Alpine?Distroless?Busybox?到底誰才是容器鏡像的瑞士軍刀?
大多數(shù)情況下,我們構(gòu)建容器鏡像時選擇的基礎(chǔ)鏡像無外乎是 busybox、alpine 和 google/distroless 這幾種,這幾個基礎(chǔ)鏡像在云原生的世界很吃香,被廣泛應(yīng)用于各個應(yīng)用的容器化。
那么問題來了,為什么這幾個基礎(chǔ)鏡像如此受歡迎呢?
我們先來看下這幾個基礎(chǔ)鏡像的大?。?/p>
- 🐳 → podman image ls
- REPOSITORY TAG IMAGE ID CREATED SIZE
- docker.io/library/alpine latest 14119a10abf4 6 days ago 5.87 MB
- docker.io/library/busybox latest 42b97d3c2ae9 13 days ago 1.46 MB
- gcr.io/distroless/static latest e0851a4aa136 51 years ago 3.06 MB
可以看到這些鏡像的體積都非常小,幾乎可以忽略不計。
Busybox
先啟動一個 Busybox 容器進去一探究竟:
這個鏡像的大小只有 1.24MB,缺容納了這么多 GNU 命令,麻雀雖小五臟俱全啊,這到底是怎么做到的?
事實上這一切都要歸功于 Multi-Call binary。什么是 Multi-Call binary 呢?
顧名思義,Multi-Call binary 就是多重調(diào)用二進制文件,是一個用C語言編寫的程序,它允許多次調(diào)用來執(zhí)行二進制文件。它包含了很多函數(shù),每個執(zhí)行獨特動作的函數(shù)都可以通過一個名字來調(diào)用,這個名字同時也是 Multi-Call binary 的一個符號鏈接。Multi-Call binary 最好的應(yīng)用范例便是 Busybox。
Busybox 里面的函數(shù)可以通過兩種方式來調(diào)用:
- busybox ls
- ls
例如:
Busybox 容器
很明顯,這些不是我們所熟知的 GNU 二進制文件,因為所有的二進制文件都具有相同的屬性,比如大小、日期等。這些都不是獨立的二進制文件,而是 Multi-Call binary 每個調(diào)用函數(shù)的別名。這個 Multi-Call binary 就叫 Busybox。
遺憾的是,這些 Busybox 命令并不完全等同于 GNU 命令,某些命令的某些參數(shù)是無法執(zhí)行的,相當于閹割版。
Alpine
看完了 Busybox,我們再來看看 Alpine 是怎么做的。
巧了,Alpine 的二進制文件竟然是指向 busybox 二進制文件的,這就很明顯了,Alpine 鏡像的底層使用了 busybox 二進制文件。除此之外,Alpine 還包含了 apk 包管理器和一些額外的可執(zhí)行文件,所以 Alpine 鏡像的體積才會比 Busybox 大。
Distroless
Distroless 就不用說了,它來自 Google[1]。該鏡像幾乎就是空的,只包含應(yīng)用程序及其運行時所需的依賴,不包含軟件包管理器、shell 和其他 GNU 二進制文件,當然還包含一些時區(qū)配置和部分 ca-certificates。
可以看到這個鏡像中既沒有 shell 也沒有 bash,為了一探究竟,可以先把鏡像保存為 tar 包,然后把 rootfs 解壓出來:
- 🐳 → mkdir image
- 🐳 → tar xvf distroless.tar.gz -C image/
- 16679402dc206c982b5552ab8de7d898547100e5468be29d4f67d393c0eadfdb.tar
- e0851a4aa13657fc8dcd01e0e5e08cb817123ccb82e2c604b34f9ec9c1755e3f.json
- 2e18de03719583329b7fa8374130e57cc7cddf2b5a487fe4a4988622ca60575c/layer.tar
- 2e18de03719583329b7fa8374130e57cc7cddf2b5a487fe4a4988622ca60575c/VERSION
- 2e18de03719583329b7fa8374130e57cc7cddf2b5a487fe4a4988622ca60575c/json
- manifest.json
- repositories
- 🐳 → cd image
- 🐳 → ls -lh
- total 3.0M
- -r--r--r--. 1 root root 3.0M Jan 1 1970 16679402dc206c982b5552ab8de7d898547100e5468be29d4f67d393c0eadfdb.tar
- drwxr-xr-x. 2 root root 50 Sep 3 17:42 2e18de03719583329b7fa8374130e57cc7cddf2b5a487fe4a4988622ca60575c
- -r--r--r--. 1 root root 462 Jan 1 1970 e0851a4aa13657fc8dcd01e0e5e08cb817123ccb82e2c604b34f9ec9c1755e3f.json
- -r--r--r--. 1 root root 213 Jan 1 1970 manifest.json
- -r--r--r--. 1 root root 106 Jan 1 1970 repositories
- 🐳 → mkdir rootfs
- 🐳 → tar xf 16679402dc206c982b5552ab8de7d898547100e5468be29d4f67d393c0eadfdb.tar -C rootfs
- 🐳 → tree rootfs
- rootfs
- ├── bin
- ├── boot
- ├── dev
- ├── etc
- │ ├── debian_version
- │ ├── default
- │ ├── dpkg
- │ │ └── origins
- │ │ └── debian
- │ ├── group
- │ ├── host.conf
- │ ├── issue
- │ ├── issue.net
- │ ├── nsswitch.conf
- │ ├── os-release
- │ ├── passwd
- │ ├── profile.d
- │ ├── protocols
- │ ├── rpc
- │ ├── services
- │ ├── skel
- │ ├── ssl
- │ │ └── certs
- │ │ └── ca-certificates.crt
- │ └── update-motd.d
- │ └── 10-uname
- ├── home
- │ └── nonroot
- ├── lib
- ├── proc
- ├── root
- ├── run
- ├── sbin
- ├── sys
- ├── tmp
- ├── usr
- │ ├── bin
- │ ├── games
- │ ├── include
- │ ├── lib
- │ │ └── os-release
- │ ├── sbin
- │ │ └── tzconfig
- │ ├── share
- │ │ ├── base-files
- │ │ │ ├── dot.bashrc
- │ │ │ ├── dot.profile
- │ │ │ ├── dot.profile.md5sums
- │ │ │ ├── info.dir
- │ │ │ ├── motd
- │ │ │ ├── profile
- │ │ │ ├── profile.md5sums
- │ │ │ └── staff-group-for-usr-local
- ...
- ...
該鏡像只有一層,大小為 3MB,也沒有二進制文件,只有一些證書文件和目錄。如果向下滾動,還能看到許可證和時區(qū)配置。看來 Distroless 采取的是非常極端的手段,直接把不需要的二進制文件全部拋棄了,只留下一個空鏡像和部分必需品。
總結(jié)
由此看來,這幾個基礎(chǔ)鏡像如此受歡迎的主要原因就是體積小。鏡像越小,漏洞就越少,可攻擊面也會大幅減少,而且很容易維護。所以大家構(gòu)建鏡像時盡量選擇這些鏡像作為基礎(chǔ)鏡像。
引用鏈接
[1]Google: https://github.com/GoogleContainerTools/distroless