Golang 编译最小化的 Docker Image

普通做法

以下是引用自某开源项目的做法:

1
2
3
4
5
FROM golang:alpine
RUN apk update && \
apk upgrade && \
apk add git
RUN go get github.com/author/package

这样产生的包大约是 100MB,已经很不错了,但是还是浪费了大量空间。

比如 Golang SDK 在程序运行中根本用不到,Go Get带来的源文件同样用不到。Golang是可以编译到真二进制的的语言,只要保留程序本身和必要的动态链接库(.so)即可。进一步,如果使用静态链接,那库也可以不要。

From Alpine

首先编译出静态链接的二进制:

1
CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o build/release/main ./main.go

然后是Dockerfile,把刚刚编译出的程序拷贝进去就可以了。其中用到 APK (Alpine Package Manager) 安装CA证书,因为Golang标准库中的SSL会使用系统的CA证书。

1
2
3
4
5
FROM alpine:3.4
RUN apk add --no-cache ca-certificates

ADD ./build/release/main /
ENTRYPOINT ["/main"]

From Scratch

其实,Alpine Linux也可以不要,直接从0开始Build一个Docker Image也是可行的,理论上这是小的方案。

同上,先编译出静态链接的二进制。Dockerfile如下:

1
2
3
4
5
FROM scratch
ADD ca-certificates.crt /etc/ssl/certs/

ADD ./build/release/main /
ENTRYPOINT ["/main"]

ca-certificates.crt 通常位于系统的/etc/ssl/certs/目录下,你需要从那里把他拷贝到当前目录,然后添加到镜像中。


为了方便使用,我把以上两种方案都build好放在了Docker Hub上

直接在Dockerfile里FROM fuyufjh/go-alpine或者FROM fuyufjh/go-scratch即可。

References

  1. Building Minimal Docker Containers for Go Applications
  2. Building Docker Images for Static Go Binaries