8. podman -- 使用 systemd 来管理某个容器
通过 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 中,访问依旧正常