← 返回文章列表
Docker 生产实践:构建更小、更安全的镜像
分享在生产环境中优化 Docker 镜像的实战经验,包括多阶段构建、镜像瘦身、安全加固等关键技巧。
2025年2月20日·4 分钟阅读
字号
在生产环境中,Docker 镜像的质量直接影响到部署速度、安全性和运行成本。本文分享一些实战中积累的最佳实践。
多阶段构建(Multi-stage Build)
这是优化镜像大小最有效的手段:
# 构建阶段
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
RUN npm run build
# 运行阶段:只复制需要的文件
FROM node:20-alpine AS runner
WORKDIR /app
# 创建非 root 用户
RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs
# 只复制构建产物
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
COPY --from=builder --chown=nextjs:nodejs /app/public ./public
USER nextjs
EXPOSE 3000
CMD ["node", "server.js"]对比效果:
- 未优化前:
node:20基础镜像 ≈ 1.1GB - 优化后:
node:20-alpine+ 多阶段 ≈ 120MB
善用 .dockerignore
.dockerignore 就像 .gitignore,排除不需要的文件:
node_modules
.next
.git
.env.local
*.log
README.md
Dockerfile*
docker-compose*
.dockerignore
coverage
.nyc_output优化层缓存顺序
Docker 按层缓存,变化频率低的层放前面:
# ✅ 正确:依赖安装放在复制源码之前
COPY package*.json ./
RUN npm ci
COPY . . # 源码变化不影响依赖层缓存
RUN npm run build
# ❌ 错误:每次源码变化都会重新安装依赖
COPY . .
RUN npm ci
RUN npm run build使用非 root 用户运行
默认以 root 运行是安全隐患:
# Python 示例
FROM python:3.12-slim
RUN groupadd -r appuser && useradd -r -g appuser appuser
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY --chown=appuser:appuser . .
USER appuser # 切换到非特权用户
CMD ["python", "app.py"]精简基础镜像选择
| 场景 | 推荐镜像 | 说明 |
|---|---|---|
| 通用 Node.js | node:20-alpine | Alpine 基础,约 40MB |
| 生产 Python | python:3.12-slim | Debian slim,约 130MB |
| 微服务 Go | scratch + 静态二进制 | 最小化,仅几MB |
| 需要调试 | node:20-bookworm | 完整工具链 |
健康检查
生产镜像应加入健康检查:
HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
CMD wget --no-verbose --tries=1 --spider http://localhost:3000/api/health \
|| exit 1环境变量安全处理
# ❌ 不要在镜像中硬编码密钥
ENV DATABASE_URL="postgres://user:password@host/db"
# ✅ 运行时通过环境变量或 secrets 注入
# docker run --env-file .env.production myapp
# 或 Docker Swarm/K8s secrets一键扫描镜像漏洞
# 使用 Docker Scout 扫描
docker scout cves myapp:latest
# 使用 Trivy(开源方案)
trivy image myapp:latest完整的生产 Dockerfile 示例(Next.js)
FROM node:20-alpine AS deps
WORKDIR /app
COPY package*.json ./
RUN npm ci
FROM node:20-alpine AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
ENV NEXT_TELEMETRY_DISABLED=1
RUN npm run build
FROM node:20-alpine AS runner
WORKDIR /app
ENV NODE_ENV=production
ENV NEXT_TELEMETRY_DISABLED=1
RUN addgroup --system --gid 1001 nodejs && \
adduser --system --uid 1001 nextjs
COPY --from=builder /app/public ./public
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
USER nextjs
EXPOSE 3000
ENV PORT=3000
ENV HOSTNAME="0.0.0.0"
HEALTHCHECK --interval=30s --timeout=5s \
CMD wget -qO- http://localhost:3000/api/health || exit 1
CMD ["node", "server.js"]遵循这些实践,你的镜像将更小、更快、更安全。
分享