Podman 作為無守護行程的容器引擎,其 API 與系統服務的整合至關重要。本文除了介紹如何設定 Podman API 服務外,也說明瞭如何利用 systemd 管理 Podman 服務,確保服務的穩定性和可靠性。同時,文章也涵蓋了容器網路組態的檢查,包含路由表檢視和連線測試,以及如何透過埠對映將容器服務暴露給外部網路。最後,文章也示範了容器生命週期管理的常用指令,例如如何從執行中的容器分離,方便開發者和系統管理員進行容器操作。
組態你的環境
正如我們之前提到的,Podman 是一個無守護程式的容器管理器,它不需要背景服務來執行容器。然而,使用者可能需要與 Podman 公開的 Libpod API 互動,特別是在從根據 Docker 的環境遷移時。
Podman 可以透過 UNIX 通訊端(預設行為)或 TCP 通訊端公開其 API。後者選項安全性較低,因為它使 Podman 可以從外部存取,但在某些情況下是必要的,例如當它應該被 Windows 或 macOS 工作站上的 Podman 使用者端存取時。
重點注意事項
在暴露於網際網路的機器上使用 TCP 端點執行 API 服務時要小心,因為該服務將全域可存取。
以下命令在 UNIX 通訊端上公開 Podman API:
$ sudo podman system service --time=0 \
unix:///run/podman/podman.sock
執行此命令後,使用者可以連線到 API 服務。
內容解密:
此命令的作用是啟動 Podman 的系統服務,並將其組態為透過 UNIX 通訊端 /run/podman/podman.sock 提供 API 服務。 --time=0 表示服務將持續執行,直到手動停止。
在終端機視窗上執行此命令並不是一個方便的方法。相反,最佳方法是使用 systemd 通訊端(參見 man systemd.socket)。
systemd 中的通訊端單元是一種特殊的服務啟動器:當請求到達通訊端的預定義端點時,systemd 立即啟動同名的服務。
安裝 Podman 時,會建立 podman.socket 和 podman.service 單元檔案。 podman.socket 的內容如下:
# cat /usr/lib/systemd/system/podman.socket
[Unit]
Description=Podman API Socket
Documentation=man:podman-system-service(1)
[Socket]
ListenStream=%t/podman/podman.sock
SocketMode=0660
[Install]
WantedBy=sockets.target
內容解密:
此組態定義了一個名為 podman.socket 的通訊端單元,監聽 /run/podman/podman.sock 上的連線請求,並設定通訊端的許可權模式為 0660。
podman.service 的內容如下:
# cat /usr/lib/systemd/system/podman.service
[Unit]
Description=Podman API Service
Requires=podman.socket
After=podman.socket
Documentation=man:podman-system-service(1)
StartLimitIntervalSec=0
[Service]
Type=exec
KillMode=process
Environment=LOGGING="--log-level=info"
ExecStart=/usr/bin/podman $LOGGING system service
[Install]
WantedBy=multi-user.target
內容解密:
此組態定義了一個名為 podman.service 的服務單元,它依賴於 podman.socket 單元。當 podman.socket 接收到連線請求時,systemd 將啟動 podman.service。 ExecStart 欄位指定了要執行的命令,即 podman system service 命令。
要啟用和啟動通訊端單元,請執行以下命令:
# systemctl enable --now podman.socket
我們可以使用簡單的 curl 命令測試結果:
# curl --unix-socket /run/podman/podman.sock \
http://d/v3.0.0/libpod/info
內容解密:
此命令透過 UNIX 通訊端 /run/podman/podman.sock 向 Podman API 傳送 HTTP 請求,以取得容器引擎的組態資訊。
列印的輸出將是一個 JSON 負載,其中包含容器引擎組態。
當我們存取該 URL 時,底層發生了什麼?當連線請求發出時,服務單元立即由通訊端觸發啟動。有些人可能會注意到第一次執行命令時有輕微的延遲(大約十分之一秒)。
在 5 秒鐘的不活動後,podman.service 將再次停用。這是由於 podman system service 命令的預設行為,除非傳遞 --time 選項以提供不同的超時時間(值為 0 表示永久)。
自訂 Podman 的行為(可選)
Podman 的預設組態適用於大多數使用案例,但其組態具有很高的靈活性。以下組態檔案可用於自定義其行為:
containers.conf:此 TOML 格式的檔案包含 Podman 執行時組態,以及 conmon 和容器執行時二進位制檔案的搜尋路徑。它預設安裝在/usr/share/containers/路徑下,可以被/etc/containers/containers.conf和$HOME/.config/containers/containers.conf檔案覆寫,用於系統範圍和使用者範圍的設定。storage.conf:此 TOML 格式的檔案用於自定義容器引擎使用的儲存設定。特別是,此檔案允許您自定義預設儲存驅動程式,以及容器儲存的讀寫目錄(也稱為圖形根目錄),這是額外的驅動程式儲存選項。預設情況下,驅動程式設定為 overlay。
內容解密:
這些組態檔案可以用來自定義 Podman 的行為,例如日誌記錄、DNS 解析、環境變數、分享記憶體使用、Cgroup 管理等。使用者可以根據自己的需求修改這些組態檔案,以實作自定義的容器管理。
執行第一個容器
在前一節中,我們探討瞭如何在您偏好的 Linux 發行版上安裝 Podman,以及安裝後的基本套件內容。現在,我們可以開始使用這個無需守護程式的容器引擎。
Podman 的基本組態
在執行第一個容器之前,瞭解 Podman 的一些基本組態是非常有用的。這些組態包括使用者層級的設定,這些設定會影響無根(rootless)容器的行為。使用者層級的組態檔案位於 $XDG_CONFIG_HOME/containers/storage.conf 或 $HOME/.config/containers/storage.conf。
此外,還有一些其他重要的組態檔案:
mounts.conf:定義了在啟動容器時自動掛載的卷標。這對於將金鑰和憑證等秘密自動傳遞到容器內非常有用。預設路徑是/usr/share/containers/mounts.conf,可以透過位於/etc/containers/mounts.conf的檔案進行覆寫。在無根模式下,覆寫檔案可以放置在$HOME/.config/containers/mounts.conf。seccomp.json:這是一個 JSON 檔案,允許使用者自定義容器內行程允許執行的系統呼叫,並定義被阻止的系統呼叫。這個主題將在第 11 章「容器安全」中再次討論,以提供對容器安全約束的更深入理解。該檔案的預設路徑是/usr/share/containers/seccomp.json。seccomp手冊頁(man seccomp)提供了關於 seccomp 在 Linux 系統上如何運作的概述。policy.json:這是一個 JSON 檔案,定義了 Podman 如何執行簽名驗證。該檔案的預設路徑是/etc/containers/policy.json,可以透過使用者層級的$HOME/.config/containers/policy.json進行覆寫。這個組態檔案接受三種策略:
insecureAcceptAnything:接受來自指定註冊中心的任何映像。reject:拒絕來自指定註冊中心的任何映像。signedBy:只接受由特定已知實體簽名的映像。
預設組態是接受每個映像(
insecureAcceptAnything策略),但可以修改為只提取可透過簽名驗證的受信任映像。使用者可以定義自定義 GPG 金鑰來驗證簽名和簽署它們的身分。有關可能的策略和組態範例的更多詳細資訊,請參閱相關的手冊頁(man containers-policy.json)。
執行第一個容器
現在,是時候執行我們的第一個容器了。
在 Podman 中,執行容器的操作是透過 podman run 命令處理的,該命令接受許多選項來控制剛執行的容器的行為、隔離、通訊、儲存等。
執行一個全新的容器的最簡單和最短的 Podman 命令如下:
$ podman run <imageID>
我們必須用想要執行的映像名稱/位置/標籤替換 imageID 字串。如果映像不在快取中,或者我們之前沒有下載過,Podman 將為我們從相應的容器註冊中心提取映像。
互動式和偽終端
為了介紹這個命令及其選項,讓我們從簡單的開始,執行以下命令:
$ podman run -i -t fedora /bin/bash
輸出結果如下:
Resolved "fedora" as an alias (/etc/containers/registries.conf.d/000-shortnames.conf)
Trying to pull registry.fedoraproject.org/fedora:latest...
Getting image source signatures
Copying blob ecfb9899f4ce done
Copying config 37e5619f4a done
Writing manifest to image destination
Storing signatures
[root@ec444ad299ab /]#
讓我們看看 Podman 在我們執行前面的命令後做了什麼:
- 它識別出映像名稱
fedora是最新 Fedora 容器映像的別名。 - 然後,它意識到映像在本地快取中缺失,因為這是我們第一次嘗試執行它。
- 它從正確的註冊中心下載映像。它選擇了 Fedora Project 註冊中心,因為它與註冊中心組態中的別名相匹配。
- 最後,它啟動了容器,並為我們提供了一個互動式 shell,執行我們請求的 Bash shell 程式。
前面的命令提示了一個互動式 shell,這得益於我們可以分析的兩個選項:
--tty, -t:使用此選項,Podman 分配一個偽終端(見man pty),並將其附加到容器的標準輸入。--interactive, -i:使用此選項,Podman 保持 stdin 開啟並準備好附加到前面的偽終端。
#### 內容解密:
-i和-t選項用於啟動一個互動式的容器 shell。-i確保容器的 stdin 保持開啟,而-t為容器分配一個偽終端,使得我們能夠與容器內的 shell 進行互動。- 當容器被建立時,其內的隔離行程將執行在一個可寫入的根檔案系統上,這是由層疊覆寫(layered overlay)實作的。這允許任何行程寫入檔案,但別忘了這些變更只會持續到容器執行為止,因為容器預設是短暫的。
- 在互動式 shell 中,我們可以執行任何命令並檢查其輸出,如安裝
iputils和iproute軟體包的範例所示。
在互動式 Shell 中執行命令
現在,您可以在我們剛剛開啟的控制檯中執行任何命令並檢查其輸出:
[root@ec444ad299ab /]# dnf install -y iputils iproute
輸出結果如下:
Last metadata expiration check: 0:01:50 ago on Mon Sep 13 08:54:20 2021.
Dependencies resolved.
================================================================================
Package Architecture Version Repository Size
================================================================================
Installing:
iproute x86_64 5.10.0-2.fc34 fedora 679 k
iputils x86_64 20210202-2.fc34 fedora 170 k
#### 內容解密:
- 在容器內執行
dnf install命令來安裝所需的軟體包,如iputils和iproute。 dnf是 Fedora 系統上的軟體包管理器,用於安裝、更新和管理軟體包。- 安裝過程中,
dnf解析依賴關係並下載必要的軟體包進行安裝。 - 安裝完成後,這些軟體包將可用於在容器內進行網路相關的操作和測試。
執行第一個容器
安裝依賴與網路組態檢查
在前面的例子中,我們安裝了兩個套件來檢查容器的網路組態。首先,進入容器後,我們執行了 ip r 命令來檢視路由表:
[root@ec444ad299ab /]# ip r
default via 10.0.2.2 dev tap0
10.0.2.0/24 dev tap0 proto kernel scope link src 10.0.2.100
內容解密:
default via 10.0.2.2 dev tap0:表示預設路由是透過tap0網路介面將流量導向10.0.2.2。10.0.2.0/24 dev tap0 proto kernel scope link src 10.0.2.100:表示10.0.2.0/24網段直接連線在tap0網路介面上,且本機的 IP 地址是10.0.2.100。
接著,我們使用 ping 命令測試與預設路由器的連線:
[root@ec444ad299ab /]# ping -c2 10.0.2.2
PING 10.0.2.2 (10.0.2.2) 56(84) bytes of data.
64 bytes from 10.0.2.2: icmp_seq=1 ttl=255 time=0.030 ms
64 bytes from 10.0.2.2: icmp_seq=2 ttl=255 time=0.200 ms
---
10.0.2.2 ping statistics
---
2 packets transmitted, 2 received, 0% packet loss, time 1034ms
rtt min/avg/max/mdev = 0.030/0.115/0.200/0.085 ms
內容解密:
ping -c2 10.0.2.2:傳送兩個 ICMP 請求到10.0.2.2。- 結果顯示兩個請求都成功收到回應,丟包率為 0%,證明網路連線正常。
從執行中的容器分離
使用 Podman 時,可以啟動一個互動式的容器並在稍後分離。首先,啟動一個容器:
$ podman run -i -t registry.fedoraproject.org/f29/httpd
內容解密:
-i:保持 STDIN 開啟,允許互動操作。-t:分配一個偽終端(pseudo-TTY),模擬一個終端介面。
要從容器分離,按下 Ctrl + P 和 Ctrl + Q:
[Tue Sep 14 09:26:05.755346 2021] [core:notice] [pid 1:tid 140416655523200] AH00094: Command line: ‘httpd -D FOREGROUND’
內容解密:
- 這條命令讓 Apache HTTP Server 以前景模式執行。
- 使用
Ctrl + P和Ctrl + Q分離後,容器繼續在背景執行。
網路埠對映
Podman 提供 -p 選項來進行埠對映,將容器內的埠對映到主機的埠:
$ podman run -p 8080:8080 -d -i -t registry.fedoraproject.org/f29/httpd
內容解密:
-p 8080:8080:將容器內的 8080 埠對映到主機的 8080 埠。-d:以分離模式執行容器。
檢視容器的埠對映:
$ podman port fc9d97642801
8080/tcp -> 0.0.0.0:8080
內容解密:
- 這表示將容器的 8080/tcp 埠對映到主機的所有 IP 地址上的 8080 埠。
測試埠對映是否成功:
$ curl –s 127.0.0.1:8080 | head
內容解密:
- 使用
curl命令存取http://127.0.0.1:8080,並顯示前幾行回應內容。