首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

使用多阶段构建(引擎) | Use multi-stage builds (Engine)

多阶段构建是Docker 17.05中的一项新功能,对于那些努力优化Docker文件的人来说,他们会很激动,同时让他们易于阅读和维护。

致谢:特别感谢Alex Ellis授予他使用他的博客文章构建器模式与Docker中的多阶段构建的权限,作为以下示例的基础。

在多阶段构建之前

关于构建图像最具挑战性的事情之一是保持图像的大小。Dockerfile中的每条指令都会为图像添加一个图层,并且您需要记住在移动到下一图层之前清理不需要的任何工件。为了编写一个非常高效的Dockerfile,传统上需要使用shell技巧和其他逻辑来尽可能地减小图层,并确保每个图层都具有它从上一图层需要的构件,而不是其他任何东西。

实际上,有一个Dockerfile用于开发(其中包含构建应用程序所需的所有内容)以及一个用于生产的瘦客户端,它只包含您的应用程序以及运行它所需的内容。这被称为“建造者模式”。维护两个Dockerfiles并不理想。

这里有一个例子Dockerfile.buildDockerfile它遵守上面建造者模式:

Dockerfile.build*

代码语言:javascript
复制
FROM golang:1.7.3
WORKDIR /go/src/github.com/alexellis/href-counter/
RUN go get -d -v golang.org/x/net/html  
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*

代码语言:javascript
复制
FROM alpine:latest  
RUN apk --no-cache add ca-certificates
WORKDIR /root/
COPY app .
CMD ["./app"]  

build.sh*

代码语言:javascript
复制
#!/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 create --name extract alexellis2/href-counter:build  
docker cp extract:/go/src/github.com/alexellis/href-counter/app ./app  
docker rm -f extract

echo Building alexellis2/href-counter:latest

docker build --no-cache -t alexellis2/href-counter:latest .
rm ./app

当你运行这个build.sh脚本时,它需要构建第一个图像,从中创建一个容器以便将该构件复制出来,然后构建第二个图像。这两个图像都占用了系统空间,并且您app的本地磁盘上仍然存在工件。

多阶段构建大大简化了这种情况!

使用多阶段构建

使用多阶段构建,您可以在Dockerfile中使用多个FROM语句。每条FROM指令都可以使用不同的基础,并且每条指令都开始构建的新阶段。您可以选择性地将工件从一个阶段复制到另一个阶段,在最终图像中留下不需要的所有内容。为了演示这是如何工作的,让我们修改上一节中的Dockerfile以使用多阶段构建。

Dockerfile*

代码语言:javascript
复制
FROM golang:1.7.3
WORKDIR /go/src/github.com/alexellis/href-counter/
RUN go get -d -v golang.org/x/net/html  
COPY app.go .
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o app .

FROM alpine:latest  
RUN apk --no-cache add ca-certificates
WORKDIR /root/
COPY --from=0 /go/src/github.com/alexellis/href-counter/app .
CMD ["./app"]  

你只需要单个Dockerfile。您也不需要单独的构建脚本。就跑吧docker build

代码语言:javascript
复制
$ docker build -t alexellis2/href-counter:latest .

最终的结果是与以前相同的小型生产映像,并显着降低了复杂性。您不需要创建任何中间图像,也不需要将任何工件提取到本地系统。

它是如何工作的?第二FROM条指令以alpine:latest图像为基础开始新的构建阶段。该COPY --from=0行只将前一阶段构建的工件复制到这个新阶段。Go SDK和任何中间工件都被留下,并未保存在最终图像中。

为您的构建阶段命名

默认情况下,这些阶段未被命名,并且您可以用它们的整数来引用它们,从第一FROM条指令的第一个0开始。但是,您可以通过as <NAME>FROM指令中添加一个名称来命名您的阶段。此示例通过命名阶段并在COPY指令中使用名称来改进前一个示例。这意味着即使Dockerfile中的指令稍后重新排序,COPY也不会中断。

代码语言:javascript
复制
FROM golang:1.7.3 as builder
WORKDIR /go/src/github.com/alexellis/href-counter/
RUN go get -d -v golang.org/x/net/html  
COPY app.go    .
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o app .

FROM alpine:latest  
RUN apk --no-cache add ca-certificates
WORKDIR /root/
COPY --from=builder /go/src/github.com/alexellis/href-counter/app .
CMD ["./app"]  

下一步

扫码关注腾讯云开发者

领取腾讯云代金券