93ba41ed79
- 新增 backend/app/api/approval.py 审批API - 前端H5支持发起审批、审批操作 - 添加审批卡片弹窗组件 - 路由注册审批模块
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 满载跑批产出