Dockerfile-多阶段构建
多阶段构建Dockerfile对于那些积极想优化Dockerfile的人非常有用,不仅如此,多阶段构建还易于维护和可读。
多阶段构建场景
构建镜像的其中最大一项挑战就是如何缩小我们的镜像体积。官网有一句这样的话,我是这么理解的,dockerfile中每一个指令都相当于向镜像中添加了一层,类似画画的图层一样,你需要记住你自己的构建并且及时的清理你这些基础内容当你决定继续执行下一个步骤,或者说再添加一个图层。换句话说我们应该在每一层内,除了准备和执行命令,还要做好清理的工作,再进入下个步骤。要写好真正高效的dockerfile,传统做法就是竭尽所能的利用你所知道的shell技巧,来保持每一层尽可能的小巧,并且能够依赖前一层的设施最好。
在实际生产环境中,常见的情况是,我们维护了一个开发镜像(包含构建app所需要的所有内容),以及一个用于生产的精简文件,只包含应用和运行它的所有以来和辅助程序。也就是所说的“builder pattern”。但是维护两个Dockerfile不太理想。
来看官网给的“builder pattern”的实例,令我非常开心的是,官网举了个构建Go的例子。
Dockerfile.build
# syntax=docker/dockerfile:1 FROM golang:1.16 WORKDIR /go/src/github.com/alexellis/href-counter/ COPY app.go ./ RUN go get -d -v golang.org/x/net/html \ && CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o app .
看到这部分内容的时候我当时头皮发麻,官网说,该例子在运行RUN命令的时候,使用了Bash的 && 运算符人为的将两个命令压缩在了一起,避免在镜像中创建上面提到的,会因为运行指令而多出来的层。这是很容易失败且难以维护的,例如,很容易在插入另一个命令的时候忘记使用 \ ,这就回倒是镜像构建失败。但是如果只有这一个缺点的话,注意下是不是也没事了?在不影响镜像大小和构建效率的情况下。
Dockerfile
# syntax=docker/dockerfile:1 FROM alpine:latest RUN apk --no-cache add ca-certificates WORKDIR /root/ COPY app ./ CMD ["./app"]
build.sh
#!/bin/sh echo Building alexellis2/href-counter:build docker build --build-arg https_proxy=$https_proxy --build-arg http_proxy=$http_proxy \ -t alexellis2/href-counter:build . -f Dockerfile.build docker container create --name extract alexellis2/href-counter:build docker container cp extract:/go/src/github.com/alexellis/href-counter/app ./app docker container rm -f extract echo Building alexellis2/href-counter:latest docker build --no-cache -t alexellis2/href-counter:latest . rm ./app
当我们要跑build.sh脚本时,他需要构建第一个镜像,从中创建一个容器用来复制各种组件,然后再构建第二个镜像。这两个镜像都占用了系统空间,并且本地的磁盘上仍然有构建该应用的组件残留。
如果使用多阶段构建的话,就会大大简化这种情况!!!!