podman-compose 折腾记
Contents
背景
我有一个非常简单的需求:在一个容器里起一个 wireguard client,并将其直接接入上游网络(不要 NAT)。
不想看过程可以直接看总结。
折腾
在容器里起 wireguard
首先搜索 prior art,发现 https://hub.docker.com/r/linuxserver/wireguard。试了一下发现不好:
- 这货是基于
ghcr.io/linuxserver/baseimage-ubuntu:bionic
的,巨大。 - 已经巨大了,它还安装
build-essential
等一堆东西。用完还不删。 - 它需要
SYS_MODULE
以及-v /lib/modules:/lib/modules
较为恐怖。我已配备新款内核自带有关模块。 - 它需要就地编译 wireguard,需要内核头文件。我用的正规系统它却找不到相关包裹。
wg-quick
走到net.ipv4.conf.all.src_valid_mark=1
那步的时候由于没有权限会失败(尽管有关 sysctl 已经满足)。- 自带了一个我不要的
coredns
。
于是研究了一下,发现这事在配备新款内核的 host 上其实很简单:
|
|
build 完 image 总共 16 MB,而 linuxserver/wireguard
有 400 MB+。
然后带上 --cap-add=NET_ADMIN --sysctl=net.ipv4.conf.all.src_valid_mark=1
起起来,发现好用。ping 不好使,可以加 --cap-add=NET_RAW
解决。
podman-compose:cap_add
不好使
发现好用后很快写了一个 docker-compose.yaml
用 podman-compose
起,发现不好。wg-quick
在创建 link
的时候会坏:RTNETLINK answers: **Operation not permitted**
。
怎么会这样呢???
搜索了一番发现 podman-compose #239,表示 cap_add / cap_drop 根本不管用。作者给出了相关代码的链接(由于没有锚定到相关 commit 现已刻舟求剑),原来 podman-compose
其实是个单文件 python 脚本,把 docker-compose.yaml
翻译成命令行。
于是打算去打 log 看看发生了什么,一看发现相关代码不存在。再一看发现 podman-compose
在 2019-09-03 和 2021-11-14 之间都没往 PyPI 上 release 过。pip3 install --upgrade podman-compose
解决。
podman-compose:podman network exists
不存在
升级完以后 podman-compose
开始调用 podman network exists
。然而好像没有这个命令。apt upgrade
一下发现已经是最新版本 3.0.1
。于是 blame 发现 podman-compose
从 1.0.2 开始才用上这个东西,遂回滚至 0.1.10。然而回滚后 podman-compose
并没有用上什么替代品,而是根本就不创建网络了。原来创建网络上个月才被 podman-compose
支持。
于是尝试往前滚 podman
。debian/stable
里最新的是 3.0.1,于是上 debian/unstable
,升级到 3.4.3,解决。
podman-compose 不支持 macvlan
升级完 podman 后 podman-compose 不报错了,但是起来的容器获得的还是一个 bridge network。从标准输出看根本没有 macvlan。
怎么办呢?
据了解,podman 对 docker-compose 的支持分两支:
- podman-compose:将 docker-compose.yaml 翻译为 podman 命令。
- podman system service:提供与 docker 兼容的 RESTful service,可配合 docker-compose 使用。
于是安排后者。
network create only supports the bridge driver
用上 podman system service 后 docker-compose
报 ERROR: network create only supports the bridge driver
。至少比 podman-compose
不报错偷偷偷懒强了。
搜一下, 发现 rootless 不支持 macvlan。于是加 sudo,然而还是不管用。
在 GitHub 上搜索未发现该报错信息。于是试图了解一下 podman system service 是个啥。
首先代码都在 containers/podman 这个仓库里。观察根目录,猜测 cli 相关代码应当在 /cmd
中,于是可以依次发现:
/cmd/podman/system/service.go
/cmd/podman/system/service_abi.go
/pkg/api/server/server.go
/pkg/api/server/register_networks.go
/pkg/api/handlers/compat/networks.go
诶好像到这该干的都干了,没人打印这个错误信息啊。不过有了先前的经验,容易猜测可能又是版本问题。确实,这个报错信息在 2021-09-15 的 85e8fbf
中被移除了,而这个版本至今未被包含在任何 release 中。
于是从 HEAD 编译一个,解决。
cannot set network aliases for network “…” because dns is disabled: invalid argument
用上来自 HEAD 的 podman,再来。这次报错:
|
|
好在现在我们站在他头上,可以轻松搜索到它来自 /libpod/runtime_ctr.go
或 /lib/networking_linux.go
。可以发现 dns enablement 是 network 本身的属性,而 alias 是 network 在一个 service 里的别名。
尝试在 docker-compose.yaml
里放置 aliases: []
,无果。似乎是 docker-compose 会主动加一个 alias。那我们把 dns 打开吧。观察 compose 的 spec 然而根本没有这个选项。
那我们暂时不用 compose 配网,手动 create network(带 dns)然后用 compose 起 service,期待后续版本能添加相关支持。这次报:
|
|
诶明明我已经设置了 parent 了呀。
podman network inspect
可以观察到 "master": "eth0"
,显然 podman 是理解相关配置的。再看 curl -H "Content-Type: application/json" --unix-socket /var/run/docker.sock http://localhost/v1.40/networks/... | jq
,网卡不见了……似乎是 /pkg/api/handlers/compat/networks.go
里没有做相关转换。
这下需要改代码了,累了,算了。既然这事没法 rootless 就先用 docker 好了。
总结
- 在配备新版内核的宿主机里起 wireguard 容器十分简单,alpine 里直接
apk add wireguard-tools
即可。 - podman-compose 19-21 之间有两年半时间没发布 PyPI 更新。遇到问题先更新一下。
- podman-compose 目前还不支持很多东西。
- podman-compose 可以用 podman system service 和 docker-compose 替代。由于这个 service 无需长期运行,我们可以写一个脚本来启动 service 并运行 docker-compose。
- 无论是 podman-compose 还是 podman system service,目前的 HEAD 版本都不能很好的支持 macvlan / ipvlan。
- GitHub 搜索不覆盖历史版本。搜不到可能是代码被改了。
- 纯的 rootless 容器不支持 macvlan / ipvlan。
lxc-user-nic
也许可以解决这个问题但那就不全是 rootless 了。
Author SEIAROTg
LastMod 2021-12-29