1

为什么我不再使用Alpine Linux

 1 year ago
source link: https://www.51cto.com/article/751174.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

为什么我不再使用Alpine Linux

译文
作者: 千山 2023-04-04 19:14:40
Alpine Docker 镜像继承了 Alpine Linux 发行版的这些优势。相比于其他 Docker 镜像,Alpine 只有 5 MB 大小,并且拥有很友好的包管理机制。

​作者丨Martin Heinz

编译丨千山

在 Linux 的发展史上,各种 Linux 发行版本起了巨大的作用,正是它们加速了 Linux 的应用。其中比较著名的便是商业公司维护的 Red Hat 系列以及社区组织维护的 Debian 系列。

在众多的 Linux 版本中,每个版本都有自己的特点。今天故事的主角就是一款非商业性的通用 Linux 发行版——Alpine Linux,它是由社区开发的轻型 Linux 发行版,重点关注安全、性能和资源利用率。

区别于其他常见的 Linux 发行版,Alpine Linux 采用了 musl libc 和 busybox,从而减小系统体积,降低运行时的资源消耗。更重要的是,尽管体积小,但 Apline 提供了完整的 Linux 环境,其存储库中还包含了大量的软件包备选。可以称得上是“小而全”的典范。

Alpine Docker 镜像继承了 Alpine Linux 发行版的这些优势。相比于其他 Docker 镜像,Alpine 只有 5 MB 大小,并且拥有很友好的包管理机制。

在此背景下,Alpine Linux 逐渐成为当下容器基础镜像最流行的选项之一。好处是显而易见的,镜像下载速度更快、镜像安全性提升、占用更少磁盘空间等等,但是也有人在实践后发现:使用 Alpine 作为容器镜像,也要承受一些不可避免的麻烦和风险。

1、痛苦之源:处理 DNS 的方式

Alpine 在某些情况下是一个糟糕的选择,要理解这一点,首先需要谈谈 musl。

musl 是构建在 Linux 系统调用 API 之上的 C 标准库的实现,相比其他 Linux 发行版(如Ubuntu)使用的 glibc 更轻量级、更快、更简单。

这两种实现在大多数情况下都是可替换的。这就是为什么在大多数情况下,你可以从 Ubuntu 切换到 Alpine,而不会注意到任何不同。

但是再微小的差异也可能导致悲剧。其中主要的问题源于 musl 处理 DNS 的方式,更具体地说,musl(在设计上)不支持 DNS-over- tcp。

通常你不会注意到这个区别,因为大多数情况下,一个 UDP 数据包(512字节)就足以解析主机名……直到它不够用了。

之前正常工作了数月的应用程序(运行在 Kubernetes 上),突然开始抛出一个特定(非常关键)主机名的“未知主机”异常。

最糟糕的是,这可能是随机出现的,可能发生在任何时候,当一些外部网络变化导致某些特定域的分辨率需要超过单个 UDP 数据包中可用的 512 字节。

如果你运行数十个甚至数百个基于 Alpine 的微服务/应用程序,它们都突然停止工作,唯一的解决办法是切换到不同的 Linux 发行版,这需要重新构建所有应用程序并重新部署它们,那么你可能会面临一个令人抓狂的现实——强破坏性的、持续多日的停机。

总而言之,这个 DNS 问题不会在 Docker 容器中暴露出来。这只会发生在 Kubernetes 中,所以如果你在本地测试,一切都会正常工作,并且只有在将应用程序部署到集群时才会发现不可修复的问题。此外,Kubernetes 文档声称 DNS 问题只与“Alpine 3.3 或更早版本”相关,但我在 Alpine 3.16 上也遇到了上述问题,所以无需赘言。

另外,值得一提的是,许多流行的工具,例如 nicolaka/netshoot 或 giantswarm/tiny-tools,也使用 Alpine 作为基本镜像,前者是用于容器网络问题的解决工具。可以想象,当你的故障排除工具也坏了的时候,那只能祝你好运了。

2、交叉编译的风险

虽然 DNS 是 musl 最常见的问题,但有更多理由需要你审慎考虑。Alpine 使用 Musl Libc 作为传统的 glibc 的替代,编译软件的时候可能会遇到一些不可预知的问题,这一点会导致我们耗费不少不必要的时间。任何依赖于 C 标准库的编程语言或其库都会受到 musl 和 glibc 之间差异的影响。

例如,对于 Python,许多流行的库(如 NumPy 或 Cryptography)都依赖于 C 代码进行优化。幸运的是,至少对于 Numpy 这样的一些库,你可能会找到基于 alpine 的编译包和相关依赖项。

然而,对于不太受欢迎的编译器,你可能不得不自己编译。这样做真的值得吗?在我看来,不值得。此外,即使你设法构建了一个包含 numpy 的镜像,其大小将是 400MB 左右,在这种情况下,因为体积小而使用 Alpine 的理由无疑也站不住脚了。

此外,构建这样一个镜像的时间将是残酷的。你可以自己试试,下面的 Dockerfile 构建大约需要 10 分钟:

FROM python:3.11-alpine
RUN apk --update add gcc build-base
RUN pip install --no-cache-dir numpy

显然,类似的问题在其他语言中也会发生。例如,Node.js 使用附加组件,这些附加组件是用 C++ 编写的,并使用 node-gyp 编译,这些附加组件将依赖于 C 库,因此依赖于 glibc。

另一个例子是 Golang,它的标准库——或者更具体地说是 net/http 或 os/user 模块——依赖于 C 库,因此依赖于 glibc。如果应用程序需要 CGO_ENABLED=1,即使不使用这些特定的模块,使用 Alpine 显然也会遇到问题。

此外,不可忽视的一点是,在 Docker Hub 中,大部分镜像是没有 Alpine 版本的,比如 Mysql 和 PHP-Apache,如果我们需要基于这些环境开发,就不得不自己编写 Alpine 版本,或者找一些第三方镜像。

3、用什么替代

如果上述问题促使你重新考虑使用 Alpine,那么你可能想知道应该使用什么替代。有很多选择,它们都有一些利弊需要权衡。

Alpine 最大的吸引力在于它的体积小,所以如果你真的在乎这一点,那么 Wolfi(例如,cgrd .dev/chainguard/Wolfi -base只有 12MB)或 Distroless 都是不错的选择。

如果你正在寻找具有合理大小的通用基础镜像,而不是基于 musl,那么你可以考虑使用 Red Hat 公司的 UBI(通用基础镜像),它的“微型”版本(registry.access.redhat.com/ubi8-micro)只有 26.7MB,这也非常接近 Alpine。

选择 Alpine 的另一个原因是它的安全性。这也与它的小尺寸有关,因为小尺寸通常意味着更少的包,因此漏洞也更少。在这方面,上述的 Wolfi 是一个特别好的选择。

让我们实事求是地说,由于 Alpine 很小而节省几兆字节的空间并不重要,除非你要拉成千上万次镜像(你可能不应该这样做),所以使用 Ubuntu 或基于 Debian 的基本镜像也不是一个糟糕的选择。

可能有人知道,Docker 官方的 Debian 镜像有个 slim 版本,这个版本的大小比默认的版本要小一倍多。

slim 顾名思义就是“瘦身版”。Debian-slim 是一个很好的折中方案,它比 Alpine 大,但也没那么大。

有一些上层的镜像会基于 Debian-slim 进行编写,比如 Python。如果我们开发 Python 的项目,可以使用 python:slim 这个基础镜像。

另外,在 Docker 17.05 版本以后,新引入了多阶段编译(multi-stage builds) 这一概念,这将会极大地简化所有操作。

简单来说,多阶段编译支持我们将 Docker 镜像的编译分成多个“阶段”。比如常见的软件编译的情况,我们可以将编译阶段单独提出来,软件编译完成后直接将二进制文件拷贝到一个新的基础镜像中,这样做最大的好处就是,第二个镜像不再包含任何编译阶段使用的中间依赖,干干净净明明白白。

虽然使用 Alpine 没有什么问题,而且它可以作为基本容器镜像操作系统,但就我个人而言,由于前面描述的 DNS 问题,我可能永远不会再信任它,或者任何使用 musl 的操作系统。

本文的重点不是要诋毁 Alpine。相反,这是一种预警。虽然考虑到上面列出的问题,Alpine 似乎是一个不错的选择,但使用它至少是有风险的,你的决定可能是鲁莽的。不过这最终取决于你计划在哪里使用它。它满足了很多要求,也有很多优点,所以如果你不担心或不受本文所描述的问题的影响,你可能应该继续使用它。

综上所述,这里的结论应该是——在使用任何东西(无论是容器操作系统、框架还是库)之前进行合理的研究——它很受欢迎并受到好评并不一定意味着它就一定是一个好的选择。

参考链接:

https://betterprogramming.pub/why-i-will-never-use-alpine-linux-ever-again-a324fd0cbfd6

https://www.ewbang.com/community/article/details/960423446.html

342058e9175585c1e9e286d274b98362e5157c.png
责任编辑:武晓燕 来源: 51CTO技术栈

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK