Linux中國

如何構建更小的容器

使用容器工作是很多用戶和開發者的日常任務。容器開發者經常需要頻繁地(重新)構建容器鏡像。如果你開發容器,你有想過減小鏡像的大小嗎?較小的鏡像有一些好處。在下載的時候所需要的帶寬更少,而且在雲環境中運行的時候也可以節省開銷。而且在 Fedora CoreOSIoT 以及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"]

在上邊的文件中有一些注釋來解釋每一行內容都是在做什麼。更詳細的步驟:

  1. FROM registry.fedoraproject.org/fedora:33 的基礎上創建一個構建容器
  2. 運行命令: dnf install -y httpd
  3. 將與 Containerfile 有關的文件拷貝到容器中
  4. 設置 EXPOSE 80 來說明哪個埠是可以自動設置的
  5. 設置一個 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:33registry.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 &apos;files/*&apos; &apos;/var/www/html/&apos;

# 設置埠為 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

本文由 LCTT 原創編譯,Linux中國 榮譽推出


本文轉載來自 Linux 中國: https://github.com/Linux-CN/archive

對這篇文章感覺如何?

太棒了
0
不錯
0
愛死了
0
不太好
0
感覺很糟
0
雨落清風。心向陽

    You may also like

    Leave a reply

    您的郵箱地址不會被公開。 必填項已用 * 標註

    此站點使用Akismet來減少垃圾評論。了解我們如何處理您的評論數據

    More in:Linux中國