工作中有以下场景:

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

Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐