工作中有以下场景:
A同学:领导,我的程序写好了,本地测试没啥问题了。
领导:好,那你打包成docker镜像吧。
A同学一顿操作。。。
A同学:领导,我的镜像打好了。
领导:一个简单的go程序,你的镜像1.4G?回去重新打!
A同学:我打的没毛病啊,镜像大,是因为依赖多。。。。
大神出场。。。
大神:我看看你的Dockerfile
A同学打开了Dockerfile
FROM golang:1.18 AS builder
ENV GO111MODULE=on \
CGO_ENABLED=0 \
GOOS=linux \
GOARCH=amd64
ENV GOPROXY=https://goproxy.cn
WORKDIR /build
COPY go.mod ./
COPY go.sum ./
RUN go mod download
COPY hello.go ./
RUN go build -o hello.
ENTRYPOINT ["./hello"]
大神:你把应用的编译过程和最后的程序放到一个包里,能不大吗,你要采用分段式打包法。
A同学:啥叫分段式打包法?
大神:我给你改改,你看着。
FROM golang:1.18 AS builder
ENV GO111MODULE=on \
CGO_ENABLED=0 \
GOOS=linux \
GOARCH=amd64
ENV GOPROXY=https://goproxy.cn
WORKDIR /build
COPY go.mod ./
COPY go.sum ./
RUN go mod download
COPY hello.go ./
RUN go build -o hello .
FROM scratch
COPY --from=builder /build/hello /
ENTRYPOINT ["./hello"]
大神:看到了吧,要打成两个镜像。第一个镜像是你的编译过程,第二个镜像是使用FROM scratch方法,创建一个空镜像,然后把你的程序拷到这个空镜像里,这样不就小了吗?你看一下效果。
root@node2:~/build# docker images
看到了吧,你最终要用的镜像才40.9兆。
A同学:原来如此。
总结:
将应用打包镜像时:
第一不要选择FROM某操作系统,而是尽量选择编译环境镜像,比如jdk,golang等等,可减小镜像的大小。
第二要使用分段编译,将编译过程和可执行程序分成两个镜像。
第三,golang的应用打包时,建议使用go mod的方式,并且加上go mod download这个命令,这样,docker会将下载的go依赖缓存,避免每次打包都下载一遍go依赖。当使用这种方式时,docker build命令要加上--network host,否则容器内网络不通会导致go mod download超时。命令如下:
docker build --network host . -t hello:v1beta1