Docker多阶段构建

 2018年6月27日 21:05   Nick王   云计算    0 评论   244 浏览 

Docker Client: 18.03.1-ce
Docker Server: 18.03.1-ce

AA

Docker多阶段构建

官方链接: https://docs.docker.com/v17.09/engine/userguide/eng-image/multistage-build/

多阶段构建是一个新功能,需要Docker守护进程和客户端进程为17.05或者以上的版本。多阶段构建对于那些努力优化Dockerfile的人来说是非常有用的,而且这也很容易阅读和理解。

在多阶段构建之前

构建Docker镜像最具有挑战性的事情之一就是保证镜像的大小。

Dockerfile中的每条指令都会在Docker镜像中增加一个层,并且你需要记住在进入下一个层之前清除不需要的任何工作。要编写一个真正高效的Dockerfile,传统上需要使用Shell技巧和其他逻辑来保持镜像层更可能的小,同时还要确保每个镜像层都有从上层过来的所必要的工作,而不包含其他无用的内容。

通常,会有一个Dockerfile用于开发,其中包含构建应用程序所需要的所有的内容;以及一个用于生产的瘦客户端,它只包含您的应用程序以及运行它需要的内容。

来看一个例子,下面有一个Dockerfile.buildDockerfile

Dockerfile.build

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命令压缩为了一条,这样能避免多产生一个镜像层。

Dockerfile:

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 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脚本的时候,他会使用Dockerfile.build来构建第一个镜像,并且会启动一个容器,并且从容器中将应用程序拷贝出来;之后才会使用Dockerfile构建第二个镜像。

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


使用多阶段构建

当使用多阶段构建的时候,你可以在你的Dockerfile中使用多个FROM语句。每个FROM指令都可以使用不同的基础镜像,并且每个指令都会开始一个新阶段的构建。还可以选择性的将工作从一个阶段复制到另外一个阶段。

为了演示这是如何工作的,让我们修改上一个小节中的Dockerfile以使用多阶段构建。

Dockerfile

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 -t alexellis2/href-counter:latest .

最终的结果是生成了跟之前一样的一个小型的生产镜像,并且显著的降低了复杂性。你不需要创建任何的中间镜像,也不需要将任何东西拷贝都本地。

这是如何工作的?

第二条的FROM指令使用alpine:latest镜像作为基础镜像开始一个新阶段的构建。COPY --from=0这一行会将会将上一个阶段构建的镜像中的内容拷贝到这个心的阶段。GO SDK和其他任何的东西都不会保留在最终的镜像中。


命名构建阶段

默认情况下,这些阶段没有命名,我们可以使用整数来引用他们,从第一个FROM开始使用0表示,以此类推。

我们可以通过给FROM指令来添加一个<NAME>来命名阶段。

下面的示例通过命名阶段并在COPY指令中使用名称来改进前一个示例。这意味着即使稍后重新排序Dockerfile中的指令,COPY也不会中断。

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"]




如无特殊说明,文章均为本站原创,转载请注明出处
  • 转载请注明来源:Docker多阶段构建
  • 本文永久连接地址: http://ibash.cc/frontend/article/104/