多阶段构建优化
多阶段构建是减小镜像体积的关键技术,下面介绍使用方法。
基本概念
多阶段构建在一个 Dockerfile 中使用多个 FROM 指令,每个阶段可独立产出:
dockerfile
# 第一阶段:编译环境
FROM golang:1.21 AS builder
WORKDIR /app
COPY . .
RUN go build -o myapp .
# 第二阶段:运行环境
FROM alpine:3.18
WORKDIR /root
COPY --from=builder /app/myapp .
CMD ["./myapp"]
最终镜像仅包含第二阶段的内容,编译工具和源码被丢弃,显著减小体积。
Go 应用示例
单阶段构建(体积大)
dockerfile
FROM golang:1.21
WORKDIR /app
COPY . .
RUN go build -o myapp .
CMD ["./myapp"]
镜像大小:~800MB(包含 Go 编译环境)
多阶段构建(体积小)
dockerfile
# 编译阶段
FROM golang:1.21 AS builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -o myapp .
# 运行阶段
FROM alpine:3.18
RUN apk --no-cache add ca-certificates
WORKDIR /root/
COPY --from=builder /app/myapp .
CMD ["./myapp"]
镜像大小:~10MB(仅包含运行时需要)
Node.js 应用示例
dockerfile
# 依赖安装阶段
FROM node:18-alpine AS deps
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
# 构建阶段
FROM node:18-alpine AS builder
WORKDIR /app
COPY . .
COPY --from=deps /app/node_modules ./node_modules
RUN npm run build
# 运行阶段
FROM node:18-alpine AS runner
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY --from=builder /app/dist ./dist
CMD ["node", "dist/server.js"]
Java 应用示例
dockerfile
# 编译阶段
FROM maven:3.9-eclipse-temurin-17 AS builder
WORKDIR /app
COPY pom.xml .
RUN mvn dependency:go-offline
COPY src ./src
RUN mvn package -DskipTests
# 运行阶段
FROM eclipse-temurin:17-jre-alpine
WORKDIR /app
COPY --from=builder /app/target/*.jar app.jar
CMD ["java", "-jar", "app.jar"]
命名阶段
dockerfile
FROM golang:1.21 AS build-env
# ...
FROM alpine:3.18
COPY --from=build-env /app/myapp .
dockerfile
# 使用索引引用
FROM golang:1.21
# ...
FROM alpine:3.18
COPY --from=0 /app/myapp .
使用命名别名提高可读性,索引引用(0, 1, 2...)更简洁但不易读。
外部镜像作为阶段
dockerfile
FROM nginx:alpine AS final
COPY --from=builder /app/dist /usr/share/nginx/html
可以从外部镜像拷贝文件,不限于当前 Dockerfile 的阶段。
要点总结
- 多阶段构建使用多个 FROM 指令,每个阶段独立产出
- 最终镜像仅包含最后一个阶段的内容,体积显著减小
- 编译/构建阶段使用完整镜像,运行阶段使用精简镜像
- 使用
AS命名阶段提高可读性,COPY --from=阶段名引用 - 可从外部镜像拷贝文件,不限于当前 Dockerfile 的阶段
📝 发现内容有误?点击此处直接编辑