要同時跑多個容器服務,我們通常會寫一個docker-compose.yml
,將每個服務的屬性都定義好,然後透過docker compose up
指令啟動。
在Podman,要達成這個作法,有兩種方式:
- podman-compose:相容docker-compose的指令,用法類似,幾乎是一條
podman compose up
就能轉換過來。 - Podman Quadlets:將docker-compose的內容修改為符合Systemd服務檔,將Pomand容器服務變成Systemd服務的概念。這已經跟原本的docke-compose的yaml是不同語言了,需要自行改寫成Systemd語法。
本文Ivon討論第二種,以Podman Quadlets來跑多個服務的作法,將docker-compose.yml轉換到Podman Quadlets。
據說Podman Quadlets的名字來源是將Kubernetes切成兩半,由8變成4,也就是扁平化後的Kubelet。意思是試圖用Systemd簡化管理容器的程序。
RedHat公司在官網部落格介紹了許多Podman Quadlets的好處,不過沒有很詳細的文件說明,因此Ivon決定研究一番。
Docker compose的另一種形式概念就是Podman Quadlets,跳脫了從單一yaml啟動全部服務的作法,而非全部交由一個Docker的daemon去管,透過daemonless的特性迴避單點故障。Quadlets讓Podman容器與Linux系統融合,方便以systemctl指令管理,這樣能夠更靈活的處理服務之間的依賴關係,還能設定開機自動在特定的target之後跟著啟動Podman容器服務。
依照Quadlets的概念,如果一個docker-compose.yml
檔案有多個容器服務,則他們會被拆分成多個Systemd的服務檔(servcie unit)。一個服務檔裡面定義該容器的配置還有網路設定,還有依賴哪個容器才能啟動的關係。
yaml跟Systemd的格式根本不同,要將規則手動轉換感覺好麻煩喔?所幸我們有一個叫做「Podlet」的工具能夠自動轉換。它會讀取docker-compose.yml,並生成Systemd服務檔。這對於遷移現有的docker-compose十分有幫助。
1. 安裝Podlet#
以Ubuntu來說,尚未收錄Podlet安裝套件,所以就直接從Github下載二進位檔,解壓縮放到/usr/bin/local/
wget https://github.com/containers/podlet/releases/download/v0.3.0/podlet-x86_64-unknown-linux-gnu.tar.xz
tar -xvf podlet-x86_64-unknown-linux-gnu.tar.xz
chmod +x podlet-x86_64-unknown-linux-gnu/podlet
sudo mv podlet-x86_64-unknown-linux-gnu/podlet /usr/bin/local/podlet
2. 將docker-compose.yml轉成Quadlets#
- 指令用法:
podlet [選項] [指令]
podlet允許根據映像檔、容器、容器網路,還有docker-compose.yml產生對應的Systemd service unit。
這裡我們只使用轉換docker-compose.yml的指令。將一份docker-compose.yml放置到目前的工作目錄:
mkdir -p ~/apache/html
vim docker-compose.yml
- 填入一個簡單的Apache容器服務範本
services:
web: # 這個名稱將會成為.container服務檔名稱
image: docker.io/library/httpd:latest
ports:
- "80:80"
volumes:
- /home/user/apache/html:/usr/local/apache2/htdocs/
- 開始轉換,Podlet會檢查不相容的部份並給出警告。如果只有一個容器,就只會建立一個
.container
檔案。多個服務就會自動拆成多個。
# 自動建立.container的服務檔,並允許開機自動啟動
podlet -u -i compose
# 只輸出服務檔寫法,不建立檔案
podlet compose
- Podman預設應該會將
.container
檔案放到~/.config/containers/systemd/
,所以要重新載入Systemd
systemctl --user daemon-reload
- 然後,以systemctl啟動Podman容器。Podman Quadlet沒辦法用
docker compose pull
拉取容器,所以得讓它自動拉。
systemctl --user start web
- 要設定開機自動啟動就是這樣:
systemctl --user enable web
- 我們可以同時用podman以及systemctl的相關指令來操控這個容器。
systemctl --user status web
podman ps
3. 一些Quadlets的注意事項#
在轉換docker-comose.yml前需要注意:使用的映像檔鍵值
image:
要寫出完整網址。例如image: docker.io/library/httpd:latest
。不然Podmand會不知道從哪裡拉取映像檔。關於Quadlets的服務檔,應該要放在
/etc/containers/systemd/
還是~/.config/containers/systemd/
?Podlet預設是選擇後者,加強安全性,不過rootless容器可能會有一些權限問題,需要特權容器的話在.container檔加入PodmanArgs=--privileged
。預設rootful的容器才放到/etc/containers/systemd/
。使用者登出的時候,Podman容器可能會跟著被停止。要登出後仍繼續執行容器服務,使用這個指令:
loginctl enable-linger <使用者名稱>
- 對於rootless的Podman容器來說,需要使用
net.ipv4.ip_unprivileged_port_start
才可以存取1024以下的通訊埠:
echo "net.ipv4.ip_unprivileged_port_start=80" | sudo tee -a /etc/sysctl.conf
sudo sysctl -p
Podman每個容器之間的網路是彼此隔離的,如果兩個容器之間依賴Docker內部的DNS通訊(例如需要存取資料庫),你可能要寫一個Pod,或者建立一個Podman Network,將兩個容器使用同一個Network Namespace,容器之間才能連線。
有時候你會覺得與其依賴Podlet轉換,還不如自己根據docker-compose.yml的邏輯,自行重寫Systemd服務檔。
4. 多容器實際操作案例:將Immich以Quadlets部署#
目前Immich官方尚未有關於Podman的安裝指示,只有docker-compose.yml。它定義了4個容器服務,這正好適合測試一下Quadlets。
以下內容參考自jbtrystram/immich-podman-systemd,測試當下版本是v137.3。注意我是手動轉的,不想知道原理的可以直接用上面的版本。
- 放置.container的目錄可以針對每個Quadlets新增一個目錄,這樣就能放環境變數檔案。
mkdir ~/.config/containers/systemd/immich
cd ~/.config/containers/systemd/immich
- 將Immich官方提供的docker-compose.yml轉換為Quadlets,存在目前目錄。因為Immich的docker-compose.yml使用了環境變數,所以會轉換失敗,要手動刪掉
$
開頭的環境變數的部份。
wget -O docker-compose.yml https://github.com/immich-app/immich/releases/latest/download/docker-compose.yml
podlet -f -i compose
- 新增環境變數檔案,在immich.env裡面填入偏好的設定
wget -O immich.env https://github.com/immich-app/immich/releases/latest/download/example.env
- 因為容器之間需要通訊,得共享網路,新增一個Pod檔案
~/.config/containers/systemd/immich/immich.pod
,填入以下內容
[Pod]
PodName=immich
PublishPort=2283:2283
環境變數是含有Immich主服務的容器要讀取的,故編輯
~/.config/containers/systemd/immich/immich-server.container
,填入EnvironmentFile=immich.env
。在所有的
.container
檔案裡面填入[Containers]Pod=immich.pod
代表它們從屬於Immich Pod。修正剩下.container檔案裡面的volume路徑。
透過Pod啟動全部的Immich服務,它應該會將依賴的服務一併拉起來
systemctl --user start immich-pod
systemctl --user start immich-server
5. 用圖形界面管理Quadlets服務#
這樣講有點怪,應該沒有人想用圖形介面管理Linux的Systemd服務的吧?大部分都是用指令編輯,但就是有這種需求。桌面方案有Systemd Pilot,網頁有Cockpit的方案,OpenSUSE用戶可以嘗試YaST。
專門為Podman設計的Podman Desktop更是有專門的編輯選項。安裝完Quadlets的擴充套件後,就能列出Linux系統上的各個Pod狀況。
這樣一來,Podman Desktop圖形介面就能協助管理系統上的容器服務。只不過Quadlets的作法就變成更Linux-orientedㄌ,畢竟需要Systemd,對在其他作業系統跑容器服務的用戶來說可能會多一些學習成本。