之前應該沒寫過用 Docker 結合 Go 語言編譯出最小 Image 的文章,剛好趁這機會來介紹。其實網路上可以直接找到文章,像是這篇『Building Minimal Docker Containers for Go Applications』,那本文來介紹 Docker 新功能 multi-stage builds,此功能只有在 17.05.0-ce 才支援,看起來是 2017/05/03 號會 release 出來。我們拿 Go 語言的 Hello World 來介紹 Single build 及 Multiple build。
Single build
底下是 Go 語言 Hello World 範例:package main import "fmt" func main() { fmt.Println("Hello World!") }接著用 alpine 的 Go 語言 Image 來編譯出執行檔。
FROM golang:alpine WORKDIR /app ADD . /app RUN cd /app && go build -o app ENTRYPOINT ./app接著執行底下編譯指令:
$ docker build -t appleboy/go-app . $ docker run --rm appleboy/go-app最後檢查看看編譯出來的 Image 大小,使用
docker images | grep go-app
,會發現 Image 大小為 258 MB
Multiple build
Multiple build 則是可以在Dockerfile
使用多個不同的 Image 來源,請看看底下範例
# build stage FROM golang:alpine AS build-env ADD . /src RUN cd /src && go build -o app # final stage FROM alpine WORKDIR /app COPY --from=build-env /src/app /app/ ENTRYPOINT ./app從上面可以看到透過
AS
及 --from
互相溝通,以前需要寫兩個 Dockerfile,現在只要一個就可以搞定。最後一樣執行編譯指令:
$ docker build -t appleboy/go-app . $ docker run --rm appleboy/go-app會發現最後大小為 6.35 MB,比上面是不是小了很多。
最小 Image?
6.35 MB 是最小的 Image 了嗎?才單單一個 Hello World 執行檔,用 Docker 包起來竟然要 6.35,其實不用這麼大,我們可以透過 Dokcer 所提供的最小 Image: scratch,將執行檔直接包進去即可,在編譯執行檔需加入特定參數才可以:$ CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o app再透過 Docker 包起來
FROM centurylink/ca-certs ADD app / ENTRYPOINT ["/app"]編譯出來大小為: 1.81MB,相信這是最小的 Image 了。
結論
Multiple build 非常方便,這樣就可以將多個步驟全部合併在一個 Dockerfile 處理掉,像是底下例子from debian as build-essential arg APT_MIRROR run apt-get update run apt-get install -y make gcc workdir /src from build-essential as foo copy src1 . run make from build-essential as bar copy src2 . run make from alpine copy --from=foo bin1 . copy --from=bar bin2 . cmd ...用一個 Dockerfile 產生多個執行檔,最後再用 alpine 打包成 Image。