多阶段构建
优化镜像体积,实现构建与运行环境分离
为什么需要多阶段构建
单阶段构建的问题:
dockerfile
FROM node:18
WORKDIR /app
COPY . .
RUN npm ci && npm run build
# 构建产物 + 源代码 + node_modules 都留在镜像中
CMD ["npm", "start"]
# 最终镜像可能 1GB+多阶段构建:
dockerfile
# 阶段1:构建
FROM node:18-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
# 阶段2:运行(只复制构建产物)
FROM node:18-alpine
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules # 如果需要
CMD ["node", "dist/server.js"]
# 最终镜像可能 100MB-多阶段构建模式
模式1:分离构建与运行环境
dockerfile
# 构建阶段
FROM node:18-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
# 运行阶段
FROM node:18-alpine
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/package*.json ./
RUN npm ci --only=production
CMD ["node", "dist/server.js"]模式2:Webpack/Vite 构建产物分离
dockerfile
# 构建阶段
FROM node:18-alpine AS builder
WORKDIR /app
COPY . .
RUN npm ci
RUN npm run build
# 运行阶段(极简)
FROM node:18-alpine AS runner
WORKDIR /app
# 复制构建产物
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/public ./public
# 复制生产依赖
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/package.json ./
CMD ["node", "dist/server.js"]模式3:Go/Java 多阶段构建
dockerfile
# 构建阶段
FROM golang:1.21-alpine AS builder
WORKDIR /app
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o main .
# 运行阶段
FROM alpine:latest
RUN apk --no-cache add ca-certificates
WORKDIR /app
COPY --from=builder /app/main .
CMD ["./main"]模式4:前端 SPA 应用
dockerfile
# 构建阶段
FROM node:18-alpine AS builder
WORKDIR /app
COPY . .
RUN npm ci && npm run build
# Nginx 服务阶段
FROM nginx:alpine
COPY --from=builder /app/dist /usr/share/nginx/html
COPY nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]构建参数传递
dockerfile
# 构建时传递参数
ARG NODE_VERSION=18-alpine
FROM node:${NODE_VERSION}
ARG BUILD_VERSION
RUN echo "Build version: ${BUILD_VERSION}"
# 构建命令
docker build --build-arg BUILD_VERSION=1.0.0 -t myapp .优化技巧
技巧1:合并 RUN 指令
dockerfile
# ❌ 错误:多层,缓存利用率低
RUN apt-get update
RUN apt-get install -y curl
RUN apt-get install -y vim
RUN rm -rf /var/lib/apt/lists/*
# ✅ 正确:合并减少层数
RUN apt-get update && \
apt-get install -y curl vim && \
rm -rf /var/lib/apt/lists/*技巧2:.dockerignore 优化
txt
# .dockerignore
node_modules
npm-debug.log
.git
.gitignore
.env
.env.*
*.log
.DS_Store
coverage
.nyc_output
dist技巧3:选择合适的基础镜像
| 镜像 | 大小 | 适用场景 |
|---|---|---|
ubuntu | ~80MB | 需要完整系统 |
debian | ~75MB | 稳定兼容 |
alpine | ~5MB | 最小化(推荐) |
node:18-alpine | ~180MB | Node.js 应用 |
技巧4:按需复制
dockerfile
# ❌ 复制全部
COPY . .
# ✅ 只复制必要文件
COPY package*.json ./
COPY src/ ./src/
COPY public/ ./public/面试高频题
Q1: 什么是多阶段构建?有什么好处?
答案: 多阶段构建允许在一个 Dockerfile 中使用多个 FROM 指令,每个阶段可以复制前一个阶段的文件。
好处:
- 减小最终镜像体积(只包含运行所需文件)
- 构建与运行环境分离
- 提高安全性(源代码不进入生产镜像)
Q2: 如何优化 Dockerfile 减小镜像大小?
答案:
- 使用多阶段构建
- 选择轻量基础镜像(alpine)
- 合并 RUN 指令
- 合理使用 .dockerignore
- 按需 COPY 文件
- 清理不必要的缓存和文件