寻根究底,为什么 Docker 中的 Alpine Linux 镜像能这么小?

简介: 在这篇文章中,我以 Docker 中的 Alpine 与 Debian 镜像来详细对比它们的大小,及导致它们大小的原因。我们都知道,Debian 比 Ubuntu 更精简,这样对比会更有价值。

前言

去年我发表了文章 对 Docker 基础镜像的思考,该不该选择 alpine,其中对于 Alpine Linux 镜像如此之小的原因我解释为它使用了 musl 而不是 glibc

有人发现并指出了我的这个错误,说 muslglibc 的大小差别不足以造成如此大的差距,应该别有原因。

我一直记着这事,最近抽时间再次研究了下,确实如其所说,Alpine Linux 之所以这么小的原因,虽然 musl 是其中一个原因,但它是多种因素导致的。

在此我有必要表示歉意,同时我需要补充这篇文章,对于 Alpine Linux 之所以这么小,再解释的更清楚一些。

1、探究

在这篇文章中,我以 Docker 中的 AlpineDebian 镜像来详细对比它们的大小,及导致它们大小的原因。我们都知道,DebianUbuntu 更精简,这样对比会更有价值。

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 发行版本中的执行文件,它全部都只是busyboxalias 而已。

也就是,Alpine 中最主要的一个命令文件,就是 busybox ,而 busybox 是一个 5M 不到大小的,包含近 300 多个命令的工具集。

是不是 bin 命令的瑞士军刀?

  • 第四:没有 apt 与 systemd

Debian/Ubuntu 中,包管理是 apt。同样,Debian 与大都数 Linux 类似,都是使用的 systemd

但在 Alpine 中,apk 取代了 aptAlpine 同样没有使用 systemd,而是使用了 OpenRC,无论是 apt 还是 OpenRC,都是轻而小的实现。

3. 结论

现在,我能比上一次稍微准确的说出 Alpine 能这么小的原因了。

大致为:

  1. Alpine 中删除了一些不影响系统运行的辅助性资源文件;
  2. 使用 Musl取代了 Glibc;
  3. 使用了 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 等搭建一个内网镜像中心,能让容器镜像的上传下载更快捷方便。

参考

转载声明

目录
相关文章
|
2月前
|
Ubuntu Linux Shell
(已解决)Linux环境—bash: wget: command not found; Docker pull报错Error response from daemon: Get https://registry-1.docker.io/v2/: net/http: request canceled
(已成功解决)Linux环境报错—bash: wget: command not found;常见Linux发行版本,Linux中yum、rpm、apt-get、wget的区别;Docker pull报错Error response from daemon: Get https://registry-1.docker.io/v2/: net/http: request canceled
422 68
(已解决)Linux环境—bash: wget: command not found; Docker pull报错Error response from daemon: Get https://registry-1.docker.io/v2/: net/http: request canceled
|
1月前
|
Ubuntu NoSQL 开发工具
《docker基础篇:4.Docker镜像》包括是什么、分层的镜像、UnionFS(联合文件系统)、docker镜像的加载原理、为什么docker镜像要采用这种分层结构呢、docker镜像commit
《docker基础篇:4.Docker镜像》包括是什么、分层的镜像、UnionFS(联合文件系统)、docker镜像的加载原理、为什么docker镜像要采用这种分层结构呢、docker镜像commit
204 70
|
11天前
|
网络协议 Linux 网络安全
docker centos镜像 npm安装包时报错“npm ERR! code ECONNRESET”
通过上述步骤,您可以有效解决在 Docker 中使用 CentOS 镜像安装 npm 包时遇到的 "npm ERR! code ECONNRESET" 错误。希望这些方法能帮助您顺利进行 npm 包的安装。
87 26
|
19天前
|
Linux Docker 容器
Linux 中停止 Docker 服务报 warning 导致无法彻底停止问题如何解决?
在 Linux 系统中,停止 Docker 服务时遇到警告无法彻底停止的问题,可以通过系统管理工具停止服务、强制终止相关进程、检查系统资源和依赖关系、以及重置 Docker 环境来解决。通过以上步骤,能够有效地排查和解决 Docker 服务停止不彻底的问题,确保系统的稳定运行。
87 19
|
30天前
|
存储 Docker 容器
Docker-基础(数据卷、自定义镜像、Compose)
通过数据卷实现持久化存储,通过自定义镜像满足特定需求,通过Docker Compose方便地管理多容器应用
84 27
|
1月前
|
Ubuntu NoSQL Linux
《docker基础篇:3.Docker常用命令》包括帮助启动类命令、镜像命令、有镜像才能创建容器,这是根本前提(下载一个CentOS或者ubuntu镜像演示)、容器命令、小总结
《docker基础篇:3.Docker常用命令》包括帮助启动类命令、镜像命令、有镜像才能创建容器,这是根本前提(下载一个CentOS或者ubuntu镜像演示)、容器命令、小总结
151 6
《docker基础篇:3.Docker常用命令》包括帮助启动类命令、镜像命令、有镜像才能创建容器,这是根本前提(下载一个CentOS或者ubuntu镜像演示)、容器命令、小总结
|
1月前
|
存储 Docker 容器
Docker-基础(数据卷、自定义镜像、Compose)
通过数据卷实现持久化存储,通过自定义镜像满足特定需求,通过Docker Compose方便地管理多容器应用。掌握这些Docker基础概念和操作,可以显著提高开发和部署效率,确保应用程序的可移植性和可扩展性。
71 22
|
1月前
|
Ubuntu NoSQL 关系型数据库
《docker基础篇:6.本地镜像发布到私有库》包括本地镜像发布到私有库流程、docker regisry是什么、将本地镜像推送到私有库
《docker基础篇:6.本地镜像发布到私有库》包括本地镜像发布到私有库流程、docker regisry是什么、将本地镜像推送到私有库
123 29
|
2月前
|
Docker 容器
将本地的应用程序打包成Docker镜像
将本地的应用程序打包成Docker镜像
|
27天前
|
弹性计算 运维 Ubuntu
os-copilot在Alibaba Cloud Linux镜像下的安装与功能测试
我顺利使用了OS Copilot的 -t -f 功能,我的疑惑是在换行的时候就直接进行提问了,每次只能写一个问题,没法连续换行更有逻辑的输入问题。 我认为 -t 管道 功能有用 ,能解决环境问题的连续性操作。 我认为 -f 管道 功能有用 ,可以单独创建可连续性提问的task问题。 我认为 | 对文件直接理解在新的服务器理解有很大的帮助。 此外,我还有建议 可以在非 co 的环境下也能进行连续性的提问。
69 7