[Docker] 集装箱真是个废物重的Hello, World!镜像,简直能戏剧性轻巧起来

从Docker v17开始,引入了一个名为MultiStageBuild的功能。
以前的情况是,虽然只是输出”Hello,World”的镜像,但基础镜像的大小很大,最终生成的镜像也会达到几百MB大小……而现在可以将构建使用Go的镜像,执行使用alpine镜像,以实现这样的设置(尽管在v17之前也有可能做到,但比较麻烦)。
接下来将详细解释这到底是什么意思。

这次我们要创建一个输出”Hello, World!”的容器。

package main

import "fmt"

func main() {
        fmt.Println("Hello, World!")
}

如果不使用MultiStageBuild

Dockerfile 如下所示。

FROM golang:1.13.7-alpine3.11

COPY ./main.go ./

RUN go build -o ./hello ./main.go

ENTRYPOINT ["./hello"]

让我们在同一个目录中尝试输入以下命令。

$ docker build -t hello:0.1 .

如果能构建成功,我会尝试运行。

$ docker run hello:0.1
Hello World!

我成功地建立了main.go并运行了它。现在我们来看看此时的图像大小。

$ docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
hello               0.1                 ea6e8238c063        49 seconds ago      361MB
golang              1.13.7-alpine3.11   87eefb76f0a8        9 days ago          359MB

这个原因是因为golang的容器镜像作为基础,导致容器的大小变得很大。
尽管这只是一个输出”Hello, World!”的容器,但是它太重了。。。

如果使用MultiStageBuild

在下面是Dockerfile的内容。

#Stage 1
FROM golang:1.13.7-alpine3.11 as builder
COPY ./main.go ./
RUN go build -o /hello ./main.go

#Stage 2
FROM alpine:3.11
COPY --from=builder /hello .
ENTRYPOINT ["./hello"]

在Stage1阶段,我们使用golang的Image,对main.go进行构建。然后将构建好的可执行文件传输到Stage2阶段进行执行。

$ docker run hello:0.1
Hello World!

这也成功执行了。同样,我们来看一下图片的尺寸。

$ docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
hello               0.1                 15f814bf3a87        12 seconds ago      7.6MB
<none>              <none>              6f908ead16f8        13 seconds ago      361MB
golang              1.13.7-alpine3.11   87eefb76f0a8        9 days ago          359MB
alpine              3.11                e7d92cdc71fe        2 weeks ago         5.59MB

在这里,是Stage1的映像,则成为Stage2的映像。输出”Hello, World”的映像是,因此该映像的大小为7.6MB!我们成功实现了将映像大小减小了约350MB,与不使用MultiStageBuild相比!!

总结

所以,這次我們試著談談Docker的MultiStageBuild功能。我們提到,通過將體積較大的Build環境分開,可以減少映像的大小,除此之外,通過使用Stage進行區分,還能提高Dockerfile的維護性,增強安全性等,有很多好處!如果您還沒有嘗試過,請不妨一試!

bannerAds