在容器化應用程式佈署流程中,安全可靠的本地容器登入檔至關重要。本文將指導讀者如何組態本地容器登入檔,涵蓋 HTTPS 加密傳輸、根據 htpasswd 的身份驗證、映像刪除和健康檢查等關鍵設定。同時,針對 SELinux 許可權問題和 ping 命令在受限環境下的故障,提供具體的解決方案和操作步驟。此外,本文還將探討如何使用 skopeo 同步映像、執行垃圾回收,以及利用 podman logs、inspect、system df 和 system info 等命令進行容器故障排除和監控。最後,提醒讀者留意大型 UID/GID 對稀疏檔案(如 /var/log/lastlog)的潛在影響,避免容器建置過程中出現問題。

執行本地容器登入檔:組態與安全

在前面的章節中,我們探討瞭如何使用預設組態執行一個本地容器登入檔。然而,在實際的開發和生產環境中,我們需要對登入檔進行更細緻的組態,以滿足安全性和功能性的需求。本文將介紹如何透過自定義組態來增強本地容器登入檔的功能,包括啟用影像刪除、基本身份驗證和HTTPS傳輸加密。

自定義登入檔組態

首先,我們需要建立一個自定義的組態檔案config.yml,內容如下:

version: 0.1
log:
  fields:
    service: registry
storage:
  delete:
    enabled: true
  filesystem:
    rootdirectory: /var/lib/registry
auth:
  htpasswd:
    realm: basic-realm
    path: /var/lib/htpasswd
http:
  addr: :5000
  headers:
    X-Content-Type-Options: [nosniff]
tls:
  certificate: /etc/pki/certs/tls.crt
  key: /etc/pki/certs/tls.key
health:
  storagedriver:
    enabled: true
    interval: 10s
    threshold: 3

內容解密:

  1. 版本與日誌組態:指定組態檔案的版本,並設定日誌欄位以標識服務名稱。
  2. 儲存組態:啟用刪除功能,並指設定檔案系統的根目錄。
  3. 身份驗證:使用htpasswd檔案進行基本身份驗證,指定領網域名稱和檔案路徑。
  4. HTTP組態:設定監聽地址和埠,並新增安全頭部以防止內容型別嗅探。
  5. TLS組態:指定TLS證書和私鑰的路徑,以啟用HTTPS加密傳輸。
  6. 健康檢查:啟用儲存驅動的健康檢查,並設定檢查間隔和閾值。

生成htpasswd檔案和自簽名證書

在執行登入檔之前,我們需要生成htpasswd檔案和自簽名證書。

生成htpasswd檔案

htpasswd -cBb ./htpasswd admin p0dman4Dev0ps#

內容解密:

  1. 使用htpasswd工具生成包含使用者名稱和密碼的檔案。
  2. -cBb選項分別表示建立新檔案、啟用批處理模式和啟用bcrypt雜湊函式。

生成自簽名證書

$ mkdir certs
$ openssl req -newkey rsa:4096 -x509 -sha256 -nodes \
  -days 365 \
  -out certs/tls.crt \
  -keyout certs/tls.key \
  -subj '/CN=localhost' \
  -addext "subjectAltName=DNS:localhost"

內容解密:

  1. 使用openssl工具生成自簽名證書和私鑰。
  2. 指定證書有效期為365天,並設定主體名稱為localhost
  3. 新增主題別名擴充套件,以支援localhost網域名稱。

執行自定義登入檔

準備好組態檔案、htpasswd檔案和自簽名證書後,我們可以執行自定義的登入檔容器:

# podman run -d --name local_registry \
  -p 5000:5000 \
  -v $PWD/htpasswd:/var/lib/htpasswd:z \
  -v $PWD/config.yml:/etc/docker/registry/config.yml:z \
  -v /var/lib/registry:/var/lib/registry:z \
  -v $PWD/certs:/etc/pki/certs:z \
  --restart=always \
  registry:2

內容解密:

  1. 使用podman run命令執行登入檔容器,並對映必要的埠和卷。
  2. 載入自定義組態檔案、htpasswd檔案、證書和私鑰。
  3. 設定容器始終重啟,以確保服務連續性。

登入和測試登入檔

登入到登入檔:

$ skopeo login -u admin -p p0dman4Dev0ps# --tls-verify=false localhost:5000

內容解密:

  1. 使用skopeo login命令登入到登入檔。
  2. 指定使用者名稱、密碼和登入檔URL,並跳過TLS驗證。

測試刪除影像:

$ skopeo delete --tls-verify=false docker://localhost:5000/minimal_httpd

內容解密:

  1. 使用skopeo delete命令刪除指定的影像。
  2. 跳過TLS驗證以避免證書驗證錯誤。

映象同步與垃圾回收

使用本地登入檔可以映象外部公共登入檔的影像。透過skopeo sync命令,可以實作影像的同步:

$ skopeo sync --src yaml --dest docker --dest-tls-verify=false kube_sync.yaml localhost:5000

內容解密:

  1. 使用skopeo sync命令同步影像。
  2. 指定源為YAML檔案,目標為Docker登入檔,並跳過TLS驗證。

當檔案系統空間不足時,需要進行垃圾回收。刪除影像後,需要執行垃圾回收命令以釋放空間。

容器故障排除與監控

執行容器只是 DevOps 團隊旅程的第一步,確保容器正常運作是系統管理員和 DevOps 團隊的重要任務。在容器管理活動中,具備適當的故障排除技術知識有助於將對最終服務的影響降至最低,減少停機時間。監控容器以便快速攔截任何問題或錯誤,從而加速還原。

技術需求

在進行本章內容和範例之前,需要一台具有正常運作的 Podman 安裝的機器。如同第三章「執行第一個容器」所述,本文中的所有範例都在 Fedora 34 系統或更新版本上執行,但可以在您選擇的作業系統上重現。熟悉第四章「管理執行中的容器」和第五章「為容器的資料實作儲存」的內容,將有助於輕鬆理解與容器登入相關的概念。

故障排除執行中的容器

故障排除容器是一項重要的實踐,需要經驗來解決常見問題並調查在容器層或容器內執行的應用程式中可能遇到的任何錯誤。從第三章開始,我們使用基本的 Podman 命令來執行和檢查主機系統上的容器。我們瞭解瞭如何使用 podman logs 命令收集日誌,以及如何使用 podman inspect 命令提供的資訊。最後,我們還應該考慮檢視有用的 podman system df 命令的輸出,該命令將報告容器和映像的儲存使用情況,以及有用的 podman system info 命令,該命令將顯示執行 Podman 的主機上的有用資訊。

一般來說,我們應該始終認為執行中的容器只是主機系統上的一個行程,因此我們始終擁有所有可用工具和命令來進行底層作業系統及其可用資源的故障排除。容器故障排除的最佳實踐可以是自上而下的方式,首先分析應用程式層,然後移動到容器層,最後到底層主機系統。

檢查容器日誌

檢查容器日誌是故障排除的第一步。可以使用 podman logs 命令來檢視容器的日誌輸出。

podman logs -f <container_id>

使用 podman inspect 進行詳細檢查

podman inspect 命令提供了有關容器的詳細資訊,包括其組態、網路設定和掛載卷等。

podman inspect <container_id>

使用 podman system df 檢查儲存使用情況

podman system df 命令報告了容器和映像的儲存使用情況,有助於識別儲存相關的問題。

podman system df

使用 podman system info 取得主機資訊

podman system info 命令顯示了執行 Podman 的主機上的有用資訊,包括儲存驅動程式、作業系統版本等。

podman system info

使用健康檢查監控容器

Podman 提供了健康檢查功能,可以定期檢查容器的健康狀態。可以在 Dockerfile 中使用 HEALTHCHECK 指令來定義健康檢查。

HEALTHCHECK --interval=1m --timeout=3s --retries=3 \
  CMD curl -f http://localhost:8080/health || exit 1

健康檢查的設定與解說

  • --interval=1m:每隔1分鐘執行一次健康檢查。
  • --timeout=3s:健康檢查的超時時間為3秒。
  • --retries=3:如果健康檢查失敗,重試3次。
  • CMD curl -f http://localhost:8080/health || exit 1:使用 curl 命令檢查 http://localhost:8080/health 是否傳回成功狀態碼,若失敗則離開並傳回非零狀態碼。

檢查容器構建結果

檢查容器構建結果有助於識別構建過程中可能出現的問題。可以使用 podman build 命令的輸出來進行檢查。

podman build -t myimage .

使用 nsenter 進行進階故障排除

nsenter 命令允許使用者進入容器的名稱空間,從而可以對容器內部的行程進行除錯。

nsenter -t <container_pid> -n ip addr show

使用 nsenter 的步驟與解說

  1. 首先,需要找到容器的 PID。可以使用 podman inspect 命令來取得。
    podman inspect --format '{{.State.Pid}}' <container_id>
    
  2. 然後,使用 nsenter 命令進入容器的網路名稱空間,並執行所需的命令。例如,檢視容器的網路介面資訊。
    nsenter -t <container_pid> -n ip addr show
    
    • -t <container_pid>:指定要進入的名稱空間所屬的行程 PID。
    • -n:進入網路名稱空間。

容器執行疑難排解 303:儲存磁碟區許可權問題

在 RHEL、Fedora 或任何使用 SELinux 安全子系統的 Linux 發行版上進行活動時,我們可能會遇到與儲存許可權相關的問題。當 SELinux 設定為 Enforcing 模式時(也是建議用於完全保證 SELinux 的強制存取安全功能的模式),會觸發以下錯誤。

我們可以在 Fedora 工作站上測試此問題,首先建立一個目錄,然後嘗試將其用作容器中的磁碟區:

$ mkdir ~/mycontent
$ podman run -v ~/mycontent:/content fedora touch /content/file
touch: cannot touch '/content/file': Permission denied

如我們所見,touch 命令報告了 Permission denied 錯誤,因為它無法寫入檔案系統。

SELinux 標籤與容器存取控制

正如我們在第 5 章《實作容器資料儲存》中詳細討論的那樣,SELinux 遞迴地將標籤套用到檔案和目錄,以定義其上下文。這些標籤通常儲存為擴充套件的檔案系統屬性。SELinux 使用上下文來管理策略,並定義哪些行程可以存取特定資源。

我們剛剛執行的容器獲得了自己的 Linux 名稱空間和 SELinux 標籤,該標籤與 Fedora 工作站中的本地使用者完全不同,這就是為什麼我們之前遇到了錯誤。

如果沒有適當的標籤,SELinux 系統會阻止容器中的行程存取內容。這也是因為 Podman 不會更改由 OS 設定的標籤,除非透過命令選項明確請求。

使用 Podman 更改容器標籤

要讓 Podman 更改容器的標籤,我們可以使用 :z:Z 字尾來掛載磁碟區。這些選項告訴 Podman 重新標記磁碟區上的檔案物件。

  • :z 選項用於指示 Podman,兩個容器共用一個儲存磁碟區。因此,在這種情況下,Podman 將使用共用內容標籤標記內容,這將允許兩個或多個容器讀取/寫入該磁碟區上的內容。
  • :Z 選項用於指示 Podman 使用私有未共用標籤標記磁碟區的內容,該標籤只能由目前容器使用。

正確使用 :Z 選項的範例

$ podman run -v ~/mycontent:/content:Z fedora touch /content/file

如我們所見,該命令沒有報告任何錯誤;它成功執行了。

無根容器中的 ping 命令問題

在某些強化的 Linux 系統上,ping 命令的執行可能僅限於受限制的使用者群組。這可能會導致容器中使用的 ping 命令失敗。

ping_group_range 核心引數

在 Fedora 工作站安裝中,預設組態將允許任何容器執行 ping 命令,而不會出現問題。要管理對 ping 命令的使用限制,Fedora 使用 ping_group_range 核心引數,該引數定義了允許執行 ping 命令的系統群組。

$ cat /proc/sys/net/ipv4/ping_group_range
0 2147483647

如果範圍小於此值,我們可以透過簡單的命令更改允許的範圍。在此範例中,我們將限制範圍,並檢視 ping 命令是否實際上會失敗:

$ sudo sysctl -w "net.ipv4.ping_group_range=0 0"

為了使變更持久化,我們可以在 /etc/sysctl.d 中新增一個檔案,其中包含 net.ipv4.ping_group_range=0 0

建置包含 iputils 的 Fedora 映像

讓我們使用 Buildah 建置一個根據 Fedora 的映像,其中包含 iputils 套件(預設不包含):

$ container=$(buildah from docker.io/library/fedora) && \
buildah run $container -- dnf install -y iputils && \
buildah commit $container ping_example

測試 ping 命令

$ podman run --rm ping_example ping -W10 -c1 redhat.com
PING redhat.com (209.132.183.105): 56 data bytes
---
 redhat.com ping statistics 
---
1 packets transmitted, 0 packets received, 100% packet loss

在受限制的系統上執行時,該命令會產生 100% 的封包遺失,因為 ping 命令無法透過原始通訊端傳送封包。

重設 ping_group_range

請勿忘記在繼續下一個範例之前還原始的 ping_group_range。在 Fedora 上,可以使用以下命令還原預設組態:

$ sudo sysctl -w "net.ipv4.ping_group_range=0 2147483647"

並刪除在練習期間套用的任何持久化組態。

注意大型 UID/GID 的影響

對於透過 Dockerfile 建置的基礎容器映像,可能需要新增具有大 UID/GID 的新使用者。這將建立一個大型、稀疏的 /var/log/lastlog 檔案,並可能導致建置程式掛起。這與 Go 語言無法正確支援稀疏檔案有關,從而導致在容器映像中建立這個龐大的檔案。

稀疏檔案的特性

/var/log/lastlog 檔案是一個二進位且稀疏的檔案,包含有關使用者上次登入系統的時間資訊。稀疏檔案的明顯大小(由 ls -l 報告)大於實際磁碟使用量。稀疏檔案嘗試以更有效的方式使用檔案系統空間,將代表空區塊的中繼資料寫入磁碟,而不是應該儲存在區塊中的空空間。這將使用較少的磁碟空間。