寻根究底,为什么 Docker 中的 Alpine Linux 镜像能这么小?
前言
去年我发表了文章 对 Docker 基础镜像的思考,该不该选择 alpine,其中对于 Alpine Linux 镜像如此之小的原因我解释为它使用了 musl 而不是 glibc。
有人发现并指出了我的这个错误,说 musl 与 glibc 的大小差别不足以造成如此大的差距,应该别有原因。
我一直记着这事,最近抽时间再次研究了下,确实如其所说,Alpine Linux 之所以这么小的原因,虽然 musl 是其中一个原因,但它是多种因素导致的。
在此我有必要表示歉意,同时我需要补充这篇文章,对于 Alpine Linux 之所以这么小,再解释的更清楚一些。
1、探究
在这篇文章中,我以 Docker 中的 Alpine 与 Debian 镜像来详细对比它们的大小,及导致它们大小的原因。我们都知道,Debian 比 Ubuntu 更精简,这样对比会更有价值。
1.1 镜像大小
通过 docker images ls 命令,可以查出这两个镜像当前的 latest 版本的大小对比:
REPOSITORY TAG IMAGE ID CREATED SIZE
debian latest 5c8936e57a38 3 weeks ago 124MB
alpine latest 042a816809aa 3 weeks ago 7.05MB
其中 debian 的大小为 124M,而 alpine 的大小只有 7.05MB 左右,大小相差还是非常明显的。
接下来,我将探究为它们究竟差别在哪?
1.2 探究方法
通过 du -s * | sort -nr 计算文件夹大小,不断寻找两个镜像中的大小差别比较明显的一些关键目录。
1.3 结果
与大小有关的关键目录如下:(仅列出差别明显的关键目录)
Debian
36M /usr/lib/x86_64-linux-gnu
31M /usr/share/locale
13M /usr/share/doc
8.2M /lib/x86_64-linux-gnu
6.1M /var
5.2M /bin
4.0M /sbin
Alpine
828.0K /bin
72.0K /var
2. 分析
通过上述目录,可以大致分析出, Alpine镜像能如此之小的原因大致能区分为几大类:
第一:删除部分非必须的资源文件
可以看出,这两个目录在Alpine中压根没有
• /usr/share/locale: 国际化文件
• /usr/share/doc: 帮助文档
可以推断,Alpine 删除了类似的无用的资源文件,没有它们并不影响系统的运行。
第二:使用 musl,而非 glibc
/usr/lib/x86_64-linux-gnu 与 /lib/x86_64-linux-gnu 这两个目录大多是 glibc,libc,perl 等的共享类库所有目录。如我在以前的文章中所述,Alpine 中没有使用 glibc,而是使用了 musl,所以这一部分占据的大小也小了很多。
同时,通过在 musl官网与 glibc 官网查阅它们的压缩安装包大小分别是:
musl
1.1MB musl-1.2.3.tar.gz
glibc
18M glibc-2.3.6.tar.gz
123K glibc-libidn-2.3.6.tar.gz
320K glibc-linuxthreads-2.3.6.tar.gz
1.8M glibc-ports-2.16.0.tar.gz
可以看出,光是安装包就有20倍左右的差别,安装后当然相差更大。
第三:使用了 busybox 工具集
同样,分析上面的目录,会发现一个有趣的现象,Debian 中的 /bin 与 /sbin 目录大小明显高于 Alpine 的 /bin,这又是为什么呢?
这是因为,Apline 使用的是 busybox 这个工具集。那 busybox 是什么呢?
你可以把 busybox 理解为 bin 命令的瑞士军刀。
我们都知道,Linux 中我们依赖各种命令去操作系统,比如 cd,ls,pwd 等,这些命令每个都是一个个可执行文件。
而 busybox 也是一个可执行文件,但它与众不同,它是包含了常用的 300 多个命令的工具集。
看代码更容易理解:
# 功能与ls类似
busybox ls
# 功能与pwd类似
busybox pwd
# 功能与kill类似
busybox kill
现在你明白了吗,Apline 中压根没有 ls,pwd 这些类似其它 Linux 发行版本中的执行文件,它全部都只是busybox 的 alias 而已。
也就是,Alpine 中最主要的一个命令文件,就是 busybox ,而 busybox 是一个 5M 不到大小的,包含近 300 多个命令的工具集。
是不是 bin 命令的瑞士军刀?
第四:没有 apt 与 systemd
在 Debian/Ubuntu 中,包管理是 apt。同样,Debian 与大都数 Linux 类似,都是使用的 systemd。
但在 Alpine 中,apk 取代了 apt,Alpine 同样没有使用 systemd,而是使用了 OpenRC,无论是 apt 还是 OpenRC,都是轻而小的实现。
3. 结论
现在,我能比上一次稍微准确的说出 Alpine 能这么小的原因了。
大致为:
Alpine 中删除了一些不影响系统运行的辅助性资源文件;
使用 Musl取代了 Glibc;
使用了 BusyBox, apt 以及 OpenRC等一些轻量级实现;
从这些做法上也能看出,Alpine 的定位不是普通的 Linux 系统,它应该是为嵌入式 Linux 而生,几 MB 的系统大小,当然更适合嵌入式 Linux。
这也从另一个角度充分说明 Linux 系统的优秀,也就是只需要一个 Linux 内核,其它外围的一切几乎都是可以替代的,而仍然能保证 Linux 系统的运行与一致性。
幸运的是,Linux 内核是开源的。而正因为它是开源的,今天 Linux 才能造福世界。
关于基础镜像是否使用 Alpine Linux 构建的建议
如果你的服务,不依赖C,那 alpine 是合适的选择,否则不应当使用 alpine 做为基础镜像;
考虑到部署的一致性,就算是容器,使用同一系的 Linux基础镜像是更妥当的选择,比如全是 Debian 系或 RHEL 系等;
优化镜像的空间非常有必要,各种建议仍然非常有价值,但不要走的太过,镜像的空间问题并没有你想像的那么严重;
在公司或项目级别,不要使用 Docker Hub 或其它公有云镜像,使用简易的 registry 或企业级 Harbor,Nexus 等搭建一个内网镜像中心,能让容器镜像的上传下载更快捷方便。
参考
[1] 对 Docker 基础镜像的思考,该不该选择 alpine : https://taoofcoding.tech/blogs/2022-08-18/shoule-we-use-alpine-in-docker-image
转载声明
原文地址:https://mp.weixin.qq.com/s/XS6HNDKSU-MtM_Spb5hudw