第三部分-Dockerfile与镜像构建——15. 多阶段构建
15. 多阶段构建1. 多阶段构建概述多阶段构建是 Docker 17.05 引入的特性允许在单个 Dockerfile 中使用多个 FROM 语句每个阶段可以独立构建最终只选择需要的文件复制到最终镜像中从而大幅减小镜像体积。┌─────────────────────────────────────────────────────────────┐ │ 多阶段构建流程 │ ├─────────────────────────────────────────────────────────────┤ │ │ │ 阶段1: 构建阶段builder │ │ ┌─────────────────────────────────────────────────────┐ │ │ │ FROM golang:1.17 AS builder │ │ │ │ COPY . . │ │ │ │ RUN go build -o myapp │ │ │ │ 体积: 800MB │ │ │ └─────────────────────────────────────────────────────┘ │ │ │ │ │ ▼ │ │ 阶段2: 运行阶段runtime │ │ ┌─────────────────────────────────────────────────────┐ │ │ │ FROM alpine:latest │ │ │ │ COPY --frombuilder /app/myapp /myapp │ │ │ │ 体积: 10MB │ │ │ └─────────────────────────────────────────────────────┘ │ │ │ │ 最终镜像: 10MB (而非 800MB) │ │ │ └─────────────────────────────────────────────────────────────┘2. 基础用法2.1 简单多阶段构建# 多阶段构建示例 # 阶段1编译阶段 FROM golang:1.17-alpine AS builder WORKDIR /app COPY go.mod go.sum ./ RUN go mod download COPY . . RUN CGO_ENABLED0 GOOSlinux go build -a -installsuffix cgo -o main . # 阶段2运行阶段 FROM alpine:latest RUN apk --no-cache add ca-certificates COPY --frombuilder /app/main /app/main ENTRYPOINT [/app/main]2.2 命名阶段# 阶段命名 FROM node:14-alpine AS dependencies WORKDIR /app COPY package*.json ./ RUN npm ci --onlyproduction FROM node:14-alpine AS build WORKDIR /app COPY --fromdependencies /app/node_modules ./node_modules COPY . . RUN npm run build FROM nginx:alpine AS runtime COPY --frombuild /app/dist /usr/share/nginx/html3. 复制文件3.1 从指定阶段复制# 从命名阶段复制 FROM alpine AS stage1 RUN echo hello /file1.txt FROM alpine AS stage2 RUN echo world /file2.txt FROM alpine # 从不同阶段复制文件 COPY --fromstage1 /file1.txt / COPY --fromstage2 /file2.txt /3.2 从外部镜像复制# 从外部镜像复制文件 FROM alpine:latest # 从官方 nginx 镜像复制配置文件 COPY --fromnginx:latest /etc/nginx/nginx.conf /etc/nginx/nginx.conf # 从本地镜像复制 COPY --frommyapp:builder /app/dist /app/dist3.3 使用构建上下文# 使用构建上下文作为源 FROM alpine # 从构建上下文复制文件 COPY . /src4. 实战示例4.1 Go 应用多阶段构建# Go 应用 FROM golang:1.17-alpine AS builder # 安装 git如果需要 RUN apk add --no-cache git WORKDIR /app # 复制 go mod 文件 COPY go.mod go.sum ./ RUN go mod download # 复制源代码 COPY . . # 编译 RUN CGO_ENABLED0 GOOSlinux GOARCHamd64 go build \ -ldflags-s -w \ -o /app/myapp \ ./cmd/myapp # 运行阶段 FROM scratch # 复制编译好的二进制文件 COPY --frombuilder /app/myapp /myapp # 复制时区信息 COPY --frombuilder /usr/share/zoneinfo /usr/share/zoneinfo # 复制 SSL 证书 COPY --frombuilder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ EXPOSE 8080 ENTRYPOINT [/myapp]4.2 Node.js 多阶段构建# Node.js 应用 # 阶段1依赖安装 FROM node:14-alpine AS deps WORKDIR /app COPY package*.json ./ RUN npm ci --onlyproduction # 阶段2构建 FROM node:14-alpine AS builder WORKDIR /app COPY --fromdeps /app/node_modules ./node_modules COPY . . RUN npm run build # 阶段3生产运行 FROM node:14-alpine RUN addgroup -g 1001 -S nodejs \ adduser -S nodejs -u 1001 WORKDIR /app COPY --frombuilder --chownnodejs:nodejs /app/dist ./dist COPY --frombuilder --chownnodejs:nodejs /app/node_modules ./node_modules COPY --frombuilder --chownnodejs:nodejs /app/package.json ./ USER nodejs EXPOSE 3000 CMD [node, dist/server.js]4.3 Python 多阶段构建# Python 应用 # 阶段1依赖安装 FROM python:3.9-slim AS builder WORKDIR /app COPY requirements.txt ./ RUN pip install --no-cache-dir --user -r requirements.txt # 阶段2运行 FROM python:3.9-slim RUN useradd -m -u 1000 appuser WORKDIR /app # 从构建阶段复制依赖 COPY --frombuilder --chownappuser:appuser /root/.local /home/appuser/.local # 复制应用代码 COPY --chownappuser:appuser . . USER appuser ENV PATH/home/appuser/.local/bin:$PATH EXPOSE 8000 CMD [python, app.py]4.4 Java 多阶段构建# Java 应用 # 阶段1编译 FROM maven:3.8-openjdk-11-slim AS builder WORKDIR /app COPY pom.xml . RUN mvn dependency:go-offline COPY src ./src RUN mvn package -DskipTests # 阶段2运行 FROM openjdk:11-jre-slim RUN addgroup --system --gid 1000 appgroup \ adduser --system --uid 1000 --gid 1000 appuser WORKDIR /app COPY --frombuilder --chownappuser:appgroup /app/target/*.jar app.jar USER appuser EXPOSE 8080 ENTRYPOINT [java, -jar, app.jar]4.5 React 多阶段构建# React 应用 # 阶段1构建 FROM node:14-alpine AS builder WORKDIR /app COPY package*.json ./ RUN npm ci COPY . . RUN npm run build # 阶段2Nginx 服务 FROM nginx:alpine # 复制构建产物 COPY --frombuilder /app/build /usr/share/nginx/html # 复制自定义 Nginx 配置 COPY nginx.conf /etc/nginx/conf.d/default.conf EXPOSE 80 CMD [nginx, -g, daemon off;]5. 高级技巧5.1 停止特定阶段# 只构建到指定阶段dockerbuild--targetbuilder-tmyapp:builder.# 只构建运行阶段dockerbuild--targetruntime-tmyapp:latest.# 多目标构建dockerbuild--targetbuilder-tmyapp:dev.dockerbuild--targetruntime-tmyapp:prod.5.2 并行阶段构建# 启用 BuildKit 自动并行构建exportDOCKER_BUILDKIT1dockerbuild-tmyapp.# 构建图并行处理# 不互相依赖的阶段可以并行执行5.3 使用外部阶段# 引用外部镜像作为阶段 FROM alpine:latest AS base RUN apk add --no-cache curl FROM node:14-alpine # 从外部阶段复制 COPY --frombase /usr/bin/curl /usr/bin/curl6. 体积对比# 单阶段构建 vs 多阶段构建 # 单阶段构建体积~800MB FROM golang:1.17-alpine WORKDIR /app COPY . . RUN go build -o myapp CMD [./myapp] # 多阶段构建体积~10MB FROM golang:1.17-alpine AS builder WORKDIR /app COPY . . RUN go build -o myapp FROM alpine:latest COPY --frombuilder /app/myapp /myapp CMD [/myapp]7. 常见应用场景语言/框架构建阶段运行阶段体积减少Gogolang:alpinealpine/scratch90%Node.jsnode:alpinenode:alpine-slim60%Pythonpython:slimpython:slim50%Javamaven:jdkopenjdk:jre70%Reactnode:alpinenginx:alpine80%8. 最佳实践✅ 推荐做法# 1. 为阶段命名 FROM golang:1.17 AS builder # 2. 使用别名引用 FROM alpine AS runtime COPY --frombuilder /app/bin /app/bin # 3. 清理不需要的文件 RUN go mod download go build -o myapp rm -rf /root/.cache # 4. 使用 .dockerignore # 排除不需要的文件 # 5. 利用构建缓存 # 先复制依赖文件再复制源代码❌ 避免做法# ❌ 在最终阶段包含构建工具 FROM alpine RUN apk add --no-cache gcc make # 不需要 # ❌ 复制整个目录而不是特定文件 COPY --frombuilder /app /app # 包含源码 # ✅ 只复制必要文件 COPY --frombuilder /app/bin/myapp /app/myapp9. 调试技巧# 1. 构建到指定阶段并进入调试dockerbuild--targetbuilder-tmyapp:builder.dockerrun-itmyapp:buildersh# 2. 查看各阶段大小dockerbuild--progressplain.# 3. 使用 dive 分析dive myapp:latest# 4. 保存中间阶段dockerbuild--targetbuilder-tmyapp:cache.10. 常见问题Q1: 多阶段构建可以有多少个阶段理论上无限制但建议不超过 10 个阶段。Q2: 如何重用其他项目的阶段# 从其他项目镜像复制 COPY --fromotherproject:latest /app/bin /app/binQ3: 多阶段构建如何利用缓存# 阶段依赖层级 FROM base AS stage1 # 缓存命中 RUN command1 # 变化导致后续全部失效 FROM stage1 AS stage2 RUN command211. 小结多阶段构建大幅减小镜像体积使用AS为阶段命名使用COPY --fromstage跨阶段复制可以引用外部镜像作为阶段支持--target构建特定阶段不同阶段可并行构建BuildKit适合编译型语言Go、Java、Rust和前端项目运行时阶段应最小化内容
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2599486.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!