爲什麼我不再使用 Alpine Linux?

現在,Alpine Linux 已經成爲最受歡迎的容器基礎鏡像之一。許多人(你可能也是其中之一)用它幹很多事情。有些人選擇 Alpine 是因爲它體積小,有些人是因爲習慣,還有些人可能只是從某個教程中複製粘貼了 Dockerfile。但是,也有很多人告訴你,在某些情況下不應該使用 Alpine 作爲容器鏡像,因爲這可能會給你帶來麻煩。

01 麻煩的根源

要了解 Alpine 在某些情況下爲什麼不是一個好選擇,我們首先需要談論一下 musl。musl 是 C 標準庫的一種實現。相對於其他 Linux 發行版(如 Ubuntu)所使用的 glibc,musl 更輕量、更快、更簡單。大部分情況下,這兩種實現可以互換,這就是爲什麼你可以從 Ubuntu 切換到 Alpine 而幾乎察覺不到任何差異。

然而,正是這些微小的差異可能帶來一系列麻煩。其中一些問題源於 musl(因此也包括 Alpine)如何處理 DNS(怎麼總是 DNS?)。更具體地說,musl(出於設計考慮)不支持 DNS-over-TCP

通常情況下,你可能不會注意到這種差異,因爲大多數情況下,一個單獨的 UDP 數據包(512 字節)足以解析主機名…… 直到有一天,當某些外部網絡變化導致解析某個特定域名需要超過單個 UDP 數據包可容納的 512 字節時,你的應用程序(在 Kubernetes 上運行)突然對一個非常關鍵的主機名拋出 “Unknown Host” 異常。最糟糕的是,這個問題可能隨機出現,只要某些外部網絡變化導致解析某個特定域名需要更多字節,就可能會發生這種情況。

通過使用 Alpine,你實際上爲你的集羣獲得了一種 “免費” 的混沌工程。

如果你運行幾十甚至數百個基於 Alpine 的微服務 / 應用程序,它們突然停止工作,唯一的解決方法是切換到另一個 Linux 發行版,這將需要重新構建所有應用程序並重新部署,那麼你可能面臨着一個極具破壞性的、持續好幾天的停機時間。

這個 DNS 問題不會在 Docker 容器中暴露出來。它只會在 Kubernetes 中發生,所以如果你在本地進行測試,一切工作都正常,只有在將應用程序部署到集羣中時纔會發現無法解決的問題。此外,Kubernetes 文檔聲稱 DNS 問題只與 “Alpine 3.3 或更早版本”,但我在 Alpine 3.16 上也遇到了上述問題,所以你可以自行判斷。

作爲額外福利,許多流行的工具也使用 Alpine 作爲基礎鏡像,例如 nicolaka/netshoot 或 giantswarm/tiny-tools,前者專門用於網絡故障排除。當你的網絡故障排除工具本身也出現問題時,那隻能祝你好運了。

02 其他問題

雖然 DNS 問題是 musl 的最常見問題,但還有更多原因要重新考慮使用它。任何依賴於 C 標準庫的編程語言或其庫都會受到 musl 和 glibc 之間差異的影響。

例如,對於 Python 來說,許多流行的庫如 NumPy 或 Cryptography 依賴於 C 代碼進行優化。幸運的是,至少對於像 NumPy 這樣的一些庫,你很有可能找到基於 Alpine 編譯的軟件包和相關依賴項。

然而,對於不太流行的庫,你可能需要自己進行編譯,但是這樣做值得嗎?在我看來…… 不值得。此外,即使你成功構建了一個包含 NumPy 等庫的鏡像,其大小也將達到約 400MB,這時候使用 Alpine 來節省空間並沒有太多幫助。

此外,構建這樣一個鏡像的時間將會非常長。你可以自己嘗試一下;下面的 Dockerfile 構建過程幾乎需要十分鐘:

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

當然,其他編程語言也可能遇到類似問題。例如,Node.js 使用插件(add-ons),這些插件是用 C++ 編寫並使用 node-gyp 進行編譯的,它們依賴於 C 庫,因此也依賴於 glibc。

另一個例子是 Golang,其標準庫(特別是 net/http 或 os/user 模塊)依賴於 C 庫,因此也依賴於 glibc。即使你不使用這些特定模塊,如果你的應用程序需要設置 CGO_ENABLED=1,那麼在 Alpine 上也可能會遇到問題。

03 代替方案

如果上述問題促使你重新考慮使用 Alpine,你可能會想知道有什麼可以使用的代替方案。其實選擇有很多,而且它們各有優缺點,使用的時候需要你來權衡。

Alpine 最大的吸引力在於其小巧的體積,所以如果你非常關注這一點,那麼 Wolfi(例如,cgr.dev/chainguard/wolfi-base 只有 12MB)或 Distroless 是不錯的選擇。

如果你需要一個大小合適且不基於 musl 的通用基礎鏡像,那麼可以考慮使用 Red Hat 提供的 UBI(Universal Base Image),其 “micro” 版本只有 26.7MB(registry.access.redhat.com/ubi8-micro),這與 Alpine 相差無幾。

選擇 Alpine 的另一個原因是其安全性。這也與其小巧的體積有關,因爲小巧的體積通常意味着較少的軟件包,從而減少了潛在的漏洞。前面提到的 Wolfi 鏡像在這方面特別出色。

但是實事求是地說,除非你需要頻繁拉取鏡像(你可能本應該避免這樣做),否則通過 Alpine 的小巧體積節省幾兆字節的空間可能並不重要,因此基於 Ubuntu 或 Debian 的基礎鏡像也是不錯的選擇

04 結論

總之,雖然使用 Alpine 沒有問題,並且作爲基礎容器鏡像操作系統是很好的選擇,但就我個人而言,因爲前面描述的 DNS 問題,我可能再也不會完全信任它,也不會信任使用 musl 的其他系統。

本文的目的不是詆譭 Alpine,而是提醒人們。 儘管 Alpine 可能看起來是一個不錯的選擇(考慮到上述問題),但至少是有一定風險的,在某些特定情況下決定使用 Alpine 可能是很魯莽的。當然,Alpine 也有許多優點,所以如果你不擔心或不受本文描述的問題影響,那麼繼續使用它也是可以的。

因此,我們應該得出結論:在決定使用任何東西(無論是容器操作系統、框架還是庫)之前,要進行合理的研究。一個系統受歡迎並且聲譽良好並不意味着它會自動成爲一個好的選擇。

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/BKRkbLQurJrd1F0JjMeEkw