← 返回文章列表

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.jsnode:20-alpineAlpine 基础,约 40MB
生产 Pythonpython:3.12-slimDebian slim,约 130MB
微服务 Goscratch + 静态二进制最小化,仅几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"]

遵循这些实践,你的镜像将更小、更快、更安全。

分享