返回文章列表

容器映像檔來源管理與最佳實踐

本文探討容器化環境中映像檔來源的管理策略,涵蓋 Podman 的組態選項、映像檔映象設定、不受信任來源的封鎖,以及使用別名簡化映像檔管理。同時,文章也介紹了 Universal Base Image (UBI) 的特性與應用,並提供 UBI Standard、Minimal、Micro 和 Init

容器技術 DevOps

容器化應用程式佈署的效率與安全性,很大程度上取決於映像檔來源的管理。善用 Podman 的組態選項,可以精確控制映像檔的來源、映象和安全性。設定映像檔映象可以提升下載速度和穩定性,而封鎖不受信任的來源則能有效降低安全風險。此外,使用別名可以簡化映像檔名稱的管理,提高工作效率。選擇合適的基礎映像檔也是容器化應用成功的關鍵。Red Hat Universal Base Image (UBI) 提供了多種版本,滿足不同應用場景的需求。UBI Standard 映像檔功能完整,UBI Minimal 映像檔輕量高效,UBI Micro 映像檔則追求極致精簡與安全性,而 UBI Init 映像檔則支援 Systemd 管理多個服務。最後,使用容器登入檔和 Skopeo 工具可以有效管理和分發容器映像檔,確保應用程式佈署的流程順暢且安全。

管理容器映像檔來源

在容器化的環境中,選擇正確的映像檔來源至關重要。Podman 提供了一系列組態選項,讓使用者能夠指定信任的映像檔來源、設定映像檔映象,以及封鎖不受信任的來源。

設定映像檔映象

Podman 允許使用者設定映像檔映象,以提高映像檔下載的速度和可靠性。映像檔映象是一種將映像檔儲存在多個位置的技術,當使用者嘗試下載映像檔時,Podman 會嘗試從這些映象位置下載。

設定範例

unqualified-search-registries = ["docker.io", "quay.io"]
[[registry]]
prefix = "example.com/foo"
location = "registry.example.com:5000/foo"
insecure = false
[[registry.mirror]]
location = "mirror1.example.com:5000/bar"
[[registry.mirror]]
location = "mirror2.example.com:5000/bar"

內容解密:

  • unqualified-search-registries 指定了當使用者沒有指定完整的映像檔名稱時,Podman 會搜尋的映像檔倉函式庫。
  • [[registry]] 指定了一個映像檔倉函式庫的組態,prefix 指定了映像檔名稱的字首,location 指定了映像檔的實際位置。
  • [[registry.mirror]] 指定了映像檔的映象位置,Podman 會嘗試從這些位置下載映像檔。

封鎖不受信任的來源

除了設定映像檔映象外,Podman 還允許使用者封鎖不受信任的映像檔來源。這可以防止惡意的映像檔被下載到系統中。

設定範例

[[registry]]
location = "registry.rogue.io"
blocked = true

內容解密:

  • [[registry]] 指定了一個映像檔倉函式庫的組態,location 指定了要封鎖的映像檔倉函式庫。
  • blocked = true 指定了該映像檔倉函式庫被封鎖,使用者無法從該倉函式庫下載映像檔。

使用別名簡化映像檔管理

為了簡化映像檔管理,Podman 允許使用者使用別名來代表完整的映像檔名稱。

設定範例

[aliases]
"fedora" = "registry.fedoraproject.org/fedora"
"debian" = "docker.io/library/debian"

內容解密:

  • [aliases] 指定了映像檔別名的組態。
  • "fedora" = "registry.fedoraproject.org/fedora" 指定了一個別名,當使用者使用 fedora 作為映像檔名稱時,Podman 會自動使用 registry.fedoraproject.org/fedora 作為實際的映像檔名稱。

介紹 Universal Base Image

在企業環境中,許多使用者和公司採用 RHEL 作為作業系統,以可靠和安全地執行工作負載。根據 RHEL 的容器映像檔也可用,並且它們利用與 OS 發行版相同的套件版本控制。所有為 RHEL 發布的安全性更新都會立即應用於 OCI 映像檔,使其成為用於建置生產級應用程式的豐富、安全的映像檔。

不幸的是,沒有 Red Hat 訂閱的使用者無法使用 RHEL 映像檔。不過,Red Hat UBI 映像檔可以作為一個有用的解決方案,用於建置輕量級和安全的容器映像檔。

選擇容器基礎映像檔的最佳實踐

在容器化的世界中,選擇合適的基礎映像檔對於確保應用程式的安全性、可靠性和可維護性至關重要。許多公司出於對可靠性和安全性的考量,傾向於選擇企業級的解決方案,而Red Hat的Universal Base Image(UBI)正是為此而生。

Universal Base Image(UBI)簡介

UBI是Red Hat為瞭解決RHEL映像檔再分發限制而建立的。UBI映像檔是可自由再分發的,可以用於構建容器化應用程式、中介軟體和實用工具,並且由Red Hat不斷維護和升級。

目前有四種不同型別的UBI映像檔,每一種都針對特定的使用場景進行了最佳化:

  • Standard:標準的UBI映像檔,具備最多的功能和套件。
  • Minimal:精簡版的UBI映像檔,採用最小化的套件管理。
  • Micro:進一步縮小了的UBI映像檔,不包含套件管理器。
  • Init:包含systemd init系統的UBI映像檔,允許在單一容器中管理多個服務的執行。

UBI Standard映像檔

UBI Standard映像檔是最完整的UBI映像檔版本,與標準的RHEL映像檔最為接近。它包含了YUM套件管理器,可以透過安裝專用軟體倉函式庫中的套件進行自定義。

以下是一個使用UBI8 Standard映像檔構建最小化httpd伺服器的Dockerfile/ContainerFile範例:

FROM registry.access.redhat.com/ubi8
# 更新映像檔並安裝httpd
RUN yum update -y && yum install -y httpd && yum clean all -y
# 暴露預設的httpd埠80
EXPOSE 80
# 執行httpd
CMD ["/usr/sbin/httpd", "-DFOREGROUND"]

內容解密:

  1. FROM registry.access.redhat.com/ubi8:指定使用UBI8作為基礎映像檔。
  2. RUN yum update -y && yum install -y httpd && yum clean all -y:更新映像檔、安裝httpd並清理快取。
  3. EXPOSE 80:暴露容器的80埠給主機。
  4. CMD ["/usr/sbin/httpd", "-DFOREGROUND"]:設定容器的預設啟動命令為執行httpd。

UBI Minimal映像檔

UBI Minimal映像檔是UBI Standard映像檔的精簡版本,專為自洽的應用程式和其執行環境(如Python、Ruby、Node.js等)設計。它體積更小,套件選擇有限,且不包含YUM套件管理器,而是使用一個名為microdnf的最小化工具。

以下是一個使用UBI8 Minimal映像檔構建Python網頁伺服器的Dockerfile/ContainerFile範例:

# 根據UBI8 Minimal映像檔
FROM registry.access.redhat.com/ubi8-minimal
# 升級並安裝Python 3.6
RUN microdnf upgrade && microdnf install python3
# 複製原始碼
COPY entrypoint.sh http_server.py /
# 暴露預設的httpd埠8080
EXPOSE 8080
# 組態容器入口點
ENTRYPOINT ["/entrypoint.sh"]
# 執行httpd
CMD ["/usr/bin/python3", "-u", "/http_server.py"]

內容解密:

  1. FROM registry.access.redhat.com/ubi8-minimal:指定使用UBI8 Minimal作為基礎映像檔。
  2. RUN microdnf upgrade && microdnf install python3:升級映像檔並安裝Python 3。
  3. COPY entrypoint.sh http_server.py /:將本地的entrypoint.sh和http_server.py複製到容器根目錄。
  4. EXPOSE 8080:暴露容器的8080埠。
  5. ENTRYPOINT ["/entrypoint.sh"]CMD ["/usr/bin/python3", "-u", "/http_server.py"]:設定容器的入口點和預設命令。

Python網頁伺服器的程式碼實作了一個簡單的HTTP伺服器,回應"Hello World!“給客戶端請求。並且,透過Python的signal模組處理了SIGTERM和SIGINT訊號,以優雅地終止服務。

#!/usr/bin/python3
import http.server
import socketserver
import logging
import sys
import signal

# 省略實作細節...

同時,使用了一個最小化的入口指令碼來啟動Python可執行檔:

#!/bin/bash
set -e
exec $@

這個指令碼會執行CMD指令陣列中傳遞過來的命令,並啟用無緩衝輸出,以便即時列印存取日誌。

選擇容器基礎映像檔

UBI Micro 映像檔

UBI Micro 映像檔是 UBI 家族的最新成員。它的基本理念是提供一個無分發版的映像檔,一個精簡的套件管理器,不包含所有不必要的套件,以提供一個非常小的映像檔,同時提供最小的攻擊面。減少攻擊面是實作安全、最小映像檔的要求,這些映像檔更難以被利用。

UBI 8 Micro 映像檔在多階段建置中非常有用,第一階段建立完成的成品,第二階段將它們複製到最終映像檔中。以下範例顯示了一個基本的多階段 Dockerfile/ContainerFile,其中在 UBI 標準容器中建置了一個最小的 Golang 應用程式,而最終成品被複製到 UBI Micro 映像檔中:

# 建置器映像檔
FROM registry.access.redhat.com/ubi8-minimal AS builder
# 安裝 Golang 套件
RUN microdnf upgrade && \
    microdnf install golang && \
    microdnf clean all
# 複製檔案以進行建置
COPY go.mod /go/src/hello-world/
COPY main.go /go/src/hello-world/
# 設定工作目錄
WORKDIR /go/src/hello-world
# 下載相依性
RUN go get -d -v ./...
# 安裝套件
RUN go build -v ./...

# 執行階段映像檔
FROM registry.access.redhat.com/ubi8/ubi-micro:latest
COPY --from=builder /go/src/hello-world/hello-world /
EXPOSE 8080
CMD ["/hello-world"]

內容解密:

  1. 使用 registry.access.redhat.com/ubi8-minimal 作為建置器映像檔來編譯 Golang 應用程式。
  2. 在建置階段安裝必要的 Golang 套件,並清理暫存檔案。
  3. 將 Golang 應用程式原始碼複製到容器中,並進行編譯。
  4. 使用 registry.access.redhat.com/ubi8/ubi-micro:latest 作為最終執行階段映像檔。
  5. 將編譯好的 Golang 應用程式從建置器映像檔複製到最終映像檔中。
  6. 設定容器暴露的埠號和預設執行的命令。

最終產生的映像檔大小約為 45 MB。

UBI Micro 映像檔沒有內建的套件管理器,但仍然可以使用 Buildah 原生命令安裝額外的套件。以下範例顯示了一個可以在 RHEL 8 上執行的建置指令碼,其目的是在 UBI Micro 映像檔上安裝額外的 Python 套件:

#!/bin/bash
set -euo pipefail

if [ $UID -ne 0 ]; then
    echo "This script must be run as root"
    exit 1
fi

container=$(buildah from registry.access.redhat.com/ubi8/ubi-micro)
mount=$(buildah mount $container)

yum install -y \
    --installroot $mount \
    --setopt install_weak_deps=false \
    --nodocs \
    --noplugins \
    --releasever 8 \
    python3

yum clean all --installroot $mount
buildah umount $container
buildah commit $container micro_httpd

內容解密:

  1. 使用 buildah from 命令建立一個新的容器。
  2. 使用 buildah mount 命令掛載容器檔案系統。
  3. 使用 yum install 命令安裝 Python 3 到掛載的容器檔案系統中。
  4. 使用 yum clean all 命令清理暫存檔案。
  5. 使用 buildah umount 命令解除安裝容器檔案系統。
  6. 使用 buildah commit 命令將更改提交到新的映像檔。

UBI Init 映像檔

UBI Init 映像檔允許在容器內協調多個服務的執行。它內建了一個最小的 Systemd init 程式,可以用來管理多個 Systemd unit。

以下範例顯示了一個 Dockerfile/ContainerFile,它安裝了 httpd 套件並組態了一個 Systemd unit 以執行 httpd 服務:

FROM registry.access.redhat.com/ubi8/ubi-init

RUN yum -y install httpd && \
    yum clean all && \
    systemctl enable httpd

RUN echo "Successful Web Server Test" > /var/www/html/index.html

RUN mkdir /etc/systemd/system/httpd.service.d/ && \
    echo -e '[Service]\nRestart=always' > /etc/systemd/system/httpd.service.d/httpd.conf

EXPOSE 80
CMD [ "/sbin/init" ]

內容解密:

  1. 使用 registry.access.redhat.com/ubi8/ubi-init 作為基礎映像檔。
  2. 安裝 httpd 套件並啟用 httpd 服務。
  3. 建立一個簡單的網頁內容。
  4. 組態 httpd 服務的 Systemd unit 以實作自動重啟。
  5. 設定容器暴露的埠號和預設執行的命令。

我們可以建置和執行這個映像檔,並使用 ps 命令檢查容器內的 init 系統行為:

$ buildah build -t init_httpd .
$ podman run -d --name httpd_init -p 8080:80 init_httpd
$ podman exec -ti httpd_init /bin/bash
[root@b4fb727f1907 /]# ps aux

內容解密:

  1. 使用 buildah build 命令建置映像檔。
  2. 使用 podman run 命令執行容器並對映埠號。
  3. 使用 podman exec 命令進入容器並執行 bash。
  4. 使用 ps aux 命令檢視容器內的行程列表。

這個例子展示瞭如何在 UBI Init 映像檔中使用 Systemd init 程式來管理多個服務。

將映像檔推播到容器登入檔

在前一章中,我們探討了容器基礎映像檔的重要概念。正如我們所見,選擇容器基礎映像檔對於我們的容器至關重要,我們應該使用來自受信任的容器登入檔和開發社群的官方容器映像檔。

但是一旦我們選擇了首選的基礎映像檔並構建了最終的容器映像檔,我們就需要一種方法將我們的成果分發到我們計劃讓其執行的各種目標主機上。

分發容器映像檔的最佳選擇是將其推播到容器登入檔,然後讓所有目標主機提取容器映像檔並執行它。

因此,在本章中,我們將涵蓋以下主要主題:

  • 什麼是容器登入檔?
  • 根據雲端和本地的容器登入檔
  • 使用Skopeo管理容器映像檔
  • 執行本地容器登入檔

技術需求

在繼續本章及其範例之前,需要一台具有正常運作的Podman安裝的機器。如第3章《執行第一個容器》所述,本文中的所有範例都在Fedora 34系統或更高版本上執行,但可以在您選擇的作業系統上重現。

對第4章《管理執行中的容器》和第8章《選擇容器基礎映像檔》中涵蓋的主題有良好的理解,有助於輕鬆掌握有關容器登入檔的概念。

什麼是容器登入檔?

容器登入檔只是容器映像檔儲存函式庫的集合,與需要動態提取和執行容器映像檔的系統一起使用。

容器登入檔上可用的主要功能如下:

  • 儲存函式倉管理
  • 推播容器映像檔
  • 標籤管理
  • 提取容器映像檔
  • 身份驗證管理

讓我們在以下章節中詳細瞭解每個功能。

儲存函式倉管理

容器登入檔最重要的功能之一是透過儲存函式倉管理容器映像檔。根據我們選擇的容器登入檔實作,我們一定會找到一個網頁介面或命令列介面,讓我們能夠處理建立一種資料夾,用作我們的容器映像檔的儲存函式庫。

使用Skopeo管理容器映像檔

Skopeo是一個專門用於管理容器映像檔的工具。它可以用於複製、刪除和檢查容器映像檔,以及其他操作。

推播和提取容器映像檔

推播和提取容器映像檔是容器登入檔的基本功能。我們可以使用Skopeo或其他工具將容器映像檔推播到登入檔,也可以從登入檔提取容器映像檔。

本地容器登入檔

執行本地容器登入檔是一種在本地環境中管理和分發容器映像檔的方法。這對於開發和測試環境尤其有用。

使用Skopeo檢查和複製容器映像檔

Skopeo可以用於檢查和複製容器映像檔。以下是一個範例:

skopeo inspect docker://registry.fedoraproject.org/fedora:latest

這個命令將檢查Fedora最新版本的容器映像檔。

使用Skopeo複製容器映像檔

Skopeo可以用於複製容器映像檔。以下是一個範例:

skopeo copy docker://registry.fedoraproject.org/fedora:latest docker://localhost:5000/fedora:latest

這個命令將Fedora最新版本的容器映像檔複製到本地的容器登入檔。

內容解密:

此範例展示瞭如何使用Skopeo檢查和複製容器映像檔。skopeo inspect命令用於檢查容器映像檔,而skopeo copy命令用於複製容器映像檔。在這個範例中,我們將Fedora最新版本的容器映像檔複製到本地的容器登入檔。