?
本文檔使用 php中文網(wǎng)手冊 發(fā)布
多階段構(gòu)建是Docker 17.05中的一項新功能,對于那些努力優(yōu)化Docker文件的人來說,他們會很激動,同時讓他們易于閱讀和維護。
致謝:特別感謝Alex Ellis授予他使用他的博客文章構(gòu)建器模式與Docker中的多階段構(gòu)建的權(quán)限,作為以下示例的基礎(chǔ)。
關(guān)于構(gòu)建圖像最具挑戰(zhàn)性的事情之一是保持圖像的大小。Dockerfile中的每條指令都會為圖像添加一個圖層,并且您需要記住在移動到下一圖層之前清理不需要的任何工件。為了編寫一個非常高效的Dockerfile,傳統(tǒng)上需要使用shell技巧和其他邏輯來盡可能地減小圖層,并確保每個圖層都具有它從上一圖層需要的構(gòu)件,而不是其他任何東西。
實際上,有一個Dockerfile用于開發(fā)(其中包含構(gòu)建應用程序所需的所有內(nèi)容)以及一個用于生產(chǎn)的瘦客戶端,它只包含您的應用程序以及運行它所需的內(nèi)容。這被稱為“建造者模式”。維護兩個Dockerfiles并不理想。
這里有一個例子Dockerfile.build
和Dockerfile
它遵守上面建造者模式:
Dockerfile.build
*
FROM golang:1.7.3WORKDIR /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 &&
運算符人為地壓縮兩個命令,以避免在圖像中創(chuàng)建額外的圖層。這很容易失敗并且很難維護。例如,插入另一個命令并忘記繼續(xù)使用該\
字符行很容易。
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
腳本時,它需要構(gòu)建第一個圖像,從中創(chuàng)建一個容器以便將該構(gòu)件復制出來,然后構(gòu)建第二個圖像。這兩個圖像都占用了系統(tǒng)空間,并且您app
的本地磁盤上仍然存在工件。
多階段構(gòu)建大大簡化了這種情況!
使用多階段構(gòu)建,您可以在Dockerfile中使用多個FROM
語句。每條FROM
指令都可以使用不同的基礎(chǔ),并且每條指令都開始構(gòu)建的新階段。您可以選擇性地將工件從一個階段復制到另一個階段,在最終圖像中留下不需要的所有內(nèi)容。為了演示這是如何工作的,讓我們修改上一節(jié)中的Dockerfile以使用多階段構(gòu)建。
Dockerfile
*
FROM golang:1.7.3WORKDIR /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。您也不需要單獨的構(gòu)建腳本。就跑吧docker build
。
$ docker build -t alexellis2/href-counter:latest .
最終的結(jié)果是與以前相同的小型生產(chǎn)映像,并顯著降低了復雜性。您不需要創(chuàng)建任何中間圖像,也不需要將任何工件提取到本地系統(tǒng)。
它是如何工作的?第二FROM
條指令以alpine:latest
圖像為基礎(chǔ)開始新的構(gòu)建階段。該COPY --from=0
行只將前一階段構(gòu)建的工件復制到這個新階段。Go SDK和任何中間工件都被留下,并未保存在最終圖像中。
默認情況下,這些階段未被命名,并且您可以用它們的整數(shù)來引用它們,從第一FROM
條指令的第一個0開始。但是,您可以通過as <NAME>
在FROM
指令中添加一個名稱來命名您的階段。此示例通過命名階段并在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"]
查看博客文章Builder模式與Docker中的多階段構(gòu)建,了解完整的源代碼以及這些示例的演練。