首页/云/Docker 容器速查/Go 多阶段构建示例
镜像与构建107 条

Go 多阶段构建示例

Go 静态编译的典型流水线:构建阶段带工具链,运行阶段用 distroless/scratch;配合交叉编译参数产出目标架构二进制。

Docker 容器速查云更新于 2026-10-13

Go 多阶段构建

Go 的典型流水线:构建阶段带完整工具链,运行阶段用 distroless 或 scratch 这类极小基础镜像,只放静态编译出的二进制。配合目标平台参数做交叉编译,一份文件就能产出目标架构的产物。

基本信息

阶段划分构建阶段用 golang 镜像,运行阶段用 distroless 或 scratch
静态编译CGO_ENABLED=0 与目标平台参数一起传入
交叉编译TARGETOS 与 TARGETARCH 由构建平台自动注入
体积优化-trimpath 配合链接参数去掉路径与符号信息
依赖缓存先复制 go.mod 与 go.sum 再下载模块

典型使用场景

  • 服务镜像精简:只带二进制与证书,运行阶段不含工具链
  • 多架构发布:构建阶段按目标平台交叉编译,运行阶段对应平台基础镜像
  • 排查镜像内报找不到动态库:确认是否真的完成了静态编译
  • 依赖层缓存优化:改业务代码不触发模块重新下载
  • 排查启动缺少时区或证书:运行阶段按需补上相应文件
  • 统一构建产物路径,方便 CI 归档与后续校验

示例

示例
FROM --platform=$BUILDPLATFORM golang:1.23 AS build
ARG TARGETOS TARGETARCH
WORKDIR /src
COPY go.mod go.sum ./
RUN go mod download                 # 依赖层单独缓存
COPY . .
RUN CGO_ENABLED=0 GOOS=$TARGETOS GOARCH=$TARGETARCH \
    go build -trimpath -ldflags='-s -w' -o /out/app .

FROM gcr.io/distroless/static-debian12:nonroot
COPY --from=build /out/app /app
ENTRYPOINT ["/app"]

两个阶段的分工

内容构建阶段运行阶段
Go 工具链有无
模块缓存有无
静态二进制产出运行
证书与时区文件系统自带需要按需补齐
镜像体积数百 MB 级数十 MB 级或更小
先复制 go.mod 与 go.sum 再执行模块下载,改业务代码不会触发依赖重新下载,构建时间差别很明显。
运行在 distroless 或 scratch 上时容器里没有 shell,exec 进容器排查不可用,需要调试时临时换用带工具的基础镜像。
CGO_ENABLED=0 时域名解析走纯 Go 实现,个别依赖系统解析库的行为会变化,涉及解析的场景要在目标环境验证。
运行阶段用 nonroot 变体时启动身份已经是普通用户,注意二进制的可执行权限,以及日志、临时目录是否可写。

易错点

  • 依赖 cgo 或 glibc 的库在 distroless、scratch 里因缺动态库启动失败,需要静态编译或换基础镜像
  • 运行阶段没有带上 CA 证书,程序访问 HTTPS 时报证书校验失败,构建时把证书文件一并复制过去
  • 忘记 -trimpath,镜像里带出构建机的目录路径,体积变大且暴露内部结构
  • 多架构构建时没用目标平台参数,产物架构与运行镜像不匹配,启动直接报格式错误
  • 构建阶段与运行阶段的基础镜像架构不一致,二进制运行不起来,多架构构建时两端要一起对齐平台参数

数据来源与参考

  • Docker 官方文档:Multi-stage builds(docs.docker.com)
​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌