# 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 当前实现 ```dockerfile 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 优化版 ```dockerfile # 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 当前实现 ```dockerfile 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 优化版 ```dockerfile # 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 修复 1. **所有 Dockerfile 加 `USER` 指令**(已写优化版) 2. **加 Trivy 扫描到 CI**: ```yaml # .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 ``` 3. **加 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 立即(本次跑批) - [x] 审计报告写完(本文件) - [ ] 加根目录 `.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 满载跑批产出*