镜像瘦身利器,Docker的多阶段构建
小轲

为什么要使用多阶段构建?

传统的Docker Build 镜像构建过程中,所有的构建步骤都在同一个镜像层中完成,其中包含了大量的构建工具和中间文件。

比如使用go mod downloadgo build后,你的镜像可以轻轻松松的超过1G。在持续部署过程中,分发的成本和时间非常高,有的时候修复一个问题,早1秒部署都可以减少很大的损失,更别说日常了,1G的镜像分发费用也不是一笔小费用。

什么是多阶段构建?

多阶段构建是指在一个Dockerfile中使用多个FROM指令来创建不同的构建阶段。每个阶段都可以有自己的基础镜像,并且每个阶段可以相互独立地运行命令。

通过这种方式,我们可以将构建过程分为几个部分,每个部分专注于完成特定的任务,如编译代码、复制依赖文件等。

image

类似于上图的逻辑,瘦身的体验相当不错,从1.3G直接缩到28M,效果非常显著。

在上图中,做一个简单的解释

  1. 第一个阶段从基础 Go 镜像中拉取,并执行编译和下载等操作,这些资源在构建完成后实际上并不需要。我们将该阶段命名为 builder

  2. 第二个阶段引用第一阶段的 builder,从中复制构建物。在第二阶段中,只有基础的 Linux 环境和一个 Go 的二进制运行包。

使用两个阶段就可以轻松将Go的构建物实现解耦和精简,非常的方便。

怎么使用多阶段构建?

下面是一个Go的dockerfile,供参考

其实和我们正常的构建操作是差不多的,编写完成后正常执行docker build . 即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# 使用已有的 Golang 镜像作为基础镜像
FROM golang:1.23.0 AS builder
# 设定代理
ENV GOPROXY=https://goproxy.cn

# 设置工作目录
WORKDIR /app

# 复制 go.mod 和 go.sum 文件
COPY go.mod go.sum ./

# 下载依赖
RUN go mod download

# 复制整个项目
COPY . .

# 编译 Go 应用
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o main ./src/main/app.go

# 使用较小的基础镜像
FROM alpine:latest

# 安装 ca-certificates 和 tzdata
RUN apk --no-cache add ca-certificates tzdata

# 设置时区为上海
RUN cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && echo "Asia/Shanghai" > /etc/timezone

# 设置工作目录
WORKDIR /root/

# 从 builder 镜像中复制编译后的二进制文件
COPY --from=builder /app/main .

# 暴露应用运行的端口
EXPOSE 8080

# 运行应用
CMD ["./main"]

总结

无论是可以直接编译机器码的Go、还是已经推出GraalVM的Java,还有其他可以编译机器码的语言都可以使用这种多阶段构建方式进行瘦身。

其中好处有不仅可以提升部署的速度,更能减少分发的时间和带宽成本。

 评论
评论插件加载失败
正在加载评论插件