多階段構(gòu)建是一項(xiàng)新功能,需要守護(hù)程序和客戶端上使用docker 17.05或更高版本。多級(jí)構(gòu)建對(duì)于在優(yōu)化dockerfile的同時(shí)使其易于閱讀和維護(hù)的任何人都非常有用。
在進(jìn)行多階段構(gòu)建之前
關(guān)于構(gòu)建鏡像,最具挑戰(zhàn)性的事情之一是保持鏡像尺寸變小。dockerfile中的每條指令都會(huì)在映像上添加一層,您需要記住在移至下一層之前清除不需要的任何工件。為了編寫一個(gè)真正有效的dockerfile,傳統(tǒng)上,您需要使用shell技巧和其他邏輯來使各層盡可能小,并確保每一層都具有上一層所需的工件,而沒有其他任何東西。
實(shí)際上,通常只有一個(gè)dockerfile用于開發(fā)(包含構(gòu)建應(yīng)用程序所需的一切),而精簡的dockerfile用于生產(chǎn)時(shí),僅包含您的應(yīng)用程序以及運(yùn)行該應(yīng)用程序所需的內(nèi)容。這被稱為“構(gòu)建器模式”。維護(hù)兩個(gè)dockerfile是不理想的。
這是一個(gè)dockerfile.build和dockerfile的例子,它遵循上面的模式:
dockerfile.build:
from golang:1.7.3
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 .
請(qǐng)注意,此示例還run使用bash&&運(yùn)算符將兩個(gè)命令人工壓縮在一起,以避免在鏡像中創(chuàng)建額外的圖層。這是容易失敗的并且難以維護(hù)。
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 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
運(yùn)行build.sh腳本時(shí),它需要構(gòu)建第一個(gè)鏡像,從中創(chuàng)建一個(gè)容器以復(fù)制工件,然后構(gòu)建第二個(gè)鏡像。這兩個(gè)映像都占用了系統(tǒng)空間,并且app 本地磁盤上也仍然有工件。
多階段構(gòu)建極大地簡化了這種情況!
使用多階段構(gòu)建
通過多階段構(gòu)建,您可以from在dockerfile中使用多個(gè)語句。每個(gè)from指令可以使用不同的基礎(chǔ),并且每個(gè)指令都
開始構(gòu)建的新階段。您可以有選擇地將工件從一個(gè)階段復(fù)制到另一個(gè)階段,從而在最終圖像中留下不需要的所有內(nèi)
容。為了展示它是如何工作的,讓我們改編上一部分中的dockerfile以使用多階段構(gòu)建。
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]
您只需要單個(gè)dockerfile。您也不需要單獨(dú)的構(gòu)建腳本。只需運(yùn)行docker build:
$ docker build -t alexellis2/href-counter:latest .
最終結(jié)果是與之前的鏡像大小相同,并大大降低了復(fù)雜性。您無需創(chuàng)建任何中間映像,也不需要將任何工件提取到本地系統(tǒng)。