podman使用及与systemd集成

Table of contents

曾经不喜欢docker而将podman视为替代。脱离docker依赖后又渐渐懒得用podman了。如今因为偷懒重拾podman,发现它成长超乎我想象,非常符合我现在部署各种服务的需求。

这里简单记录一下。

开端

部署Perplexica,实在不想往虚拟机环境里塞更多难以管理的环境了。项目提供的是docker,而我又不喜欢docker,于是重拾Podman,顺带学习一下。

不喜欢docker哪些点?

其实就一点:深度依赖守护进程。这引发了下列问题:

  • 临时修改配置很繁琐
  • 还是个root级别服务,不够安全
  • 重量级程序

懒到极致

podman-docker

太懒了,直接照抄docker的命令!用到podman-docker直接包裹podman、试图兼容docker命令行。目前来看podman发展下来并不想完全兼容docker命令行,不过多数命令的格式仍然相同。

但是选择这种非原生操作仍然会引入不确定因素。

podman-compose

podman-compose是第三方为podman编写的docker-compose。虽然和docker-compose有不少差异,但是主要功能类似。

podman-compose up -d,哎,服务就起来了。但是这里暗藏玄机,在后面会一一显现。

systemd集成

手搓systemd配置用podman compose启动服务发现问题

先说结果:和我想的不太一样,不能用老方法。

  1. 不能用系统服务配置以非root身份开启容器,会遇到一些crun运行环境问题。
  2. 即便解决了前述问题,crun仍会fallback cgroupfs(因为systemd)。
  3. 这也不是大问题,但是容器启动后service会挂掉,类似于用户登出带走了所有程序。
  4. 情况类似,就算登陆用户后手动直接启动的容器也会在登出后被停止。

我就不想把折腾再写一遍了 |ω・`)

这里就引出了几个问题:

  1. 以用户身份启动容器需要什么条件?
  2. 如何用systemd以用户身份启动容器?

在尝试过程中,发现日志里有提示:

The cgroupv2 manager is set to systemd but there is no systemd user session available
For using systemd, you may need to log in using a user session
Alternatively, you can enable lingering with: `loginctl enable-linger 1000` (possibly as root)
Falling back to --cgroup-manager=cgroupfs

看起来像是要维护一个session。linger又是什么?这个问题晚点再答。

尝试podlet(失败)

赶时间,所以在网上直接找podman、systemd集成的相关文章。其中就有讲到podlet。

因为compose配置文件不能完美兼容、现有pod使用了尚未支持的参数,podlet无法生成合适的服务配置。因而无法使用podlet。暂时搁置。

不过如果启用单个容器还是可以看看podlet的。

遵循podman-compose提示

在折腾途中,发现podman-compose有一个systemd指令,直接在perplexica的源码文件夹里执行看看:

Perplexica bash> podman-compose systemd      

you can use systemd commands like enable, start, stop, status, cat
all without `sudo` like this:

        systemctl --user enable --now 'podman-compose@perplexica'
        systemctl --user status 'podman-compose@perplexica'
        journalctl --user -xeu 'podman-compose@perplexica'

and for that to work outside a session
you might need to run the following command *once*

        sudo loginctl enable-linger 'user'

you can use podman commands like:

        podman pod ps
        podman pod stats 'pod_perplexica'
        podman pod logs --tail=10 -f 'pod_perplexica'

有不少有趣的东西哎:

  1. 一个compose相当于k8s里面的pod,这点我之前完全忽略了(生疏了)。
  2. 随系统启动的服务可以只用某个用户自己配置的服务。前提是 enable-linger

Note

按理从文档看应该要逐渐deprecate podman-compose,但是目前看来还是很好用的嘛!

systemd user service 简述

由systemd管理的Linux系统为每个用户提供了管理自己服务的方法,user instance。通过user instance,用户可以自行管理自己的user service。用户自定义的服务配置文件通常位于 $XDG_CONFIG_PATH/systemd/user,暂且忽略由系统提供的用户服务模板。

每次用户登陆(创建新会话)时,会创建一个systemd user instance并启动用户激活的服务。给几个现实中还算常见的例子:

  • 单用户下的pipewire守护进程
  • gpg-agent
  • appimagelauncherd
  • 代理服务,随用户登陆启动

可以读 ArchWiki 了解更多。

linger?

通常情况下,用户服务只会在用户创建首个活跃会话(也就是登陆)时自动启动,并在用户登出全部会话后自动停止。

这挺智能的不是吗?但是对于想使用专用非root用户、借由podman-compose启动容器的我来说是个问题。可能出于类似的原因,systemd自233版本后提供了 loginctl enable-linger

用户被标记linger后,其用户服务会随系统启动一并启动,并且不会因为用户登出而停止。

podman-compose与systemd集成

需要先装个服务模板,根据提示,以root用户执行执行下面一条命令:

podman-compose systemd -a create-unit

服务模板会写至 /etc/systemd/user/[email protected]

接着进一步根据提示,注册所需要的compose服务。在docker-compose.yaml所在位置执行命令注册服务(配置会被写入 $XDG_CONFIG_PATH/containers/compose/projects):

podman-compose systemd -a register

最后激活并启动服务,标记用户为linger

# 注意名称替换
systemctl --user enable --now 'podman-compose@perplexica'
# 下面的指令只需执行一次
sudo loginctl enable-linger "$USER"

之后可以重启机器验证一下容器是否正常启动。

探寻

podlet & quadlet

看起来使用quadlet是大势所趋,就想看看它到底是什么。

rootless是podman精华的一部分。但是podman没有daemon!它需要一个daemon维护容器启停,aka orchestrator。而这时的orchestrator可以是systemd,毕竟它已经管了一堆服务了。

systemd支持systemd-generator来更灵活地从其它配置文件生成systemd的服务配置。安装podman会同时安装一个generator配置,其会调用 quadlet 生成正确的systemd服务配置。quadlet并不在通常的可执行文件位置(*/bin之类),用户通常无需手动运行它。对于podman quadlet,generator会将quadlet配置转换为合适的systemd服务配置。

那podlet是干什么的?简单说它可以从现有的podman命令、compose文件、container或pod生成quadlet配置文件*.container 文件),丢进合适的位置重载后就能用啦。不过看起来podlet功能不甚完善,至少在compose场景下有很多不兼容之处。

一些小问题

容器连接宿主

对于docker,有个 host.docker.internal 用来连接宿主机。只不过需要配置一下 extra_hosts,增加 'host.docker.internal:host-gateway'

与docker类似,podman提供了 host.containers.internal 来连接宿主,而且不需要任何额外配置。迁移时需要注意。

如果服务认hostname,那还要格外注意呀!

结语

现在我部署服务大多在母机上开容器再手动配置环境、改写systemd配置文件,偶尔在必要的时候开个虚拟机。既然podman可以轻松与systemd集成,那未来向podman容器迁移也不错?用起来比nix简单不少,也有一定的reproducibility。

k8s?一个人用的私有云要什么k8s啊增加心智负担 (ノ=Д=)ノ┻━┻