由于Golang編譯之后的文件是二進制长酗,而scratch是docker最基礎(chǔ)的空image溪北,所以可以使用scratch來構(gòu)建Go程序的docker image,使得最終構(gòu)建的image最小化.
構(gòu)建image過程分為兩步:
- 在Go基礎(chǔ)image中build.
- 將build好的二進制文件拷貝到scratch image中。
無需cgo的程序
對于無需cgo交叉編譯的程序之拨,使用scratch來作為最終運行的基礎(chǔ)image非常合適茉继。
首先,選擇合適版本的golang基礎(chǔ)image來build蚀乔,這里沒有必要選擇更小的golang alpine烁竭,build過程中pull一般會有緩存所以pull速度差別不大,此外alpine中沒有g(shù)it和ssl吉挣,我們在構(gòu)建image過程中都有可能用到派撕,況且alpine也不會影響最終image大小。
FROM golang:1.13 AS builder
禁掉cgo交叉編譯睬魂,我們服務(wù)器一般為linux amd64终吼,build二進制文件。
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags="-w -s" -o /bin/appmain main.go
對于絕大多數(shù)go程序而言氯哮,是無需root來運行际跪,根據(jù)docker best practice,使用non-root來運行程序能夠帶來更好的安全性蛙粘,所以我們使用non-root用戶來運行垫卤,創(chuàng)建一個appuser威彰,之后再拷貝到scratch運行image中出牧。(scratch是空image,所以在builder中創(chuàng)建user歇盼,再拷貝舔痕。)
# 創(chuàng)建appuser
RUN groupadd -r appuser && useradd --no-log-init -r -g appuser appuser
...
# 拷貝appuser到scratch
COPY --from=builder /etc/passwd /etc/passwd
...
# 選擇appuser為默認程序運行用戶
USER appuser
多數(shù)程序可能會用到ssl,我們將builder中的crt拷貝一下即可豹缀。(如果builder是alpine伯复,不能拷貝,需要在alpine中apk先預(yù)裝一下邢笙。)
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
完整版Dockerfile
FROM golang:1.13 AS builder
COPY . /app
WORKDIR /app
RUN groupadd -r appuser && useradd --no-log-init -r -g appuser appuser
RUN go mod download
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags="-w -s" -o /bin/appmain main.go
FROM scratch
COPY --from=builder /etc/passwd /etc/passwd
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
COPY --from=builder /bin/appmain /bin/appmain
USER appuser
CMD [ "/bin/appmain" ]
需要cgo的程序
有些Go程序是需要cgo交叉編譯的啸如,例如ethereum. 對于需要cgo的程序,相對于scratch氮惯,更推薦使用alpine來作為基礎(chǔ)image叮雳,原因是alpine中帶有l(wèi)ibc,并且體積也才2MB多妇汗。而scratch中沒有帘不,當(dāng)然也可以在builder中l(wèi)dd依賴并拷貝到scratch中。只是用alpine會更方便一些杨箭。
在alpine中只要軟鏈接一下就可以使用寞焙。
RUN mkdir /lib64 && ln -s /lib/libc.musl-x86_64.so.1 /lib64/ld-linux-x86-64.so.2
此外,創(chuàng)建non-root用戶的步驟也沒有必要在builder中進行了,可以直接在alpine中創(chuàng)建捣郊。
RUN addgroup -S appuser && adduser -S -G appuser appuser
完整版Dockerfile
FROM golang:1.13 AS builder
COPY . /app
WORKDIR /app
RUN go mod download
RUN CGO_ENABLED=1 GOOS=linux GOARCH=amd64 go build -ldflags="-w -s" -o /bin/appmain main.go
FROM alpine:3.10
RUN mkdir /lib64 && ln -s /lib/libc.musl-x86_64.so.1 /lib64/ld-linux-x86-64.so.2
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
COPY --from=builder /bin/appmain /bin/appmain
RUN addgroup -S appuser && adduser -S -G appuser appuser
USER appuser
CMD [ "/bin/appmain" ]