news 2026/5/10 3:45:26

第三部分-Dockerfile与镜像构建——15. 多阶段构建

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
第三部分-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 --from=builder /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_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o main . # 阶段2:运行阶段 FROM alpine:latest RUN apk --no-cache add ca-certificates COPY --from=builder /app/main /app/main ENTRYPOINT ["/app/main"]

2.2 命名阶段

# 阶段命名 FROM node:14-alpine AS dependencies WORKDIR /app COPY package*.json ./ RUN npm ci --only=production FROM node:14-alpine AS build WORKDIR /app COPY --from=dependencies /app/node_modules ./node_modules COPY . . RUN npm run build FROM nginx:alpine AS runtime COPY --from=build /app/dist /usr/share/nginx/html

3. 复制文件

3.1 从指定阶段复制

# 从命名阶段复制 FROM alpine AS stage1 RUN echo "hello" > /file1.txt FROM alpine AS stage2 RUN echo "world" > /file2.txt FROM alpine # 从不同阶段复制文件 COPY --from=stage1 /file1.txt / COPY --from=stage2 /file2.txt /

3.2 从外部镜像复制

# 从外部镜像复制文件 FROM alpine:latest # 从官方 nginx 镜像复制配置文件 COPY --from=nginx:latest /etc/nginx/nginx.conf /etc/nginx/nginx.conf # 从本地镜像复制 COPY --from=myapp:builder /app/dist /app/dist

3.3 使用构建上下文

# 使用构建上下文作为源 FROM alpine # 从构建上下文复制文件 COPY . /src

4. 实战示例

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_ENABLED=0 GOOS=linux GOARCH=amd64 go build \ -ldflags="-s -w" \ -o /app/myapp \ ./cmd/myapp # 运行阶段 FROM scratch # 复制编译好的二进制文件 COPY --from=builder /app/myapp /myapp # 复制时区信息 COPY --from=builder /usr/share/zoneinfo /usr/share/zoneinfo # 复制 SSL 证书 COPY --from=builder /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 --only=production # 阶段2:构建 FROM node:14-alpine AS builder WORKDIR /app COPY --from=deps /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 --from=builder --chown=nodejs:nodejs /app/dist ./dist COPY --from=builder --chown=nodejs:nodejs /app/node_modules ./node_modules COPY --from=builder --chown=nodejs: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 --from=builder --chown=appuser:appuser /root/.local /home/appuser/.local # 复制应用代码 COPY --chown=appuser: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 --from=builder --chown=appuser: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 # 阶段2:Nginx 服务 FROM nginx:alpine # 复制构建产物 COPY --from=builder /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_BUILDKIT=1dockerbuild-tmyapp.# 构建图并行处理# 不互相依赖的阶段可以并行执行

5.3 使用外部阶段

# 引用外部镜像作为阶段 FROM alpine:latest AS base RUN apk add --no-cache curl FROM node:14-alpine # 从外部阶段复制 COPY --from=base /usr/bin/curl /usr/bin/curl

6. 体积对比

# 单阶段构建 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 --from=builder /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 --from=builder /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 --from=builder /app /app # 包含源码 # ✅ 只复制必要文件 COPY --from=builder /app/bin/myapp /app/myapp

9. 调试技巧

# 1. 构建到指定阶段并进入调试dockerbuild--targetbuilder-tmyapp:builder.dockerrun-itmyapp:buildersh# 2. 查看各阶段大小dockerbuild--progress=plain.# 3. 使用 dive 分析dive myapp:latest# 4. 保存中间阶段dockerbuild--targetbuilder-tmyapp:cache.

10. 常见问题

Q1: 多阶段构建可以有多少个阶段?

理论上无限制,但建议不超过 10 个阶段。

Q2: 如何重用其他项目的阶段?

# 从其他项目镜像复制 COPY --from=otherproject:latest /app/bin /app/bin

Q3: 多阶段构建如何利用缓存?

# 阶段依赖层级 FROM base AS stage1 # 缓存命中 RUN command1 # 变化导致后续全部失效 FROM stage1 AS stage2 RUN command2

11. 小结

  • 多阶段构建大幅减小镜像体积
  • 使用AS为阶段命名
  • 使用COPY --from=<stage>跨阶段复制
  • 可以引用外部镜像作为阶段
  • 支持--target构建特定阶段
  • 不同阶段可并行构建(BuildKit)
  • 适合编译型语言(Go、Java、Rust)和前端项目
  • 运行时阶段应最小化内容

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/10 3:39:55

基于MCP协议的AI调试实践:让Claude成为你的代码调试搭档

1. 项目概述&#xff1a;当Claude成为你的调试搭档 如果你是一名开发者&#xff0c;那么“调试”这两个字&#xff0c;大概率是你日常工作中最耗时、也最令人头疼的部分之一。面对一个诡异的bug&#xff0c;你需要在IDE、终端、浏览器控制台之间反复横跳&#xff0c;设置断点&a…

作者头像 李华
网站建设 2026/5/10 3:38:47

做企业软件的定制软件开发公司解决方案商

当你决定为你的企业定制一款软件时&#xff0c;你期待的蓝图是什么&#xff1f;或许是降本增效的利器&#xff0c;或许是开拓新市场的战车。然而&#xff0c;现实往往骨感。大量企业主满怀希望地投入资金后&#xff0c;等来的却是一堆“烂尾”代码、无休止的返工和交付即失联的…

作者头像 李华
网站建设 2026/5/10 3:36:34

基于Alexa技能与无服务器架构的香港地铁实时查询系统开发实战

1. 项目概述与核心价值最近在折腾智能音箱的技能开发&#xff0c;发现一个挺有意思的开源项目&#xff1a;tomfong/hk-mtr-next-train-skill。这是一个为香港地铁&#xff08;MTR&#xff09;乘客量身定做的语音技能&#xff0c;让你动动嘴皮子&#xff0c;就能问出下一班车什么…

作者头像 李华
网站建设 2026/5/10 3:35:25

开源企业级AI搜索平台Ocular:基于RAG构建内部知识助手

1. 项目概述&#xff1a;当ChatGPT遇上企业级搜索如果你在团队里负责过知识管理或者内部工具&#xff0c;大概率遇到过这样的场景&#xff1a;新来的同事问你“咱们去年那个项目复盘文档放哪儿了&#xff1f;”&#xff0c;或者产品经理想找“三年前用户调研中关于支付流程的所…

作者头像 李华
网站建设 2026/5/10 3:32:41

Flutter+开源鸿蒙实战|城市共享驿站智能存取系统 Day4 订单生成逻辑+多状态管理+我的订单页面+会员中心UI+全局交互细节优化

Flutter开源鸿蒙实战&#xff5c;城市共享驿站智能存取系统 Day4 订单生成逻辑多状态管理我的订单页面会员中心UI全局交互细节优化 欢迎加入开源鸿蒙跨平台社区&#xff1a;https://openharmonycrossplatform.csdn.net <!-- Schema.org 结构化数据 --> <script type&q…

作者头像 李华
网站建设 2026/5/10 3:32:40

拓扑量子计算与Sine-Cosine链模型解析

1. 拓扑量子计算与Sine-Cosine链模型概述量子计算面临的核心挑战之一是量子态的脆弱性——环境噪声和退相干效应极易破坏量子信息。传统解决方案如量子纠错码需要大量物理量子比特来编码单个逻辑量子比特&#xff0c;导致资源开销呈指数级增长。而拓扑量子计算提供了一种根本不…

作者头像 李华