Docker 多阶段构建:把 Go 后端镜像从 900MB 瘦到 20MB

举报
yd_278073926 发表于 2026/11/09 06:05:49 2026/11/09
【摘要】 Docker 多阶段构建:把 Go 后端镜像从 900MB 瘦到 20MB 先说结论Go 程序编译出来就是一个静态二进制,理论上镜像可以很小,但很多人写的 Dockerfile 一上来就 FROM golang,把编译器、源码、依赖缓存全打进最终镜像,900MB 起步。换成多阶段构建:第一阶段用 Go 官方镜像编译,第二阶段只把编译好的二进制拷进一个最小基础镜像,镜像直接瘦到 20MB 左...

Docker 多阶段构建:把 Go 后端镜像从 900MB 瘦到 20MB

先说结论

Go 程序编译出来就是一个静态二进制,理论上镜像可以很小,但很多人写的 Dockerfile 一上来就 FROM golang,把编译器、源码、依赖缓存全打进最终镜像,900MB 起步。换成多阶段构建:第一阶段用 Go 官方镜像编译,第二阶段只把编译好的二进制拷进一个最小基础镜像,镜像直接瘦到 20MB 左右,推送快、拉取快、攻击面也小。

第一步:一个能跑的多阶段 Dockerfile

假设项目在模块根目录,有 go.mod,入口是 main.go:

# 第一阶段:构建
FROM golang:1.23-alpine AS builder
WORKDIR /src
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -o /out/server .

# 第二阶段:运行
FROM alpine:3.20
WORKDIR /app
COPY --from=builder /out/server ./server
EXPOSE 8080
ENTRYPOINT ["./server"]

关键点有三个。CGO_ENABLED=0 让 Go 生成纯静态二进制,不依赖系统 C 库,这样第二阶段用 Alpine 甚至 scratch 都能跑;go mod download 单独一层,利用 Docker 层缓存——只要 go.mod 没变,依赖就不用重新下载;COPY --from=builder 只把产物拷过去,编译器和源码都留在第一阶段,不会进最终镜像。

第二步:验证瘦身效果

docker build -t order-backend:v1 .
docker images order-backend

对比一下就知道差距:单阶段 FROM golang 的镜像通常 800MB 以上,多阶段 + Alpine 一般在 20MB 上下;如果第二阶段换成 FROM scratch,连 Alpine 的几 MB 也省了,只剩二进制本身的大小。不过 scratch 里什么都没有,连 shell 和 CA 证书都没有,服务要调外部 HTTPS 接口时会报证书错误,需要多拷一个 ca-certificates.crt,还要接受出问题时进不去容器排查的代价。对只有自己和女友用的点餐后端,Alpine 是更稳妥的选择:有 shell 能 docker exec 进去看一眼,体积也足够小。

第三步:上线部署时的两个习惯

第一,给镜像打上有意义的 tag 再推:order-backend:20261109 比 latest 好,回滚时知道到底回滚到哪个版本;latest 永远指向最后一次构建,出问题没法一眼定位。第二,构建时顺手加 --trimpath -ldflags="-s -w":

RUN CGO_ENABLED=0 GOOS=linux go build -trimpath -ldflags="-s -w" -o /out/server .

-s -w 去掉符号表和调试信息,二进制能再小 20% 到 30%,对生产部署完全够用;本地调试再用默认参数编译,需要堆栈信息时不受影响。

检查清单

  1. 最终镜像里只有二进制,没有 Go 编译器和源码:docker images 看大小,docker history 看各层。
  2. 二进制是静态编译的:CGO_ENABLED=0 写了没有。
  3. 依赖下载走了缓存层:改业务代码后重新构建,go mod download 那层是不是 Using cache。
  4. 容器里能正常调外部接口:Alpine 阶段带了 CA 证书,HTTPS 请求不报错。
  5. 镜像 tag 带日期或版本号,不用裸 latest 上生产。

多阶段构建的思路其实很通用:构建环境和运行环境分开,最终产物只带运行必需的东西。Go 天生适合这一套,镜像瘦下来之后,每次部署推送拉取都只要几秒,小服务器的磁盘和带宽也都省下来了。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。