
通過 systemd
來管理容器,
-
並非是讓
systemd
來管理podman
這個程序的 start,stop,...,而是讓systemd
來管理某個容器的 start,stop,... -
實現某個容器需要在開機的時候自動運行,
-
實現某個容器通過
systemctl start
來啟動,systemctl stop
來刪除
1. podman generate 的幫助文檔
systemd
的時候說過,可以自定義 unit
、service
之類,
在 podman
中,通過下面的命令,將某個容器加入到 systemd
的管理范圍
podman generate
Generate structured data based on containers, pods or volumes
man podman-generate
┌────────┬─────────────────────────┬────────────────────────────────────┐
│Command │ Man Page │ Description │
├────────┼─────────────────────────┼────────────────────────────────────┤
│kube │ podman-generate-kube │ Generate Kubernetes YAML based on │
│ │ │ containers, pods or volumes. │
├────────┼─────────────────────────┼────────────────────────────────────┤
│systemd │ podman-generate-systemd │ Generate systemd unit file(s) for │
│ │ │ a container or pod. │
└────────┴─────────────────────────┴────────────────────────────────────┘
podman generate
能生成 systemd
的 unit
文件,另外一個是 k8s
的 YAML
文件,很明顯,此處應該使用
man podman-generate-systemd
podman generate systemd
Generate systemd unit file(s) for a container or pod
2. --name 選項
Use the name of the container for the start, stop, and description in the unit file
也就是說,這個選項並不是接受一個參數,來作為服務的名字,
而是使用容器的名字按照規則來命名 unit,
對於容器來說,命名規則是:
container-name.service
或者是 container-id.service
也就是說,如果容器名為 test
,那么配置完成后就是 systemctl start container-test.service
當然也可以通過下面參數來修改 unit
名的前綴
--container-prefix string
Systemd unit name prefix for containers (default "container")
例子:
如上,
首先(1)運行一個名為 test_http
的容器,
其次(2)通過 generate
生成能被 systemd
管理的 unit
的配置文件
如上描述,該 unit
的名字為 前綴 container
和 容器名的組合
3. --files
至此,雖然已經有了給出的配置文件,但后續還需要自己寫入指定的位置總是麻煩,
可以通過 --files | -f 參數來完成:
Generate files instead of printing to stdout.
The generated files are named container-name.service 或者是 container-id.service and will be placed in the current working directory.
-
默認情況下,會將生成內容打印再屏幕上,上圖的樣子;使用
-f
就會直接在當前目錄生成文件。 -
同樣,也不接受參數
-
因為是當前目錄下生成,因此需要
copy
到systemd
的目錄下,
(/etc/systemd/system/xxxx 通常是 /usr/lib/systemd/system/xxxx 的鏈接)
修改如上的例子:
如上,
(1)運行一個名為 test-thhp 的容器
(2)切換到 systemd 目錄,生成配置文件的時候使用了 --files
參數,當前目錄下也出現了預期的文件。
podman stop
該容器,緊接着 systemctl start
,ps
能看到容器的狀態為 Up
(3)systemctl stop
,發現容器的狀態為 Exited
4. --new
關於這個參數,先看實例
如上,
(2)中生成 systemd 配置文件的時候,多了一個 --new
(3)差別在於 systemctl stop
的時候,podman ps -a
查看,容器已經被刪除,
而上個例子中,沒有 --new
選項,systemctl stop
的時候,容器是 Exited
5. 普通用戶來創建 systemd 管理的容器
5.1 問題
前面的示例都是在 root 用戶下進行的操作,
但是不同用戶的 podman 操作都是隔離的,
前面說過,root 的 podman 有 httpd 這個鏡像,切換到 xyz 用戶的時候,那么就得重新下載這個鏡像了。
使用 systemd 來管理容器也有類似的情況
如上,
(1)通過 systemctl stop
刪除了容器
(2)切換到用戶 xyz,並 systemctl start
容器,
啟動后發現 podman ps -a
並不看到容器
(3)退出,切換到 root,發現(2)啟動的是 root 下的容器
在來例子:
如上,普通用戶的操作
(1)運行容器 t1
(2)切換到 systemd 目錄,試圖生成配置文件
但是遇到了紅框中的 permission denied,
使用 sudo 的時候,又說找不到 t1 這個容器,即使 t1 是 Up 的,
因為 sudo 了,那自然身份就是 root,root 就找不到 xyz 的 t1 這個容器
5.2 解決
運行 systemctl 的時候,有兩種模式
-
--system (系統級別,默認,因此平時都不寫這個選項)
-
--user 用戶級別
此處就是使用用戶級別來解決這個問題
用戶級別 systemd 的目錄:
-
/usr/lib/systemd/user/ 優先級低
-
/etc/systemd/user/ 里面的文件也是上面這個鏈接
-
~/.config/systemd/user/ 優先級最高
-
~/.local/share/systemd/user/

如上,
(1)(2)正常的啟動服務,生成配置文件
到(3)的時候
-
需要重新加載 unit,因此使用
daemon-reload
。reload
是重載指定的服務,如apache
重載自己的配置,和daemon-reload
是不一樣的。 -
對於 su - xyz 的方式,能順利創建 配置文件,但是在加載服務的時候會報錯
https://access.redhat.com/discussions/6029491
Make sure that you aren't working in a 'sudo' or 'su' session.
The command only works when ssh-ing into your system or logging in to console.
因此,通過 ssh 的方式重開一個終端,進行 daemon-reload
的操作,
-
注意這些操作都不要忘記
--user
-
操作沒錯,遇到問題,看看是不是 su - 的方式切換用戶,使用 ssh
繼續:
如上,
(4)手動刪除掉 t1 這個容器
(5)通過 systemctl --user 來啟動,停止 t1 這個容器
6. loginctl
6.1 問題
對於 --system 的服務來說,
enable 的服務會在系統啟動時啟動,系統關閉時停止。
而 --user 的服務(非 root 用戶的情況下),有說:
當打開會話的時候,服務會自動啟動,
但是當所有會話都關閉的時候,服務會自動停止
(服務時伴隨會話啟停,而非伴隨系統啟停)
舉個下面這個例子來測試:
運行一個 http 容器 ,宿主機 8000 端口(server1:8000)映射到 容器的 80,
配置 --user 級別的 systemd 來管理,
在 active 的狀態下,退出所有宿主機 server1 的會話,
從另一主機 server2 訪問 server1:8000,
如果如上所說的話,那么應該訪問失敗。
測試如下:
如上:
(1)運行容器 http-server,並映射本地 8000 端口到容器的 80 端口,測試訪問宿主機上的 8000 端口,訪問成功
(2)生成 systemd 的配置文件,並重載 --user 級別的 unit
(是需要 ssh 之類的操作到 containers 用戶,而非 su - containers)
如上,systemctl start/enable 來管理這個容器

如上,因為測試是要訪問宿主機 server1 的 8000 端口,
所以需要在 server1 中,root 狀態下放行 8000 端口和 http 服務

如上,
退出了所有 server1 的會話,
ssh containers@server1 后查看到,容器是 active / up 的狀態,
此時,在 server2 中,訪問 server1:8000 端口,訪問正常
退出這最后一個會話,
再回到 server2 中,訪問 server1:8000,訪問失敗
- 由此,側面印證了,--user 級別的服務,退出所有會話后,服務自動停止
6.2 解決 -- loginctl
如果需要會話關閉后,服務也一直在運行(linger)
需要使用 loginctl enable-linger
loginctl enable-linger [USER...]
loginctl disable-linger [USER...]
If enabled for a specific user,
a user manager is spawned for the user at boot and kept around after logouts.
This allows users who are not logged in to run long-running services.
loginctl show-user USER

修改並測試

如上,
(1)enable-linger
(2)容器狀態為 active / up,
(3)server2 訪問正常;
退出 server1 的所有會話,
(4)和前面不一樣,雖然 server1 的所有會話都已經退出,但是 server2 中,訪問依舊正常