这段代码展示了 Docker 中非常高级且强大的技巧:多阶段构建 (Multi-stage Build)。
简单来说,这就像是**“过河拆桥”**:为了造出一台精密的机器,我们需要一个巨大的工厂和各种笨重的工具;但机器造好后,我们只需要把机器搬走,把整个工厂都扔掉。
下面我为你逐行拆解这个过程,即使不熟悉 Docker 也能看懂:
1. 第一阶段:建筑工地(编译环境)
Dockerfile
FROM golang:1.24.1 as builder # 找一个装满了 Go 语言开发工具的“大工厂”,起名叫 builder WORKDIR /opt/app # 在工厂里开辟一个工作目录 COPY . . # 把你的源代码从电脑搬进工厂 RUN CGO_ENABLED=0 go build -o example # 开始干活!把源码编译成一个“独立运行”的可执行文件
为什么大? 这个 golang 镜像里包含了操作系统、Go 编译器、各种库文件,所以它很大(通常几百 MB 甚至 1GB)。
产出物: 一个名为 example 的二进制文件。它就像一个绿色的“免安装版”软件。
2. 第二阶段:极简快递盒(运行环境)
Dockerfile
FROM scratch # 关键!这是一个特殊的“空镜像”,里面真的什么都没有 WORKDIR /opt/app # 在这个空格子里建个文件夹 COPY --from=builder /opt/app/example ./example # 只把刚才工厂里造好的那个“免安装软件”搬过来 CMD ["/opt/app/example"] # 告诉 Docker:启动时直接运行这个软件
什么是 scratch? 它是 Docker 里最基础的形象。你可以把它想象成一个真空包装袋。它没有 Ubuntu、没有 Debian、甚至连查看文件的 ls 命令都没有。
为什么要这样做? 因为你的 Go 程序在第一步已经通过 CGO_ENABLED=0 被编译成了“静态资源”。它不再需要依赖任何系统库,自己就能跑。
3. 为什么体积能从 1GB 变成 10MB?
我们可以通过下表对比两种方案的差异:
| 组成部分 | 普通方案 (把代码丢进 Golang 镜像直接跑) | 你的方案 (多阶段构建 + scratch) |
|---|---|---|
| 操作系统基础文件 | 约 200MB - 600MB | 0 MB |
| Go 语言编译器/工具 | 约 400MB | 0 MB |
| 你的代码/程序 | 约 10MB | 10 MB |
| 最终镜像大小 | 约 1GB | 约 10MB |
💡 这样做的好处不仅是“小”
极度安全: 镜像里没有 Shell(命令行),没有包管理器。黑客即使攻破了你的程序,进去之后发现里面什么工具都没有,连 ls 或 cd 都做不了,极大地增加了攻击难度。
传输极快: 10MB 的镜像在部署时,秒级下载完成。
节省成本: 存储镜像的仓库和服务器磁盘空间占用极低。
⚠️ 需要注意的“坑”
由于 scratch 镜像是完全真空的,你会遇到以下小问题:
无法进入容器调试: 你不能执行 docker exec -it 进去看文件,因为它里面连个命令提示符都没有。
时区和证书: 如果你的程序需要访问 HTTPS 网站或者获取北京时间,你需要额外从 builder 阶段把 /etc/ssl/certs 和 /usr/share/zoneinfo 拷贝过来。