通過(guò)多階段構(gòu)建減小Golang鏡像的大小
我們?nèi)绾瓮ㄟ^(guò)引入具有多階段構(gòu)建過(guò)程的Dockerfiles來(lái)減小Golang鏡像的大???
讓我們從一個(gè)通用的Dockerfile開(kāi)始,它負(fù)責(zé)處理基本的事務(wù),如依賴項(xiàng)、構(gòu)建二進(jìn)制文件、暴露必要的端口等,以便為Go中的一個(gè)非?;A(chǔ)的REST API提供服務(wù)。
FROM golang:1.16-alpine
ENV GO111MODULE=on
WORKDIR /app
COPY go.mod .
COPY go.sum .
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build
ENV HTTP_PORT=8080
EXPOSE 8080
ENTRYPOINT ["/app/reduce-docker-size"]
那將無(wú)縫地構(gòu)建您項(xiàng)目的二進(jìn)制文件,并創(chuàng)建Docker鏡像。
這樣做真的足夠好嗎? 我會(huì)說(shuō)不,因?yàn)樯傻溺R像大小超過(guò)300MB(確切地說(shuō)是322MB),因?yàn)樗怂械腉olang工具,這對(duì)我們來(lái)說(shuō)是不必要的,因?yàn)槲覀冎甘揪幾g器禁用cgo(CGO_ENABLED=0)并靜態(tài)鏈接任何將為我們提供自包含可執(zhí)行文件的C綁定(其大小僅為6.05MB?。?,無(wú)需任何外部框架或運(yùn)行時(shí)依賴。
圖片
CGO_ENABLED=0 是至關(guān)重要的,如果我們不構(gòu)建自包含的可執(zhí)行文件,多階段構(gòu)建過(guò)程將無(wú)法工作。
我們可以做得更好的是,采用所謂的多階段構(gòu)建。多階段構(gòu)建允許多個(gè)不同的構(gòu)建過(guò)程,這些構(gòu)建可以完全從不同的基礎(chǔ)鏡像構(gòu)建,選擇性地將文件從一個(gè)階段傳遞到下一個(gè)階段,從而剝離最終鏡像中所有不必要的文件。例如,我們可以將前一個(gè)階段稱為BUILD,然后引入第二個(gè)階段,我們稱之為BINARIES,該階段使用alpine:latest作為基礎(chǔ)鏡像,并從BUILD階段復(fù)制我們構(gòu)建的應(yīng)用程序的二進(jìn)制文件。
# BUILD
FROM golang:1.16-alpine as BUILD
ENV GO111MODULE=on
WORKDIR /app
COPY go.mod .
COPY go.sum .
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build
ENV HTTP_PORT=8080
EXPOSE 8080
# BINARIES
FROM alpine:latest
COPY --from=BUILD /app/reduce-docker-size /app/reduce-docker-size
ENTRYPOINT ["/app/reduce-docker-size"]
由于不再需要,配備了golang工具包的 已被清理?,F(xiàn)在鏡像大小已降至11.7MB。
圖片
這個(gè)好到足夠了嗎? 我會(huì)說(shuō)是的,但是為了實(shí)驗(yàn)的緣故,我們還是盡量挑戰(zhàn)一下極限。我們繼續(xù)沿著多階段構(gòu)建的道路前進(jìn),但這次在我們的第二階段,我們將不再使用alpine:latest,而是轉(zhuǎn)向一個(gè)非常特殊的名為scratch的鏡像,這是一個(gè)完全空白的鏡像,實(shí)際上什么都沒(méi)有。
# BUILD
FROM golang:1.16-alpine as BUILD
ENV GO111MODULE=on
WORKDIR /app
COPY go.mod .
COPY go.sum .
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build
ENV HTTP_PORT=8080
EXPOSE 8080
# MINIATURE
FROM scratch
COPY --from=BUILD /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
COPY --from=BUILD /app/reduce-docker-size /app/reduce-docker-size
ENTRYPOINT ["/app/reduce-docker-size"]
新創(chuàng)建的鏡像現(xiàn)在已經(jīng)降至6.34MB!
圖片
因?yàn)槲覀冾A(yù)先告知的scratch鏡像實(shí)際上是空的,所以找不到任何根SSL證書。以下指令將在最終鏡像中復(fù)制證書,絕對(duì)不應(yīng)被省略:
COPY — from=BUILD /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
請(qǐng)問(wèn)使用scratch作為最終階段的基礎(chǔ)鏡像值得嗎?我會(huì)說(shuō)既值得又不值得。如果你排除一些特殊情況——那些在alpine:latest和scratch構(gòu)建的最終鏡像之間的5.36MB差異可能會(huì)產(chǎn)生巨大的影響——在其余的情況下,你最終會(huì)在生產(chǎn)中得到一個(gè)完全沒(méi)有任何工具的容器,我完全不推薦這樣做。這些特殊情況很少見(jiàn),所以在為了僅僅5.36M。