Docker 技巧 多阶段构建 (Multi-stage Build)

这段代码展示了 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 - 600MB0 MB
Go 语言编译器/工具约 400MB0 MB
你的代码/程序约 10MB10 MB
最终镜像大小约 1GB约 10MB

💡 这样做的好处不仅是“小”

极度安全: 镜像里没有 Shell(命令行),没有包管理器。黑客即使攻破了你的程序,进去之后发现里面什么工具都没有,连 ls 或 cd 都做不了,极大地增加了攻击难度。

传输极快: 10MB 的镜像在部署时,秒级下载完成。

节省成本: 存储镜像的仓库和服务器磁盘空间占用极低。

⚠️ 需要注意的“坑”

由于 scratch 镜像是完全真空的,你会遇到以下小问题:

无法进入容器调试: 你不能执行 docker exec -it 进去看文件,因为它里面连个命令提示符都没有。

时区和证书: 如果你的程序需要访问 HTTPS 网站或者获取北京时间,你需要额外从 builder 阶段把 /etc/ssl/certs 和 /usr/share/zoneinfo 拷贝过来。