44e77dcb0e
**重构前**(旧编号 02-11): - docs/02-产品需求/ → 00 产品规划/PRD - docs/03-技术架构/ → 01-05 子目录散落 - docs/04-原型设计/ → 01-02 产品设计(HTML 原型) - docs/05-原型设计/ → screens/ - docs/06-测试素材/ → 02-E2E / 03-功能 / 04-版本测试 - docs/07-项目管理/ → 任务说明书/日报/计划 - docs/08-安全审计/ → 审计报告 - docs/09-堡垒运维/ → toolbox / deploy - docs/10-项目管理/ → 任务说明书(重复) - docs/11-历史归档/ → deploy-nas-archived **重构后**(新编号 00-07,语义化): - docs/00-产品开发流程与文档管理规范.md - docs/00-版本迭代总览.md - docs/01-产品文档/ (PRD/原型/认证/会话/AI 服务/坐席/集成) - docs/02-技术文档/ (技术方案/架构图/重构记录/前端改造/实现配置) - docs/03-测试文档/ (E2E/功能用例/版本报告/缺陷单) - docs/04-运维文档/ (部署运维/运维指南) - docs/05-运营文档/ (品牌推广/用户手册) - docs/06-安全审计/ (审计报告) - docs/07-项目管理/ (任务说明书/日报/计划/看板) **净收益**: - 目录编号与产品文档管理规范对齐(按文档阶段 01-07 编号) - 消除 02-产品需求 与 10-项目管理 的编号重叠 - 子目录按文档类型分组(如 01-产品文档/00-产品规划、01-产品文档/01-认证与登录) - 把运维/安全/项目管理从 0X 散落改为 04/06/07 合计 494 文件 + 78495 行 / - 14076 行
9.0 KiB
9.0 KiB
Dockerfile 优化 + 镜像审计报告
审计日期: 2026-06-15 审计人: Claude 关联: 风险跟踪表 / SOP-001-Gitea部署
📌 1. 现状盘点
| 镜像 | Dockerfile | 基础 | 估计大小 | 多阶段 |
|---|---|---|---|---|
| backend | backend/Dockerfile |
python:3.12-slim |
~250 MB | ✅ |
| frontend-agent | frontend-agent/Dockerfile |
nginx:1.27-alpine |
~50 MB | ✅ |
| frontend-h5 | frontend-h5/Dockerfile |
nginx:1.27-alpine |
~50 MB | ✅ |
| postgres | (用官方) | postgres:16-alpine |
~80 MB | — |
| redis | (用官方) | redis:7-alpine |
~30 MB | — |
| nginx | (用官方) | nginx:1.27-alpine |
~40 MB | — |
总估计镜像大小:~500 MB(4 业务 + 2 数据库)
📌 2. backend Dockerfile 审计
2.1 当前实现
FROM python:3.12-slim AS builder
RUN apt-get update && apt-get install -y --no-install-recommends \
gcc libpq-dev libjpeg-dev zlib1g-dev curl
COPY requirements.txt .
RUN pip install --no-cache-dir --timeout 120 --retries 5 \
-i https://pypi.tuna.tsinghua.edu.cn/simple/ \
--trusted-host pypi.tuna.tsinghua.edu.cn \
-r requirements.txt
FROM python:3.12-slim
RUN apt-get update && apt-get install -y --no-install-recommends libpq5 curl
COPY --from=builder /usr/local/lib/python3.12/site-packages /usr/local/lib/python3.12/site-packages
COPY --from=builder /usr/local/bin /usr/local/bin
COPY . .
EXPOSE 8000
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]
2.2 问题清单
| # | 问题 | 严重度 | 优化 |
|---|---|---|---|
| B-1 | ⚠️ 装 curl — 但 P1-3 已改 healthcheck 用 Python urllib | 🟡 | 删 curl(节省 1MB) |
| B-2 | ⚠️ 不用非 root 用户 | 🟠 中 | 加 USER appuser |
| B-3 | ⚠️ 没 HEALTHCHECK — 交给 docker-compose | 🟡 | Dockerfile 也加 |
| B-4 | ⚠️ COPY . . 太宽 — 含 .git / tests / docs | 🟡 | 加 .dockerignore |
| B-5 | 🟢 pip 装到 venv(更隔离) | 🟢 | 已用 site-packages |
| B-6 | ⚠️ 没用 BuildKit cache mount | 🟡 | 加 --mount=type=cache |
| B-7 | ⚠️ PyPI 用清华源 — 公司内网可,但生产建议官方 | 🟡 | 评估 |
2.3 优化版
# syntax=docker/dockerfile:1.7
FROM python:3.12-slim AS builder
# 创建非 root 用户
RUN groupadd -r appuser && useradd -r -g appuser appuser
WORKDIR /app
# 系统依赖(只装构建期需要的)
RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
--mount=type=cache,target=/var/lib/apt,sharing=locked \
apt-get update && \
apt-get install -y --no-install-recommends \
gcc libpq-dev libjpeg-dev zlib1g-dev && \
rm -rf /var/lib/apt/lists/*
# 依赖(用 cache mount + BuildKit)
COPY requirements.txt .
RUN --mount=type=cache,target=/root/.cache/pip \
pip install --no-cache-dir --user \
--timeout 120 --retries 5 \
-i https://pypi.tuna.tsinghua.edu.cn/simple/ \
--trusted-host pypi.tuna.tsinghua.edu.cn \
-r requirements.txt
# 运行镜像
FROM python:3.12-slim
# 复制非 root 用户
COPY --from=builder /etc/passwd /etc/passwd
COPY --from=builder /etc/group /etc/group
# 运行时依赖(只 libpq5,**不装 curl**)
RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
--mount=type=cache,target=/var/lib/apt,sharing=locked \
apt-get update && \
apt-get install -y --no-install-recommends libpq5 && \
rm -rf /var/lib/apt/lists/*
WORKDIR /app
# 复制构建好的 Python 包
COPY --from=builder /root/.local /home/appuser/.local
COPY --chown=appuser:appuser . .
# 切非 root 用户
USER appuser
ENV PATH=/home/appuser/.local/bin:$PATH
ENV PYTHONUNBUFFERED=1
EXPOSE 8000
# 内置 healthcheck(不依赖 curl)
HEALTHCHECK --interval=30s --timeout=10s --start-period=40s --retries=3 \
CMD python -c "import urllib.request; urllib.request.urlopen('http://localhost:8000/health').read()"
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]
预期收益:
- 镜像小 ~10 MB(删 curl)
- 安全(非 root)
- 加速 rebuild(BuildKit cache)
- 内置 healthcheck(无需依赖 compose)
📌 3. frontend Dockerfile 审计(agent + h5 同)
3.1 当前实现
FROM node:20-slim AS builder
WORKDIR /app
COPY package.json package-lock.json* ./
RUN npm install
COPY . .
RUN npm run build
FROM nginx:1.27-alpine
COPY --from=builder /app/dist /usr/share/nginx/html
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
3.2 问题清单
| # | 问题 | 严重度 | 优化 |
|---|---|---|---|
| F-1 | ⚠️ 不用非 root(nginx 默认 root) | 🟠 中 | 自定义 nginx.conf 改 user |
| F-2 | ⚠️ 没 nginx.conf — 用默认 | 🟡 | 复制 custom nginx.conf |
| F-3 | ⚠️ 没 .dockerignore | 🟡 | 加 |
| F-4 | ⚠️ 没 layer cache 优化 | 🟡 | BuildKit cache mount |
| F-5 | ⚠️ 不用 alpine node | 🟡 | 改 node:20-alpine |
3.3 优化版
# syntax=docker/dockerfile:1.7
FROM node:20-alpine AS builder
WORKDIR /app
# 装 pnpm(快 2-3 倍,磁盘省 50%)
RUN corepack enable && corepack prepare pnpm@9 --activate
# 依赖
COPY package.json pnpm-lock.yaml* ./
RUN --mount=type=cache,target=/root/.local/share/pnpm/store \
pnpm install --frozen-lockfile
# 源码 + 构建
COPY . .
RUN pnpm run build
# 运行镜像
FROM nginx:1.27-alpine
# 自定义 nginx.conf(非 root + 反代配置)
COPY nginx.conf /etc/nginx/nginx.conf
# 从 builder 复制 dist
COPY --from=builder --chown=nginx:nginx /app/dist /usr/share/nginx/html
# nginx alpine 默认是 nginx user
USER nginx
EXPOSE 80
HEALTHCHECK --interval=30s --timeout=3s --retries=3 \
CMD wget -q --spider http://localhost/ || exit 1
CMD ["nginx", "-g", "daemon off;"]
预期收益:
- 用 pnpm 代替 npm(快 2-3 倍)
- alpine node 镜像小 ~150 MB
- 自定义 nginx.conf + 非 root
- 内置 healthcheck
📌 4. .dockerignore 建议
根目录 .dockerignore:
# Git
.git/
.gitignore
.gitattributes
.git-blame-ignore-revs
# 文档
docs/
*.md
!backend/README.md
# 测试
tests/
**/test_*.py
**/*_test.py
**/*.test.ts
**/*.spec.ts
coverage/
.coverage
htmlcov/
.pytest_cache/
# 开发工具
.vscode/
.idea/
*.swp
.DS_Store
Thumbs.db
# 构建产物(各端 dist)
frontend-*/dist/
frontend-*/node_modules/
# 部署包 / 备份
deploy-*.tar
deploy-*.tar.gz
*.log
*.log.err
build_logs/
# Python
__pycache__/
*.py[cod]
*$py.class
.venv/
venv/
*.egg-info/
# 环境变量(敏感)
.env
.env.*
!.env.example
# Docker
Dockerfile
.dockerignore
docker-compose*.yml
每个前端 frontend-X/.dockerignore:
node_modules/
dist/
.env
.env.*
📌 5. 镜像大小优化(整体)
| 优化项 | 节省 | 风险 |
|---|---|---|
| backend 删 curl | 1 MB | 无 |
前端换 node:20-alpine |
~150 MB × 2 | 无 |
| 前端用 pnpm | ~50 MB × 2 | 无 |
| 加 .dockerignore | ~30% build 体积 | 无 |
跑 docker system prune |
100-500 MB | 无 |
| 总节省 | ~400 MB | — |
📌 6. 安全加固
6.1 当前问题
| # | 问题 | 严重度 |
|---|---|---|
| S-1 | 全部容器跑 root | 🟠 中 |
| S-2 | 没 secret 扫描(防 docker build 时 COPY 进 secret) | 🟡 |
| S-3 | 没镜像漏洞扫描(Trivy) | 🟡 |
6.2 修复
- 所有 Dockerfile 加
USER指令(已写优化版) - 加 Trivy 扫描到 CI:
# .gitea/workflows/security.yml - name: Run Trivy vulnerability scanner uses: aquasecurity/trivy-action@master with: image-ref: 'wecom-it-desk-backend:latest' format: 'table' exit-code: '1' ignore-unfixed: true - 加 secret 扫描:
.gitleaks.toml配 gitleaks- pre-commit hook 跑 gitleaks
📌 7. 构建性能
| 优化 | 加速 | 实现 |
|---|---|---|
| BuildKit cache mount | 3-5x | RUN --mount=type=cache,target=... |
| 多阶段 | 减少最终大小 | 已用 |
| 依赖层缓存 | 2-3x | COPY requirements.txt 先于 COPY . |
| 并行构建 | 2-3x | docker buildx build |
| 镜像 registry 缓存 | 1.5-2x | 推 Gitea Container Registry |
📌 8. 实施路径
8.1 立即(本次跑批)
- 审计报告写完(本文件)
- 加根目录
.dockerignore - 加每个前端
.dockerignore
8.2 下周
- backend Dockerfile 优化版(删 curl + 非 root + healthcheck)
- frontend Dockerfile 优化版(alpine + pnpm + 非 root)
- 跑
docker build验证大小
8.3 季度
- 加 Trivy 扫描到 CI
- 加 Gitea Container Registry
- 多架构构建(amd64 + arm64)
📌 9. 风险与缓解
| 风险 | 等级 | 缓解 |
|---|---|---|
| 优化版 Dockerfile 漏改回归 | 🟡 中 | CI 跑 docker build 测试 |
| alpine 镜像 musl libc 兼容性 | 🟡 中 | 验证 Python wheels |
| pnpm lockfile 跟 npm 差异 | 🟢 低 | 用 pnpm import 转 |
| 非 root 用户文件权限 | 🟡 中 | chown 显式指定 |
📌 10. 关联文档
- 风险跟踪表 M-11(数据库密码弱) / 部署相关
- SOP-001-Gitea部署 - Gitea 部署参考
- Gitea部署指南 - 部署文档
本审计是 2026-06-15 Claude 满载跑批产出