07 Docker 鏡像多階段構(gòu)建

背景

在 Docker 的早期版本中,對于編譯型語言(如C、Java、Go)的鏡像構(gòu)建,我們只能將應(yīng)用的編譯和運行環(huán)境,全部放到一個 Dockerfile 中,導(dǎo)致了我們構(gòu)建出來的鏡像體積過大,從而增加了鏡像的存儲和分發(fā)成本。

以下是一個以 Go 語言開發(fā)的 HTTP 服務(wù)為例:使用 Docker.build 文件來編譯應(yīng)用程序,使用 Dockerfile 文件來構(gòu)建應(yīng)用的運行環(huán)境,然后通過額外引入的 build.sh 腳本文件實現(xiàn)鏡像編譯和運行環(huán)境的分離,但這使得整個構(gòu)建過程復(fù)雜且不夠透明。

### Docker.build:依賴 Go 語言編譯環(huán)境,將代碼編譯成可執(zhí)行的二進(jìn)制文件
FROM golang:1.13
WORKDIR /go/src/github.com/wilhelmguo/multi-stage-demo/
COPY main.go .
RUN CGO_ENABLED=0 GOOS=linux go build -o http-server .

### Dockerfile:在臨時運行環(huán)境下執(zhí)行編譯后的執(zhí)行文件
FROM alpine:latest
WORKDIR /root/
COPY http-server .
CMD ["./http-server"]

### build.sh:該腳本將應(yīng)用的編譯和運行環(huán)境共同執(zhí)行
#!/bin/bash
docker build -t http-server:build . -f Dockerfile.build
docker create --name builder http-server:build
docker cp builder:/go/src/github.com/wilhelmguo/multi-stage-demo/http-server ./http-server
docker rm -f builder 

docker build -t http-server:latest .
rm ./http-server

多階段構(gòu)建

Docker 在 17.05 版本推出了多階段構(gòu)建(multistage-build)的解決方案,多階段構(gòu)建主要使用場景就是分離編譯環(huán)境和運行環(huán)境。Docker 允許我們在 Dockerfile 中使用多個 FROM 語句,而每個 FROM 語句都可以使用不同基礎(chǔ)鏡像,最終生成的鏡像,是以最后一條 FROM 為準(zhǔn),因此還節(jié)省了第一階段所生成的編譯鏡像所占用的磁盤空間。

FROM golang:1.13
WORKDIR /go/src/github.com/wilhelmguo/multi-stage-demo/
COPY main.go .
RUN CGO_ENABLED=0 GOOS=linux go build -o http-server .

FROM alpine:latest  
WORKDIR /root/
# --from=0 表示從第一階段構(gòu)建結(jié)果中拷貝文件到當(dāng)前構(gòu)建階段
COPY --from=0 /go/src/github.com/wilhelmguo/multi-stage-demo/http-server .
CMD ["./http-server"] 

為構(gòu)建階段命名

默認(rèn)情況下,每一個構(gòu)建階段都沒有被命名,我們可以通過 FROM 指令出現(xiàn)的順序來引用這些構(gòu)建階段,構(gòu)建階段的序號是從 0 開始的。然而,為了提高 Dockerfile 文件的可讀性,我們也可以使用 AS 指令為某些構(gòu)建階段起一個名稱,這樣即便后面我們對 Dockerfile 中的內(nèi)容進(jìn)行重新排序或者添加了新的構(gòu)建階段,其他構(gòu)建過程中的 COPY 指令也不需要修改。

FROM golang:1.13 AS builder
WORKDIR /go/src/github.com/wilhelmguo/multi-stage-demo/
COPY main.go .
RUN CGO_ENABLED=0 GOOS=linux go build -o http-server .

FROM alpine:latest  
WORKDIR /root/
# 將 --from=0 改成了 --from=builder
COPY --from=builder /go/src/github.com/wilhelmguo/multi-stage-demo/http-server .
CMD ["./http-server"]

停止在特定的構(gòu)建階段

有時候,我們的構(gòu)建階段非常復(fù)雜,我們想在代碼編譯階段進(jìn)行調(diào)試,但是多階段構(gòu)建默認(rèn)構(gòu)建 Dockerfile 的所有階段,為了減少每次調(diào)試的構(gòu)建時間,我們可以使用 target 參數(shù)來指定構(gòu)建停止的階段。

$ docker build --target builder -t http-server:latest .

使用現(xiàn)有鏡像作為構(gòu)建階段

使用多階段構(gòu)建時,我們不僅可以從 Dockerfile 已經(jīng)定義的階段中拷貝文件,還可以使用 COPY --from 指令從一個指定的鏡像中拷貝文件,指定的鏡像可以是本地已經(jīng)存在的鏡像,也可以是遠(yuǎn)程鏡像倉庫上的鏡像。

COPY --from=nginx:latest /etc/nginx/nginx.conf /etc/local/nginx.conf
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容