Docker 镜像体积优化
本文最后更新于 2024年6月7日 下午
在我使用docker
对我目前负责的一个项目进行部署时,遇到了这样的一个问题,使用dockerfile
构建出的docker
镜像的体积太大了。当时我只觉得这是不可避免的,毕竟容器的底层还是运行着一个操作系统,加之Golang
的编译环境,再加上项目的代码以及静态资源,最终构建出的镜像体积为1.1G
似乎是一件再正常不过的事情。
Version 1
以下是我第一版用于构建docker
镜像的dockerfile
,可以看到为了保证最终容器的兼容性,我使用1.16
版本的Golang
镜像作为基础镜像,该镜像的下层为Ubuntu
镜像。
1 |
|
打包之后,查看一下生成的镜像,发现该镜像的大小为1.1G
,显然达到了一个不能接受的大小,但令人难以置信的是一开始我就将这个镜像推送至DockerHub
,然后又将这个镜像拉取到部署到服务器上。
Version 2
由于考虑到,上一个版本中我们是以Ubuntu
作为底层镜像来进行镜像构建的,但实际上我们并不需要Ubuntu
中附加的诸多软件和功能,我们仅仅需要一个能够运行代码的环境,那么有没有这样的操作系统镜像呢?Alpine
操作系统是一个面向安全的轻型 Linux
发行版。它不同于通常 Linux
发行版,Alpine
采用了 musl libc
和 busybox
以减小系统的体积和运行时资源消耗。Alpine Docker
镜像也继承了Alpine Linux
发行版的这些优势。相比于其他 Docker
镜像,它的容量非常小,仅仅只有5 MB
左右(对比Ubuntu
系列镜像接近200 MB
),且拥有非常友好的包管理机制。官方镜像来自 docker-alpine
项目。为了减小docker
镜像的体积,这次使用了golang:alpine
作为基础镜像进行构建,其中移除了非必要的工具,只提供最基础的功能,因此相比我们第一个版本使用的Ubuntu镜像可以节省很多的体积。
1 |
|
如我们所预料的那样,使用这个方法改进后的镜像大小,下降了400M
左右,但是700M
还是让人无法接受,我们使用命令查看一下镜像构建时每层的大小。可以看到在LABEL
命令执行前,文件的体积已经很大了。这是因为我们还是依赖Golang
的编译环境,并且在编译Golang
时还要通过网络拉取很多的依赖库,导致最终的镜像体积爆炸。
Version 3
我们着手想办法继续减小构建出的镜像体积。我了解到一种分阶段构建的方法,也即先使用一个拥有编译环境的镜像对代码进行编译,然后将编译后的代码拷贝至一个新的alpine
镜像中运行我们编译后的二进制文件。
1 |
|
通过这个方法,我们发现镜像的大小大幅下降,下降至30M。
Version 4
到这里镜像的大小已经大幅度压缩了,还有什么办法可以进一步减小镜像的大小吗?办法还真有!Alpine
相比于Ubuntu
是一个大小足够小的操作系统镜像,但是其中还是携带了一部分的包管理工具,这些包管理工具对我们来说还是多余的,能否将他们也去掉呢?
这时候就需要用到scratch
镜像,官方说明:该镜像是一个空的镜像,可以用作构建docker
镜像的最小基础镜像使用,并且在其上可以运行没有依赖的二进制文件。这个镜像无疑是最满足我们需求的。
1 |
|
构建完成,镜像的体积又一次减少了7M
。
Version 5
我们再过分一点,在go build
阶段添加参数,去掉了调试信息以减小镜像尺寸,并且禁用cgo
。
1 |
|
镜像的体积又稍微减少了一些,至此我停止继续折腾它了。