使用alpine给镜像减肥,以及no such file or directory的问题解决

以go项目为例

首先我们下看一下直接打包的程序有多大

[$] <git:(master*)> go build -o ./bin/app .
[$] <git:(master*)> ls -lh bin
total 13M
-rwxrwxr-x 1 liyang liyang 13M Jul 24 14:02 app

可以看到,只有13M

然后我们再来看一个没经过优化的的Dockerfile打包出来的镜像

FROM golang:1.18

WORKDIR /usr/src/app

COPY go.mod go.sum ./

RUN export GOPROXY=https://proxy.golang.com.cn,direct && go mod download && go mod verify

COPY . .

RUN go build -v -o /usr/local/bin/app .

CMD ["app"]

打包出来的镜像竟然有1GB多,原因是镜像里包含了go镜像内容和所有编译所用到的工具/源码等

REPOSITORY   TAG       IMAGE ID       CREATED             SIZE
bdfdc        default   244a313c3bac   24 seconds ago      1.09GB

下一步使用ubuntu中间镜像来优化镜像体积

FROM golang:1.18 as buildstage

WORKDIR /usr/src/app

COPY go.mod go.sum ./

RUN export GOPROXY=https://proxy.golang.com.cn,direct && go mod download && go mod verify

COPY . .

RUN go build -v -o /usr/local/bin/app .

FROM ubuntu

COPY --from=buildstage /usr/local/bin/app /usr/local/bin/app

CMD ["app"]
REPOSITORY   TAG       IMAGE ID       CREATED             SIZE
bdfdc        ubuntu    8f002a76c331   26 minutes ago      85.5MB

镜像一下减少到85.5MB,已不足原来的1/10,用下面的命令运行是没问题的

docker run dbdfc:ubuntu

但是还是不够小,如果把ubuntu镜像换成alpine可以更进一步优化体积,我们把上面的FROM ubuntu改成FROM alipine,其他地方保持不变,重新打包镜像,发现镜像已经减小到了18.3MB

EPOSITORY   TAG       IMAGE ID       CREATED             SIZE
bdfdc        alpine    a9073c5ba036   8 minutes ago       18.3MB

但是这个时候出现了一个问题,运行的时候报错了

[$] <git:(master*)> docker run --rm bdfdc:alpine  
exec /usr/local/bin/app: no such file or directory

不要怀疑路径的问题,因为我已经到容器里检查过了

原因是由于alpine镜像使用的是musl libc而不是gnu libc,/lib64/ 是不存在的。但他们是兼容的,可以创建个软连接过去,在创建镜像是增加这条命令RUN mkdir /lib64 && ln -s /lib/libc.musl-x86_64.so.1 /lib64/ld-linux-x86-64.so.2

此部分参考了https://www.cnblogs.com/yangzp/p/14609641.html

FROM golang:1.18 as buildstage

WORKDIR /usr/src/app

COPY go.mod go.sum ./

RUN export GOPROXY=https://proxy.golang.com.cn,direct && go mod download && go mod verify

COPY . .

RUN go build -v -o /usr/local/bin/app .

FROM alpine

COPY --from=buildstage /usr/local/bin/app /usr/local/bin/app

RUN mkdir /lib64 && ln -s /lib/libc.musl-x86_64.so.1 /lib64/ld-linux-x86-64.so.2

CMD ["app"]

这个一个精简版的镜像就做好了.

当然还可以继续优化,比如用第二个基础镜像使用scratch,使用这个镜像比使用alpine可以再减小5MB左右,打包成功的镜像竟然比直接打包项目还小.但是里面确缺少了很多基础的命令/工具/库,甚至连sh都没有,给后面的调试带来了很多麻烦,在一个程序几十几百兆的项目中,这5MB的开销不值得一提

REPOSITORY   TAG       IMAGE ID       CREATED             SIZE
bdfdc        alpine    e295e34e5afb   7 minutes ago       18.3MB
bdfdc        scratch   0c295c729d99   About an hour ago   12.7MB