返回文章列表

容器映像安全:建構可信任的映像來源策略

本文探討容器映像的安全性,闡述如何選擇和管理可信任的映像來源,並介紹 Red Hat Universal Base Image (UBI) 的應用,以降低安全風險,強化容器化環境的防禦。

容器技術 資安

在容器化應用程式佈署的過程中,映像的安全性往往是關鍵的環節。如同程式碼的來源需要被審慎檢驗,容器映像的來源也必須經過嚴格的篩選和管理。本文將探討如何建構一套可信任的映像來源策略,並介紹 Red Hat UBI 的應用,以提升容器化環境的安全性。

容器映像的安全性並非單純地檢查映像本身,更重要的是確保其來源的可靠性。惡意軟體、已知漏洞和錯誤組態都可能潛藏在看似正常的映像中,對系統造成威脅。因此,選擇可信任的 Registry 並設定映象,是確保映像安全的第一步。透過映象設定,我們可以將映像來源指向內部或受信任的 Registry,同時也能透過封鎖特定 Registry 或名稱空間,防止意外或惡意地使用不安全的映像。此外,妥善利用映像別名機制,可以簡化映像管理,降低人為錯誤的風險。

Red Hat Universal Base Image (UBI) 的出現,為容器映像的安全性提供了一個更堅實的基礎。UBI 映象根據 RHEL,並提供多種版本,滿足不同應用場景的需求。從功能豐富的標準版,到精簡的最小版和微型版,開發者可以根據應用程式的特性,選擇最合適的 UBI 映象,在兼顧效能的同時,最大限度地降低安全風險。更重要的是,UBI 映象可以自由再發布,方便企業內部使用和分享。

選擇容器基礎映象,如同選擇建築的根本,必須穩固可靠。UBI 提供了多種選擇,讓開發者可以根據應用需求,選擇最合適的版本,兼顧功能性、安全性與效能。UBI 的標準版適用於大多數應用,而最小版和微型版則更適合資源有限的環境。此外,Init 版的 UBI 則提供了 systemd 的支援,方便管理多個服務。

容器映像的奧秘:從何而來?

在容器化的世界裡,容器映像是應用程式執行的根本。但這些映像究竟從何而來?它們的內容是否安全可靠?本文中,玄貓將帶領大家探索容器映像的來源,並分享如何選擇安全可靠的映像。

Docker Hub:官方映像與社群力量

Docker Hub 是目前最流行的容器映像 registry 之一,它提供了大量的官方映像和社群貢獻的映像。

在 Docker Hub 上,你可以找到:

  • 官方映像(Official Images):由 Docker 團隊與上游專案維護者共同維護,品質有保障。
  • 社群映像:由社群成員貢獻,種類別繁多,但需要仔細檢查其 Dockerfile 和安全性。

在 Docker Hub 頁面頂部,你可以找到映像的相關資訊,如最新的標籤、支援的架構以及專案檔案和 issue 回報系統的連結。

玄貓建議優先選擇官方映像,若官方映像不符合需求,則需要仔細檢查社群映像的 Dockerfile 和安全性。

Quay:安全掃描的守護者

Quay 是另一個流行的容器映像 registry,它提供了安全掃描功能,可以幫助使用者選擇更安全的映像。

Quay 採用 Clair 專案,這是一個領先的容器漏洞掃描器,可以在 repository 標籤頁面上顯示報告。透過安全掃描,你可以瞭解映像中是否存在已知的安全漏洞。

Red Hat Ecosystem Catalog:企業級的選擇

Red Hat Ecosystem Catalog 是 Red Hat Enterprise Linux (RHEL) 和 Red Hat OpenShift Container Platform (OCP) 使用者的預設容器 registry。

這個 registry 結合了 Docker Hub 和 Quay 的優點,提供了:

  • Red Hat 官方容器映像
  • ContainerFile/Dockerfile 原始碼
  • 安全報告

在 Red Hat Ecosystem Catalog 上,你可以找到經過 Red Hat 官方認證的映像,並檢視其 Dockerfile 和安全報告,確保映像的品質和安全性。

UBI:通用基礎映像

Red Hat 推出了 Universal Base Image (UBI) 計畫,允許所有使用者(無論是否為 Red Hat 客戶)使用 Red Hat 容器映像。這擴充套件了 Red Hat 生態系統,並讓使用者能夠利用 Red Hat Ecosystem Catalog 提供的服務和最新的套件。

玄貓的建議:如何選擇容器映像

在選擇容器映像時,玄貓建議遵循以下步驟:

  1. 優先選擇官方映像:官方映像通常由專案維護者或可信任的組織提供,品質和安全性有保障。
  2. 檢查 Dockerfile:仔細檢查 Dockerfile,瞭解映像的構建過程,確保其中沒有惡意程式碼或不必要的軟體。
  3. 進行安全掃描:使用安全掃描工具掃描映像,檢查是否存在已知的安全漏洞。
  4. 關注社群評價:檢視社群對映像的評價,瞭解其他使用者的使用經驗和建議。
  5. 定期更新映像:定期更新映像,以修復已知的安全漏洞並取得最新的功能。

選擇安全可靠的容器映像是確保應用程式安全執行的重要一步。透過本文的介紹,玄貓希望能夠幫助大家更好地瞭解容器映像的來源,並做出明智的選擇。

總結來說,選擇容器映像時,要像挑選食材一樣謹慎。官方認證、成分透明、安全檢測,這些都是不可或缺的考量因素。只有這樣,才能確保你的應用程式在容器化的世界裡安全、穩定地執行。

容器基礎映象選擇:信任的起點

在先前的章節中,我們確立了映象倉函式庫作為有效、可用映象的可靠來源的核心地位。現在,我們要強調採用來自可信任來源的映象的重要性。

OCI 映象用於將二進位檔案和執行時環境封裝成結構化的檔案系統,以提供特定的服務。當我們提取這些映象並在系統上執行時,實際上是在信任映象的作者沒有使用惡意元件篡改內容。然而,在現今,信任並非理所當然。

正如我們在第 11 章「保護容器安全」中將看到的,容器可能存在許多攻擊場景和惡意行為:許可權提升、資料洩露和挖礦只是其中幾個例子。當 Kubernetes 叢集中執行的容器(可能遍佈數千個叢集)能夠輕易地在基礎設施中產生惡意 Pod 時,這些行為可能會被放大。

為了幫助安全團隊緩解這些風險,MITRE 公司定期發布 MITRE ATT&CK 矩陣,以識別所有可能的攻擊策略及其相關技術,並提供真實案例以及檢測和緩解的最佳實踐。其中一個矩陣專門針對容器,其中許多技術都是根據不安全的映象實作的,這些映象可能導致惡意行為成功執行。

重要提示

您應該優先選擇來自支援漏洞掃描的映象倉函式庫的映象。如果掃描結果可用,請仔細檢查,並避免使用存在嚴重漏洞的映象。

那麼,建立安全的雲原生基礎設施的第一步是什麼?答案是選擇僅來自可信任來源的映象,而第一步是組態受信任的映象倉函式庫和模式,以阻止未經授權的映象。我們將在以下小節中介紹這一點。

管理受信任的映象倉函式庫

正如在第 3 章「執行第一個容器」的「準備環境」部分中所示,Podman 可以使用設定檔管理受信任的映象倉函式庫。/etc/containers/registries.conf 檔案(如果存在,則會被使用者相關的 $HOME/.config/containers/registries.conf 檔案覆寫)管理一個受信任的映象倉函式庫列表,Podman 可以安全地連線這些映象倉函式庫以搜尋和提取映象。

讓我們看一個這個檔案的例子:

unqualified-search-registries = ["docker.io", "quay.io"]

[[registry]]
location = "registry.example.com:5000"
insecure = false

這個檔案幫助我們定義 Podman 可以使用的受信任的映象倉函式庫,因此值得詳細分析。Podman 接受不完整和完整限定的映象。區別很簡單,如下所示:

  • 完整限定的映象:包括映象倉函式庫伺服器的 FQDN、名稱空間、映象名稱和標籤。例如,docker.io/library/nginx:latest 是一個完整限定的映象。它具有完整的名稱,不會與任何其他 Nginx 映象混淆。
  • 不完整限定的映象:僅包括映象的名稱。例如,nginx 映象在搜尋的映象倉函式庫中可能有多個例項。從基本的 podman search nginx 命令產生的映象大多數不是官方的,應詳細分析以確保它們是可信任的。可以使用 OFFICIAL 標誌和 STARS 數量(越多越好)來過濾輸出。

映象倉函式庫組態檔案的第一個全域性設定是 unqualified-search-registry 陣列,它定義了不完整限定映象的映象倉函式庫搜尋列表。當使用者執行 podman search <image_name> 命令時,Podman 將在列表中定義的映象倉函式庫中進行搜尋。從列表中刪除映象倉函式庫後,Podman 將停止搜尋該映象倉函式庫。但是,Podman 仍然能夠從外部映象倉函式庫提取完整限定的映象。

映象倉函式庫組態進階:prefix、insecure 與 mirror

為了管理單個映象倉函式庫並為特定映象建立比對模式,我們可以使用 [[registry]] TOML 表。這些表的主要設定如下:

  • prefix: 用於定義映象名稱,可以支援多種格式。通常,我們可以按照 host[:port]/namespace[/_namespace_...]/repo(:_tag|@digest) 模式定義映象,儘管可以應用更簡單的模式,例如 host[:port]host[:port]/namespace 甚至 [*.]host。透過這種方法,使用者可以為映象倉函式庫定義通用字首,也可以定義更詳細的字首以比對特定的映象或標籤。給定一個完整限定的映象,如果兩個 [[registry]] 表具有帶有部分比對的字首,則將使用最長比對模式。
  • insecure: 一個布林值(true 或 false),允許根據不信任證書的未加密 HTTP 連線或 TLS 連線。
  • blocked: 一個布林值(true 或 false),用於定義被阻止的映象倉函式庫。如果設定為 true,則阻止與字首比對的映象倉函式庫或映象。
  • location: 此欄位定義映象倉函式庫的位置。預設情況下,它等於字首,但它可以具有不同的值。在這種情況下,與自定義字首名稱空間比對的模式將解析為位置值。

除了主要的 [[registry]] 表之外,我們還可以定義一個 [[registry.mirror]] TOML 表陣列,以提供主映象倉函式庫或映象倉函式庫名稱空間的備用路徑。當提供多個映象時,Podman 將首先在它們之間搜尋,然後回退到在主 [[registry]] 表中定義的位置。

以下示例透過定義一個名稱空間映象倉函式庫條目及其映象來擴充套件前一個示例:

unqualified-search-registries = ["docker.io", "quay.io"]

[[registry]]
location = "registry.example.com:5000/foo"
insecure = false

[[registry.mirror]]
location = "mirror1.example.com:5000/bar"

[[registry.mirror]]
location = "mirror2.example.com:5000/bar"

在容器化環境中,確保映象來源的可信度至關重要。透過 Podman 的組態,玄貓建議開發者應嚴格管理受信任的映象倉函式庫,從源頭上降低安全風險。

容器映像來源:開發堅固的信任防線

在容器化的世界裡,映像的安全性至關重要。如同軟體開發需要信任的程式碼來源,容器也需要信任的映像來源。不安全的映像可能帶來惡意程式、漏洞或組態錯誤,對系統造成嚴重威脅。因此,建立一套完善的容器映像信任機制,是確保應用程式安全執行的根本。

映像映象:高用性與加速的雙面刃

映像映象是提高映像可用性和下載速度的有效方法。透過設定映象站點,Podman 可以從多個來源提取映像,避免單點故障,並分散流量,降低主要 Registry 的負載。

以下是一個 registries.conf 的範例,展示如何設定映像映象:

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: 定義未指定完整 Registry 名稱時,Podman 預設搜尋的 Registry。
  • [[registry]]: 定義一個 Registry 的設定。
  • prefix: 指定 Registry 的字首,用於比對映像名稱。
  • location: 指定 Registry 的實際位置。
  • insecure: 設定是否允許使用不安全的 HTTP 連線。強烈建議在生產環境中使用 HTTPS。
  • [[registry.mirror]]: 定義一個映象站點。

在這個範例中,當使用者嘗試提取 example.com/foo/app:latest 映像時,Podman 會先嘗試 mirror1.example.com:5000/bar/app:latest,然後是 mirror2.example.com:5000/bar/app:latest,如果都失敗,才會回到原始的 registry.example.com:5000/foo/app:latest

玄貓認為,使用字首可以提供更大的彈性。例如,以下設定會將所有符合 example.com/foo 的映像重新導向到映象站點:

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"

當提取 example.com/foo/app:latest 映像時,Podman 會依序嘗試 mirror1.example.com:5000/bar/app:latestmirror2.example.com:5000/bar/app:latestregistry.example.com:5000/foo/app:latest

開發私有映像映象:離線環境的救星

映象的進階用法之一,是將公共 Registry 替換為私有映象,尤其在網路隔離的環境中。以下範例將 docker.ioquay.io 重新對應到一個私有映象,並使用不同的名稱空間:

[[registry]]
prefix="quay.io"
location="mirror-internal.example.com/quay"

[[registry]]
prefix="docker.io"
location="mirror-internal.example.com/docker"

重點提示:

映象 Registry 應與被映象的儲存函式庫保持同步。管理員或 SRE 團隊應實施映像同步策略,定期更新儲存函式庫。

封鎖不信任來源:強化安全防禦

除了信任的來源,我們還需要能夠封鎖不信任的來源。這可以針對單一映像、名稱空間或整個 Registry 進行。

以下範例告訴 Podman 不要搜尋或提取來自 registry.rogue.io 的映像:

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

更精細的策略是封鎖特定的名稱空間,而不影響整個 Registry。以下範例封鎖了 quay.io/foo/ 名稱空間:

[[registry]]
prefix = "quay.io/foo/"
location = "docker.io"
blocked = true

根據這個模式,如果使用者嘗試提取 quay.io/foo/nginx:latestquay.io/foo/httpd:v2.4 映像,提取動作會被封鎖。但提取 quay.io/bar/fedora:latest 則不會受到影響。

使用者還可以針對單一映像或標籤定義非常具體的封鎖規則:

[[registry]]
prefix = "internal-registry.example.com/dev/app:v0.1"
location = "internal-registry.example.com "
blocked = true

我們可以組合多個封鎖規則,並在這些規則之上增加映象設定。

重點提示:

在具有多台執行 Podman 的機器(例如開發者工作站)的複雜基礎架構中,一個聰明的做法是使用組態管理工具更新 Registry 的設定檔,並以宣告方式套用 Registry 的過濾器。

映像別名:簡化管理,降低錯誤

完整的映像名稱可能相當長,包括 Registry FQDN、名稱空間、儲存函式庫和標籤。可以使用 [aliases] 表建立別名,允許使用簡短的映像名稱。這可以簡化映像管理並減少人為錯誤。但是,別名不處理映像標籤或摘要。

以下範例為常用映像定義了一系列別名:

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

當別名比對到一個短名稱時,它會立即被使用,而不會搜尋 unqualified-search-registries 列表中定義的 Registry。

重點提示:

我們可以在 /etc/containers/registries.conf.d/ 資料夾中建立自訂檔案,以定義別名,而不會使主要的設定檔過於臃腫。

選擇安全的基礎映像:UBI 的價值

管理信任來源和封鎖不需要的映像、Registry 或名稱空間,是一種良好的安全實務。但這並不代表我們可以忽略選擇一個有效、值得信任與具有最低攻擊面的映像的責任。這在建構新應用程式時尤其重要,基礎映像必須輕量與安全。Red Hat UBI 映像是解決這個問題的一個好方法。

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

然而,未啟用 Red Hat 訂閱的使用者無法公開使用 RHEL 映像。擁有有效訂閱的使用者可以在其 RHEL 系統上自由使用它們,並在其之上建構自訂映像,但未經 Red Hat 企業協定授權,它們無法自由重新發布。

為何選擇容器基礎映象如此重要:從 Red Hat UBI 談起

在容器化的世界中,基礎映象的選擇往往被低估。許多人認為隨便找個常用映象就好,但實際上,基礎映象的可靠性與安全性對於企業級應用至關重要。就像蓋房子打地基一樣,基礎沒打好,再華麗的應用也可能潛藏風險。

過去,許多企業因為 RHEL 映象的再發布限制而感到困擾。為瞭解決這個問題,Red Hat 推出了通用基礎映象(Universal Base Image,UBI)。UBI 映象不僅可以自由再發布,還能用於構建容器化的應用、中介軟體和工具,並且由 Red Hat 持續維護和升級。

UBI 的多種風味:找到最適合你的那一款

UBI 映象根據目前受支援的 RHEL 版本。撰寫本文時,UBI7 和 UBI8 映象(分別根據 RHEL7 和 RHEL8)以及 UBI9-beta 映象(根據 RHEL9-beta)均已可用。你可以將 UBI 映象視為 RHEL 作業系統的一個子集。

所有 UBI 映象都可以在公共 Red Hat 倉函式庫(registry.access.redhat.com)和 Docker Hub(docker.io)上找到。

目前有四種不同的 UBI 映象,每種都針對特定使用案例進行了最佳化:

  • 標準版 (Standard):這是最完整的 UBI 映象,具有最多的功能和可用的套件。
  • 最小版 (Minimal):這是標準映象的精簡版本,具有最小化的套件管理。
  • 微型版 (Micro):這是佔用空間更小的 UBI 版本,不包含套件管理器。
  • Init 版 (Init):這是一個包含 systemd init 系統的 UBI 映象,因此你可以在單個容器中管理多個服務的執行。

所有這些映象都可以免費使用,並在自定義映象中重新發布。接下來,我們將詳細介紹每一種映象,首先從 UBI 標準映象開始。

UBI 標準映象:通用應用程式的根本

UBI 標準映象是最完整的 UBI 映象版本,也是最接近標準 RHEL 映象的版本。它包含 RHEL 中提供的 YUM 套件管理器,並且可以透過安裝其專用軟體倉函式庫(即 ubi-8-baseosubi-8-appstream)中提供的套件來自定義。

以下範例展示了一個使用標準 UBI8 映象來構建最小 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: 這一行指定了基礎映象。我們使用Red Hat提供的ubi8映象,這是一個根據Red Hat Enterprise Linux 8的通用基礎映象。
  2. RUN yum update -y && yum install -y httpd && yum clean all -y: 這一行執行了三個命令。首先,yum update -y更新系統上的所有套件。然後,yum install -y httpd安裝Apache HTTP Server。最後,yum clean all -y清除yum快取,減少映象大小。
  3. EXPOSE 80: 這一行宣告容器將在80連線埠監聽連線。這是一個常見的HTTP連線埠。
  4. CMD ["/usr/sbin/httpd", “-DFOREGROUND”]: 這一行指定了容器啟動時執行的命令。這裡我們啟動Apache HTTP Server,並使用-DFOREGROUND選項使其在前台執行。

UBI 標準映象專為 RHEL 上提供的通用應用程式和套件而設計,並且已經包含一個精選的基本系統工具列表(包括 curltarvisedgzip)和 OpenSSL 函式庫,同時仍保持較小的尺寸(約 230 MiB):較少的套件意味著更輕量級的映象和更小的攻擊面。

如果 UBI 標準映象仍然被認為太大,那麼 UBI 最小映象可能是一個不錯的選擇。

UBI 最小映象:為自洽應用而生

UBI 最小映象是 UBI 標準映象的精簡版本,專為自洽應用程式及其執行時(Python、Ruby、Node.js 等)而設計。因此,它的尺寸更小,套件選擇較少,並且不包含 YUM 套件管理器;這已被一個名為 microdnf 的最小工具取代。UBI 最小映象比 UBI 標準映象小,大約是其一半大小。

以下範例展示了一個使用 UBI 8 最小映象來構建概念驗證 Python Web 伺服器的 Dockerfile/ContainerFile

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

內容解密

  1. FROM registry.access.redhat.com/ubi8-minimal: 這一行指定了基礎映象。我們使用Red Hat提供的ubi8-minimal映象,這是一個比ubi8更小的基礎映象,適合於只需要最基本功能的應用程式。
  2. RUN microdnf upgrade && microdnf install python3: 這一行使用microdnf命令來升級系統並安裝Python 3。microdnfyum的輕量級替代品,適合於在資源受限的環境中使用。
  3. COPY entrypoint.sh http_server.py /: 這一行將本地的entrypoint.shhttp_server.py檔案複製到映象的根目錄。
  4. EXPOSE 8080: 這一行宣告容器將在8080連線埠監聽連線。
  5. ENTRYPOINT ["/entrypoint.sh"]: 這一行指定了容器啟動時執行的指令碼。entrypoint.sh指令碼負責啟動Python Web伺服器。
  6. CMD ["/usr/bin/python3", “-u”, “/http_server.py”]: 這一行指定了傳遞給entrypoint.sh指令碼的命令。這裡我們啟動Python Web伺服器,並使用-u選項來停用輸出緩衝。

透過檢視由容器執行的 Python Web 伺服器的原始碼,我們可以看到,當收到 HTTP GET 請求時,Web 伺服器處理程式會印出 Hello World! 字串。該伺服器還使用 Python signal 模組管理訊號終止,允許容器優雅地停止:

#!/usr/bin/python3
import http.server
import socketserver
import logging
import sys
import signal
from http import HTTPStatus
port = 8080
message = b'Hello World!\n'
logging.basicConfig(
stream = sys.stdout,
level = logging.INFO
)
def signal_handler(signum, frame):
sys.exit(0)
class Handler(http.server.SimpleHTTPRequestHandler):
def do_GET(self):
self.send_response(HTTPStatus.OK)
self.end_headers()
self.wfile.write(message)
if __name__ == "__main__":
signal.signal(signal.SIGTERM, signal_handler)
signal.signal(signal.SIGINT, signal_handler)
try:
httpd = socketserver.TCPServer(('', port), Handler)
logging.info("Serving on port %s", port)
httpd.serve_forever()
except SystemExit:
httpd.shutdown()
httpd.server_close()

內容解密

  1. import 陳述式:這些陳述式匯入了 Python 的標準函式庫,包括 http.server(用於建立 HTTP 伺服器),socketserver(用於處理網路連線),logging(用於記錄日誌),sys(用於存取系統特定的引數和函式),signal(用於處理訊號),以及 HTTPStatus(用於 HTTP 狀態碼)。
  2. port = 8080: 這一行定義了伺服器將監聽的連線埠號。
  3. message = b’Hello World!\n’: 這一行定義了伺服器將傳回的訊息。b 字首表示這是一個位元組字串。
  4. logging.basicConfig(…): 這一行組態了日誌記錄。它將日誌輸出到標準輸出,並將日誌級別設定為 INFO。
  5. def signal_handler(signum, frame):: 這一行定義了一個訊號處理函式。當伺服器收到 SIGTERMSIGINT 訊號時,這個函式將被呼叫,並呼叫 sys.exit(0) 來正常終止程式。
  6. class Handler(http.server.SimpleHTTPRequestHandler):: 這一行定義了一個處理 HTTP 請求的類別。它繼承自 http.server.SimpleHTTPRequestHandler,並重寫了 do_GET 方法來處理 GET 請求。
  7. def do_GET(self):: 這一行定義了 do_GET 方法。當伺服器收到 GET 請求時,這個方法將被呼叫。它首先使用 self.send_response(HTTPStatus.OK) 傳送一個 HTTP 200 OK 回應,然後使用 self.end_headers() 傳送標頭,最後使用 self.wfile.write(message) 將訊息寫入回應主體。
  8. if __name__ == “__main__”:: 這一行確保程式只有在作為主程式執行時才會執行以下程式碼。
  9. signal.signal(signal.SIGTERM, signal_handler): 這一行將 SIGTERM 訊號(通常由 docker stop 命令傳送)與 signal_handler 函式關聯起來。
  10. signal.signal(signal.SIGINT, signal_handler): 這一行將 SIGINT 訊號(通常由 Ctrl+C 傳送)與 signal_handler 函式關聯起來。
  11. try…except SystemExit:: 這一塊程式碼用於啟動伺服器並處理 SystemExit 異常。SystemExit 異常通常由 sys.exit() 函式引發。
  12. httpd = socketserver.TCPServer((’’, port), Handler): 這一行建立了一個 TCP 伺服器,它將監聽所有介面上的指定連線埠,並使用 Handler 類別來處理請求。
  13. logging.info(“Serving on port %s”, port): 這一行記錄一條訊息,指示伺服器正在指定連線埠上執行。
  14. httpd.serve_forever(): 這一行啟動伺服器並使其無限期地執行,直到收到終止訊號。
  15. httpd.shutdown(): 這一行優雅地關閉伺服器。
  16. httpd.server_close(): 這一行關閉伺服器通訊端。

最後,Python 可執行檔由一個最小的進入點指令碼呼叫:

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

內容解密

  1. #!/bin/bash: 這一行指定了用於執行指令碼的直譯器。在這種情況下,它是 Bash shell。
  2. set -e: 這一行設定了 -e 選項。這意味著如果指令碼中的任何命令失敗(即,傳回非零離開程式碼),指令碼將立即終止。
  3. exec $@: 這一行使用 exec 命令來執行傳遞給指令碼的命令。$@ 是一個特殊變數,它擴充套件為傳遞給指令碼的所有引數。exec 命令用傳遞的命令替換當前行程。這意味著當執行的命令完成時,指令碼將終止。

該指令碼啟動由 CMD 指令中的陣列傳遞的命令。另外,請注意傳遞給命令陣列中 Python 可執行檔的 -u 選項。這將啟用非緩衝輸出,並使容器即時印出存取日誌。

讓我們嘗試構建並執行容器,看看會發生什麼:

$ buildah build -t python_httpd .
$ podman run -p 8080:8080 python_httpd
INFO:root:Serving on port 8080

有了這個,我們最小的 Python httpd 伺服器就可以執行,並提供大量幾乎沒用但令人感到溫暖的 Hello World! 回應。

UBI 最小映象最適合這些使用案例。但是,可能需要一個更小的映象。這是 UBI 微型映象的完美使用案例。

玄貓觀點

玄貓認為,選擇合適的容器基礎映象,就像選擇建築材料一樣,需要根據實際需求進行權衡。UBI 映象的多種風味,為開發者提供了更多的選擇,可以根據應用程式的特性,選擇最合適的映象,從而提高效率、降低風險。