8. podman -- 使用 systemd 来管理某个容器


 

通过 systemd 来管理容器,

  • 并非是让 systemd 来管理 podman 这个程序的 start,stop,...,而是让 systemd 来管理某个容器的 start,stop,...

  • 实现某个容器需要在开机的时候自动运行,

  • 实现某个容器通过 systemctl start 来启动,systemctl stop 来删除

 

1. podman generate 的帮助文档

systemd 的时候说过,可以自定义 unitservice 之类,

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 能生成 systemdunit 文件,另外一个是 k8sYAML 文件,很明显,此处应该使用

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 就会直接在当前目录生成文件。

  • 同样,也不接受参数

  • 因为是当前目录下生成,因此需要 copysystemd 的目录下,

(/etc/systemd/system/xxxx 通常是 /usr/lib/systemd/system/xxxx 的链接)

 
修改如上的例子:

 

 

如上,

(1)运行一个名为 test-thhp 的容器

(2)切换到 systemd 目录,生成配置文件的时候使用了 --files 参数,当前目录下也出现了预期的文件。

podman stop 该容器,紧接着 systemctl startps 能看到容器的状态为 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-reloadreload 是重载指定的服务,如 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 中,访问依旧正常

posted @ 2021-11-01 00:34  牛顿撕鸡  阅读(2631)  评论(0编辑  收藏  举报