因为个人的开发环境已经用 podman 替换掉了 docker-desktop,打算把服务器的容器运行时从 docker
替换成 podman
。
podman 最大的亮点是支持 rootless
模式 和 no-daemon
(通过 systemd service unit 来管理容器进程)。
服务器系统为 debian 12
,踩坑如下:
apt 默认官方源版本落后
debian 官方 apt 源,版本过于落后(目前才到 4.3.1)。
➜ sudo apt search podman -n 2>/dev/null| grep -iE ^podman/stable
podman/stable 4.3.1+ds1-8+b1 amd64
- <4.7 不支持
compose
子命令。当时心想反正不影响docker-compose
通过socket
运行容器。无关紧要,没想到这才是深渊的开始。 - <4.8
keep-id
创建的容器,容器销毁时 ip 不回收,导致 IPAM 消耗完最终无法再创建出新的容器。https://github.com/containers/podman/issues/18615 (属实天坑,这个参数在rootless
下很常用的)从 https://packages.debian.org/trixie/podman 上,整一个 4.9 来用吧。 - 不支持
socket
方式创建的容器生成systemd
单元文件:https://github.com/containers/podman/issues/13289。好吧,没有关系,我切换到podman-compose
,其原理是生成podman run
命令进行调用。(podman 现在在推Quadlets/systemd
,但又不能直接把 docker-compose.yml 无缝转换) podman-compose
volumes
绑定,需要绝对路径。好吧,podman兼容
docker,但是没有说
podman-compose` 要完全兼容 docker-compose volume。
当我以为这一切都解决了的时候,发现
- <1.0.6 ,
podman-compose
没有渲染keep-id
命令: https://github.com/containers/podman-compose/issues/166
没错,debian apt 官方的版本还是 1.0.3。一口老血喷出,换成 pip3 安装了。
➜ sudo apt search podman -n 2>/dev/null| grep -iE podman-compose
podman-compose/stable 1.0.3-3 all
结论
虽然 podman 声称自己完美兼容了 docker,并且在前几年就软文不断,各种文章说 应该用 podman
替换掉 docker
云云,并且极力夸奖 podman 的 rootless
多么的好用。实际上看来,当初吹嘘这些人不一定真的有用过 rootless
模式,严重怀疑当时收了红帽的钱。
不过至少从最新的版本来看,它可以满足我目前切换的需求。
更新
2024 年 4 月 4 日
Note: Rootlesskit changes the source IP address of incoming packets to an IP address in the container
network namespace, usually 10.0.2.100. If your application requires the real source IP address, e.g.
web server logs, use the slirp4netns port handler
背景: podman rootless 默认网桥下/用户自建网桥下,端口转发通过 Rootlesskit
,容器内无法获取客户端的 remote ip。这会严重影响诸如 web 服务的访问统计等功能。
相关问题见:https://github.com/containers/podman/issues/17765 https://github.com/containers/podman/issues/17765
按照其中的描述,network 模式使用 pasta 或者 slirp4netns:port_handler=slirp4netns 可以拿到外部的 ip。
podman rm -af
podman run --name myNginx6443.rootless --publish 6443:80 --rm -d docker.io/library/nginx:alpine
podman run --name myNginx6444.rootless --publish 6444:80 --network pasta --rm -d docker.io/library/nginx:alpine
podman run --name myNginx6445.rootless --publish 6445:80 --network slirp4netns:port_handler=slirp4netns --rm -d docker.io/library/nginx:alpine
curl http://172.27.215.8:6443 >/dev/null 2>&1
curl http://172.27.215.8:6444 >/dev/null 2>&1
curl http://172.27.215.8:6445 >/dev/null 2>&1
# 内部ip
podman logs myNginx6443.rootless 2>1 | grep GET
10.0.2.100 - - [04/Apr/2024:08:31:12 +0000] "GET / HTTP/1.1" 200 615 "-" "curl/7.88.1" "-"
# 外部ip
podman logs myNginx6444.rootless 2>1 | grep GET
172.27.215.8 - - [04/Apr/2024:08:31:16 +0000] "GET / HTTP/1.1" 200 615 "-" "curl/7.88.1" "-"
podman logs myNginx6445.rootless 2>1 | grep GET
172.27.215.8 - - [04/Apr/2024:08:31:19 +0000] "GET / HTTP/1.1" 200 615 "-" "curl/7.88.1" "-"
根据 podman network 不能将将 bridge 类型和 pastra/slirp4netns options 混合使用 和 podman compose 暂不支持 network_mode: pasta 的说法,本以为单独跑 podman run
且网络单独绑定绑定在 pasta
上可以解决问题,结果这两个模式下 container
的 IPAddr
信息为空。
podman inspect myNginx6444.rootless | grep IPAddress
"IPAddress": "",
podman inspect myNginx6445.rootless | grep IPAddress
"IPAddress": "",
而 traefik
的服务发现绑定的 load-balance ip
就是通过 IPAddress 字段获取。。。。属于是无解了。
time="2024-04-04T08:49:19Z" level=error msg="service \"traefik-traefik\" error: unable to find the IP address for the container \"/traefik\": the server is ignored"
目前看到部分的解决方案是在外部套一层 cdn,然后通过 x-real-ip
/x-forwarded-for
来尝试解决。。。
我得收回 podman rooltess 服务器目前可以用的言论了。之前在开发环境完全没有注意到这点。
欢迎来到这里!
我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。
注册 关于