在容器內運行 Buildah 的建議

將容器運行時解耦為單獨的工具元件有什麼好處? 特別是,這些工具可以開始組合起來,以便它們可以相互保護。

在容器內運行 Buildah 的建議

許多人被在其中建造容器化 OCI 鏡像的想法所吸引 Kubernetes 或類似的系統。 假設我們有一個持續收集影像的 CI/CD,那麼類似 紅帽OpenShift/Kubernetes 在建置期間的負載平衡方面非常有用。 直到最近,大多數人只是簡單地授予容器存取 Docker 套接字的權限,並允許它們執行 docker build 命令。 幾年前我們展示了這是非常不安全的,事實上,它比給予無密碼 root 或 sudo 更糟糕。

這就是為什麼人們不斷嘗試在容器中運行 Buildah。 簡而言之,我們創建了 例子 我們認為,最好如何在容器內運行 Buildah,並將相應的映像發佈到 quay.io/buildah。 讓我們開始吧...

調整

這些映像是從 Dockerfiles 建置的,可以在 Buildah 儲存庫的資料夾中找到 建構影像.
在這裡我們將看看 Dockerfile 的穩定版本.

# stable/Dockerfile
#
# Build a Buildah container image from the latest
# stable version of Buildah on the Fedoras Updates System.
# https://bodhi.fedoraproject.org/updates/?search=buildah
# This image can be used to create a secured container
# that runs safely with privileges within the container.
#
FROM fedora:latest

# Don't include container-selinux and remove
# directories used by dnf that are just taking
# up space.
RUN yum -y install buildah fuse-overlayfs --exclude container-selinux; rm -rf /var/cache /var/log/dnf* /var/log/yum.*

# Adjust storage.conf to enable Fuse storage.
RUN sed -i -e 's|^#mount_program|mount_program|g' -e '/additionalimage.*/a "/var/lib/shared",' /etc/containers/storage.conf

我們使用容器內的程序,而不是在主機 Linux 核心層級實現的 OverlayFS 保險絲覆蓋層,因為目前 OverlayFS 只能在您使用 Linux 功能為其授予 SYS_ADMIN 權限時才能掛載。 我們希望在沒有任何 root 權限的情況下執行 Buildah 容器。 Fuse-overlay 工作速度相當快,並且比 VFS 儲存驅動程式具有更好的效能。 請注意,執行使用 Fuse 的 Buildah 容器時,您必須提供 /dev/fuse 裝置。

podman run --device /dev/fuse quay.io/buildahctr ...
RUN mkdir -p /var/lib/shared/overlay-images /var/lib/shared/overlay-layers; touch /var/lib/shared/overlay-images/images.lock; touch /var/lib/shared/overlay-layers/layers.lock

接下來我們建立一個目錄用於額外儲存。 容器/儲存 支援連接附加唯讀影像儲存的概念。 例如,您可以在一台機器上配置覆蓋儲存區域,然後使用 NFS 將該儲存掛載到另一台機器上並使用其中的鏡像,而無需透過拉取下載。 我們需要此存儲,以便能夠從主機連接一些圖像存儲作為卷並在容器內使用它。

# Set up environment variables to note that this is
# not starting with user namespace and default to
# isolate the filesystem with chroot.
ENV _BUILDAH_STARTED_IN_USERNS="" BUILDAH_ISOLATION=chroot

最後,透過使用 BUILDAH_ISOLATION 環境變量,我們告訴 Buildah 容器預設以 chroot 隔離運行。 這裡不需要額外的隔熱層,因為我們已經在容器中工作了。 為了讓 Buildah 建立自己的命名空間分隔的容器,需要 SYS_ADMIN 權限,這需要放寬容器的 SELinux 和 SECCOMP 規則,這與我們從安全容器建立的偏好相反。

在容器內運行 Buildah

上面討論的 Buildah 容器鏡像圖可讓您靈活地改變啟動此類容器的方法。

速度與安全

電腦安全始終是製程速度和周圍保護程度之間的折衷。 在組裝容器時,這種說法也是正確的,所以下面我們將考慮這個折衷的選擇。

上面討論的容器映像將其儲存在 /var/lib/containers 中。 因此,我們需要將內容掛載到這個資料夾中,而如何掛載將極大地影響建構容器鏡像的速度。

讓我們考慮三個選項。

選項1。 如果需要最大程度的安全性,那麼對於每個容器,您可以為容器/映像建立自己的資料夾,並透過磁碟區掛載將其連接到容器。 此外,將上下文目錄放置在容器本身的 /build 資料夾中:

# mkdir /var/lib/containers1
# podman run -v ./build:/build:z -v /var/lib/containers1:/var/lib/containers:Z quay.io/buildah/stable
buildah  -t image1 bud /build
# podman run -v /var/lib/containers1:/var/lib/containers:Z quay.io/buildah/stable buildah  push  image1 registry.company.com/myuser
# rm -rf /var/lib/containers1

安全。 在這樣的容器中運行的Buildah 具有最大的安全性:它不會被授予使用功能的任何root 權限,並且所有SECOMP 和SELinux 限制都適用於它。這樣的容器甚至可以透過新增像—uidmap 0 這樣的選項來使用使用者命名空間隔離來運行: 100000:10000。

性能。 但這裡的效能是最低的,因為每次來自容器註冊表的任何映像都會複製到主機,並且快取根本不起作用。 完成工作後,Buildah 容器必須將映像傳送到註冊表並銷毀主機上的內容。 下次建立容器映像時,必須再次從註冊表下載它,因為到那時主機上將不再有任何內容。

選項2。 如果需要Docker等級的效能,可以將主機容器/儲存直接掛載到容器中。

# podman run -v ./build:/build:z -v /var/lib/containers:/var/lib/containers --security-opt label:disabled quay.io/buildah/stable buildah  -t image2 bud /build
# podman run -v /var/lib/containers:/var/lib/containers --security-opt label:disabled  quay.io/buildah/stable buildah push image2 registry.company.com/myuser

安全。 這是建構容器的最不安全的方法,因為它允許容器修改主機存儲,並可能向 Podman 或 CRI-O 提供惡意鏡像。 此外,您需要停用 SELinux 分離,以便 Buildah 容器中的進程可以與主機上的儲存空間進行互動。 請注意,此選項仍然比 Docker 套接字更好,因為容器被剩餘的安全功能鎖定,並且不能簡單地在主機上執行容器。

性能。 這裡它是最大值,因為快取已被充分使用。 如果 Podman 或 CRI-O 已經將所需的鏡像下載到主機上,那麼容器內的 Buildah 進程就不必再次下載,並且後續基於該鏡像的構建也可以從快取中獲取所需的內容。

選項3。 這種方法的本質是將多個鏡像合併到一個專案中,並使用一個容器鏡像的公共資料夾。

# mkdir /var/lib/project3
# podman run --security-opt label_level=s0:C100, C200 -v ./build:/build:z 
-v /var/lib/project3:/var/lib/containers:Z quay.io/buildah/stable buildah  -t image3 bud /build
# podman run --security-opt label_level=s0:C100, C200 
-v /var/lib/project3:/var/lib/containers quay.io/buildah/stable buildah push image3  registry.company.com/myuser

在此範例中,我們不會在運行之間刪除專案資料夾 (/var/lib/project3),因此專案內的所有後續建置都會受益於快取。

安全。 介於選項 1 和 2 之間。一方面,容器無權存取主機上的內容,因此無法將不良內容放入 Podman/CRI-O 鏡像儲存中。 另一方面,作為其設計的一部分,容器可能會幹擾其他容器的組裝。

性能。 這裡比在主機層級使用共享快取更糟糕,因為您無法使用已使用 Podman/CRI-O 下載的映像。 但是,一旦 Buildah 下載了映像,該映像就可以在專案內的任何後續建置中使用。

額外儲存空間

У 容器/存儲 有一個很酷的東西,叫做附加儲存(additional store),透過它,在啟動和建置容器時,容器引擎可以以唯讀覆蓋模式使用外部鏡像儲存。 本質上,您可以將一個或多個唯讀儲存體新增至 storage.conf 檔案中,以便在啟動容器時,容器引擎會在其中尋找所需的鏡像。 此外,只有在任何這些儲存體中找不到該映像時,它才會從註冊表下載該映像。 容器引擎只能寫入可寫入儲存......

如果您向上捲動並查看我們用於建立映像 quay.io/buildah/stable 的 Dockerfile,會發現如下幾行:

# Adjust storage.conf to enable Fuse storage.
RUN sed -i -e 's|^#mount_program|mount_program|g' -e '/additionalimage.*/a "/var/lib/shared",' /etc/containers/storage.conf
RUN mkdir -p /var/lib/shared/overlay-images /var/lib/shared/overlay-layers; touch /var/lib/shared/overlay-images/images.lock; touch /var/lib/shared/overlay-layers/layers.lock

在第一行中,我們修改容器映像內的 /etc/containers/storage.conf ,告訴儲存驅動程式使用 /var/lib/shared 資料夾中的「additionalimagestores」。 在下一行中,我們建立一個共用資料夾並新增幾個鎖定文件,以便容器/儲存不會被濫用。 本質上,我們只是創建一個空的容器鏡像儲存。

如果您將容器/儲存掛載到高於此資料夾的級別,Buildah 將能夠使用這些映像。

現在讓我們回到上面討論的選項2,當Buildah 容器可以讀取和寫入主機上的容器/存儲時,由於在Podman/CRI-O 級別緩存圖像,因此具有最大性能,但提供最低限度的安全性因為它可以直接寫入儲存。 現在,讓我們在這裡添加額外的儲存空間,並獲得兩全其美的效果。

# mkdir /var/lib/containers4
# podman run -v ./build:/build:z -v /var/lib/containers/storage:/var/lib/shared:ro -v  /var/lib/containers4:/var/lib/containers:Z  quay.io/buildah/stable 
 buildah  -t image4 bud /build
# podman run -v /var/lib/containers/storage:/var/lib/shared:ro  
-v >/var/lib/containers4:/var/lib/containers:Z quay.io/buildah/stable buildah push image4  registry.company.com/myuser
# rm -rf /var/lib/continers4

請注意,主機的 /var/lib/containers/storage 以唯讀模式掛載到容器內的 /var/lib/shared 。 因此,在容器中工作時,Buildah 可以使用先前使用 Podman/CRI-O 下載的任何鏡像(hello、speed),但只能寫入自己的儲存空間(hello、security)。 另請注意,這是在不停用容器 SELinux 分離的情況下完成的。

重要的細微差別

在任何情況下都不應從底層儲存庫中刪除任何影像。 否則,Buildah 容器可能會崩潰。

而這些還不是全部優點

附加儲存的可能性並不限於上述場景。 例如,您可以將所有容器映像放置在共用網路儲存體上,並授予所有 Buildah 容器存取它的權限。 假設我們的 CI/CD 系統經常使用數百個鏡像來建立容器鏡像。 我們將所有這些鏡像集中在一台儲存主機上,然後使用首選的網路儲存工具(NFS、Gluster、Ceph、ISCSI、S3...),向所有 Buildah 或 Kubernetes 節點開放對此儲存的一般存取。

現在只需將此網路儲存安裝到 /var/lib/shared 上的 Buildah 容器中就足夠了 - Buildah 容器不再需要透過 pull 下載鏡像。 因此,我們拋棄了預填充階段並立即準備好推出容器。

當然,這可以在實時 Kubernetes 系統或容器基礎設施中使用,以便在任何地方啟動和運行容器,而無需任何鏡像下載。 此外,容器註冊表收到上傳更新鏡像的推送請求後,可以自動將該鏡像發送到共享網路存儲,並立即可供所有節點使用。

容器映像的大小有時可以達到許多千兆位元組。 附加儲存的功能可讓您避免跨節點複製此類映像,並使啟動容器幾乎是即時的。

此外,我們目前正在開發一項稱為覆蓋卷安裝的新功能,這將使建置容器變得更快。

結論

在 Kubernetes/CRI-O、Podman 甚至 Docker 中的容器內執行 Buildah 是可行、簡單的,並且比使用 docker.socket 更安全。 我們大大提高了處理影像的靈活性,因此您可以透過多種方式運行它們,以優化安全性和效能之間的平衡。

附加儲存的功能可讓您加快甚至完全消除將影像下載到節點的速度。

來源: www.habr.com

添加評論