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启动服务发现问题¶
先说结果:和我想的不太一样,不能用老方法。
- 不能用系统服务配置以非root身份开启容器,会遇到一些crun运行环境问题。
- 即便解决了前述问题,crun仍会fallback cgroupfs(因为systemd)。
- 这也不是大问题,但是容器启动后service会挂掉,类似于用户登出带走了所有程序。
- 情况类似,就算登陆用户后手动直接启动的容器也会在登出后被停止。
我就不想把折腾再写一遍了 |ω・`)
这里就引出了几个问题:
- 以用户身份启动容器需要什么条件?
- 如何用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'
有不少有趣的东西哎:
- 一个compose相当于k8s里面的pod,这点我之前完全忽略了(生疏了)。
- 随系统启动的服务可以只用某个用户自己配置的服务。前提是
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啊增加心智负担 (ノ=Д=)ノ┻━┻