如何構建更小的容器
使用容器工作是很多用戶和開發者的日常任務。容器開發者經常需要頻繁地(重新)構建容器鏡像。如果你開發容器,你有想過減小鏡像的大小嗎?較小的鏡像有一些好處。在下載的時候所需要的帶寬更少,而且在雲環境中運行的時候也可以節省開銷。而且在 Fedora CoreOS、IoT 以及Silverblue 上使用較小的容器鏡像可以提升整體系統性能,因為這些操作系統嚴重依賴於容器工作流。這篇文章將會提供一些減小容器鏡像大小的技巧。
工具
以下例子所用到的主機操作系統是 Fedora Linux 33。例子使用 Podman 3.1.0 和Buildah 1.2.0。Podman 和 Buildah 已經預裝在大多數 Fedora Linux 變種中。如果你沒有安裝 Podman 和 Buildah,可以用下邊的命令安裝:
$ sudo dnf install -y podman buildah
任務
從一個基礎的例子開始。構建一個滿足以下需求的 web 容器:
- 容器必須基於 Fedora Linux
- 使用 Apache httpd web 伺服器
- 包含一個定製的網站
- 容器應該比較小
下邊的步驟也適用於比較複雜的鏡像。
設置
首先,創建一個工程目錄。這個目錄將會包含你的網站和容器文件:
$ mkdir smallerContainer
$ cd smallerContainer
$ mkdir files
$ touch files/index.html
製作一個簡單的登錄頁面。對於這個演示,你可以將下面的 HTML 複製到 index.html
文件中。
<!doctype html>
<html lang="de">
<head>
<title>Container Page</title>
</head>
<body>
<header>
<h1>Container Page</h1>
</header>
<main>
<h2>Fedora</h2>
<ul>
<li><a href="https://getfedora.org">Fedora Project</a></li>
<li><a href="https://docs.fedoraproject.org/">Fedora Documentation</a></li>
<li><a href="https://fedoramagazine.org">Fedora Magazine</a></li>
<li><a href="https://communityblog.fedoraproject.org/">Fedora Community Blog</a></li>
</ul>
<h2>Podman</h2>
<ul>
<li><a href="https://podman.io">Podman</a></li>
<li><a href="https://docs.podman.io/">Podman Documentation</a></li>
<li><a href="https://github.com/containers/podman">Podman Code</a></li>
<li><a href="https://podman.io/blogs/">Podman Blog</a></li>
</ul>
<h2>Buildah</h2>
<ul>
<li><a href="https://buildah.io">Buildah</a></li>
<li><a href="https://github.com/containers/buildah">Buildah Code</a></li>
<li><a href="https://buildah.io/blogs/">Buildah Blog</a></li>
</ul>
<h2>Skopeo</h2>
<ul>
<li><a href="https://github.com/containers/skopeo">skopeo Code</a></li>
</ul>
<h2>CRI-O</h2>
<ul>
<li><a href="https://cri-o.io/">CRI-O</a></li>
<li><a href="https://github.com/cri-o/cri-o">CRI-O Code</a></li>
<li><a href="https://medium.com/cri-o">CRI-O Blog</a></li>
</ul>
</main>
</body>
</html>
此時你可以選擇在瀏覽器中測試上面的 index.html
文件:
$ firefox files/index.html
最後,創建一個容器文件。這個文件可以命名為 Dockerfile
或者 Containerfile
:
$ touch Containerfile
現在你應該有了一個工程目錄,並且該目錄中的文件系統布局如下:
smallerContainer/
|- files/
| |- index.html
|
|- Containerfile
構建
現在構建鏡像。下邊的每個階段都會添加一層改進來幫助減小鏡像的大小。你最終會得到一系列鏡像,但只有一個 Containerfile
。
階段 0:一個基本的容器鏡像
你的新鏡像將會非常簡單,它只包含強制性步驟。在 Containerfile
中添加以下內容:
# 使用 Fedora 33 作為基鏡像
FROM registry.fedoraproject.org/fedora:33
# 安裝 httpd
RUN dnf install -y httpd
# 複製這個網站
COPY files/* /var/www/html/
# 設置埠為 80/tcp
EXPOSE 80
# 啟動 httpd
CMD ["httpd", "-DFOREGROUND"]
在上邊的文件中有一些注釋來解釋每一行內容都是在做什麼。更詳細的步驟:
- 在
FROM registry.fedoraproject.org/fedora:33
的基礎上創建一個構建容器 - 運行命令:
dnf install -y httpd
- 將與
Containerfile
有關的文件拷貝到容器中 - 設置
EXPOSE 80
來說明哪個埠是可以自動設置的 - 設置一個
CMD
指令來說明如果從這個鏡像創建一個容器應該運行什麼
運行下邊的命令從工程目錄創建一個新的鏡像:
$ podman image build -f Containerfile -t localhost/web-base
使用一下命令來查看你的鏡像的屬性。注意你的鏡像的大小(467 MB)。
$ podman image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
localhost/web-base latest ac8c5ed73bb5 5 minutes ago 467 MB
registry.fedoraproject.org/fedora 33 9f2a56037643 3 months ago 182 MB
以上這個例子中展示的鏡像在現在佔用了467 MB的空間。剩下的階段將會顯著地減小鏡像的大小。但是首先要驗證鏡像是否能夠按照預期工作。
輸入以下命令來啟動容器:
$ podman container run -d --name web-base -P localhost/web-base
輸入以下命令可以列出你的容器:
$ podman container ls
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
d24063487f9f localhost/web-base httpd -DFOREGROUN... 2 seconds ago Up 3 seconds ago 0.0.0.0:46191->80/tcp web-base
以上展示的容器正在運行,它正在監聽的埠是 46191
。從運行在主機操作系統上的 web 瀏覽器轉到 localhost:46191
應該呈現你的 web 頁面:
$ firefox localhost:46191
階段 1:清除緩存並將殘餘的內容從容器中刪除
為了優化容器鏡像的大小,第一步應該總是執行「清理」。這將保證安裝和打包所殘餘的內容都被刪掉。這個過程到底需要什麼取決於你的容器。對於以上的例子,只需要編輯 Containerfile
讓它包含以下幾行。
[...]
# Install httpd
RUN dnf install -y httpd &&
dnf clean all -y
[...]
構建修改後的 Containerfile
來顯著地減小鏡像(這個例子中是 237 MB)。
$ podman image build -f Containerfile -t localhost/web-clean
$ podman image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
localhost/web-clean latest f0f62aece028 6 seconds ago 237 MB
階段 2:刪除文檔和不需要的依賴包
許多包在安裝時會被建議拉下來,包含一些弱依賴和文檔。這些在容器中通常是不需要的,可以刪除。 dnf
命令有選項可以表明它不需要包含弱依賴或文檔。
再次編輯 Containerfile
,並在 dnf install
行中添加刪除文檔和弱依賴的選項:
[...]
# Install httpd
RUN dnf install -y httpd --nodocs --setopt install_weak_deps=False &&
dnf clean all -y
[...]
構建經過以上修改後的 Containerfile
可以得到一個更小的鏡像(231 MB)。
$ podman image build -f Containerfile -t localhost/web-docs
$ podman image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
localhost/web-docs latest 8a76820cec2f 8 seconds ago 231 MB
階段 3:使用更小的容器基鏡像
前面的階段結合起來,使得示例鏡像的大小減少了一半。但是仍然還有一些途徑來進一步減小鏡像的大小。這個基鏡像 registry.fedoraproject.org/fedora:33
是通用的。它提供了一組軟體包,許多人希望這些軟體包預先安裝在他們的 Fedora Linux 容器中。但是,通用的 Fedora Linux 基鏡像中提供的包通常必須要的更多。Fedora 項目也為那些希望只從基本包開始,然後只添加所需內容來實現較小總鏡像大小的用戶提供了一個 fedora-minimal
鏡像。
使用 podman image search
來查找 fedora-minimal
鏡像,如下所示:
$ podman image search fedora-minimal
INDEX NAME DESCRIPTION STARS OFFICIAL AUTOMATED
fedoraproject.org registry.fedoraproject.org/fedora-minimal 0
fedora-minimal
基鏡像不包含 DNF,而是傾向於使用不需要 Python 的較小的 microDNF。當 registry.fedoraproject.org/fedora:33
被 registry.fedoraproject.org/fedora-minimal:33
替換後,需要用 microdnf
命令來替換 dnf
。
# 使用 Fedora minimal 33 作為基鏡像
FROM registry.fedoraproject.org/fedora-minimal:33
# 安裝 httpd
RUN microdnf install -y httpd --nodocs --setopt install_weak_deps=0 &&
microdnf clean all -y
[...]
使用 fedora-minimal
重新構建後的鏡像大小如下所示 (169 MB):
$ podman image build -f Containerfile -t localhost/web-docs
$ podman image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
localhost/web-minimal latest e1603bbb1097 7 minutes ago 169 MB
最開始的鏡像大小是 467 MB。結合以上每個階段所提到的方法,進行重新構建之後可以得到最終大小為 169 MB 的鏡像。最終的 總 鏡像大小比最開始的 基 鏡像小了 182 MB!
從零開始構建容器
前邊的內容使用一個容器文件和 Podman 來構建一個新的鏡像。還有最後一個方法要展示——使用 Buildah 來從頭構建一個容器。Podman 使用與 Buildah 相同的庫來構建容器。但是 Buildah 被認為是一個純構建工具。Podman 被設計來是為了代替 Docker 的。
使用 Buildah 從頭構建的容器是空的——它裡邊什麼都 沒有 。所有的東西都需要安裝或者從容器外複製。幸運地是,使用 Buildah 相當簡單。下邊是一個從頭開始構建鏡像的小的 Bash 腳本。除了運行這個腳本,你也可以在終端逐條地運行腳本中的命令,來更好的理解每一步都是做什麼的。
#!/usr/bin/env bash
set -o errexit
# 創建一個容器
CONTAINER=$(buildah from scratch)
# 掛載容器文件系統
MOUNTPOINT=$(buildah mount $CONTAINER)
# 安裝一個基本的文件系統和最小的包以及 nginx
dnf install -y --installroot $MOUNTPOINT --releasever 33 glibc-minimal-langpack httpd --nodocs --setopt install_weak_deps=False
dnf clean all -y --installroot $MOUNTPOINT --releasever 33
# 清除
buildah unmount $CONTAINER
# 複製網站
buildah copy $CONTAINER 'files/*' '/var/www/html/'
# 設置埠為 80/tcp
buildah config --port 80 $CONTAINER
# 啟動 httpd
buildah config --cmd "httpd -DFOREGROUND" $CONTAINER
# 將容器保存為一個鏡像
buildah commit --squash $CONTAINER web-scratch
或者,可以通過將上面的腳本傳遞給 Buildah 來構建鏡像。注意不需要 root 許可權。
$ buildah unshare bash web-scratch.sh
$ podman image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
localhost/web-scratch latest acca45fc9118 9 seconds ago 155 MB
最後的鏡像只有 155 MB!而且 攻擊面 也減少了。甚至在最後的鏡像中都沒有安裝 DNF(或者 microDNF)。
結論
構建一個比較小的容器鏡像有許多優點。減少所需要的帶寬、磁碟佔用以及攻擊面,都會得到更好的鏡像。只用很少的更改來減小鏡像的大小很簡單。許多更改都可以在不改變結果鏡像的功能下完成。
只保存所需的二進位文件和配置文件來構建非常小的鏡像也是可能的。
via: https://fedoramagazine.org/build-smaller-containers/
作者:Daniel Schier 選題:lujun9972 譯者:ShuyRoy 校對:wxy
本文轉載來自 Linux 中國: https://github.com/Linux-CN/archive