Files
wecom_it_smart_desk/docs/审计报告/Dockerfile优化与镜像审计.md
T
Simon 93ba41ed79 feat: 审批流程模块 (T审批A审批)
- 新增 backend/app/api/approval.py 审批API
- 前端H5支持发起审批、审批操作
- 添加审批卡片弹窗组件
- 路由注册审批模块
2026-06-15 09:32:41 +08:00

9.0 KiB
Raw Blame History

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 修复

  1. 所有 Dockerfile 加 USER 指令(已写优化版)
  2. 加 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
    
  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 立即(本次跑批)

  • 审计报告写完(本文件)
  • 加根目录 .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. 关联文档


本审计是 2026-06-15 Claude 满载跑批产出