起因
我的服务器上 Docker daemon 用 root 跑。任何能跟 docker.sock 通信的用户
都等于 root(passing socket 到容器 = 容器逃逸)。多用户 / 共享开发机
上风险大。
podman 是 Red Hat 主导的 OCI 兼容容器引擎,几个区别:
- no daemon:每个容器一个进程 fork 出来,systemd 直接 supervise
- rootless first:默认非 root 用户跑
- Docker CLI 兼容:
alias docker=podman大多数命令直接 work - 支持 pod(K8s 那种多容器组)
装
# Debian 12+ / Ubuntu 22.04+
sudo apt install -y podman
# 给当前用户 subuid / subgid(rootless 必须)
# /etc/subuid + /etc/subgid 应当各有:
# me:100000:65536
# 默认装好就有;没有就:
sudo usermod --add-subuids 100000-165535 --add-subgids 100000-165535 me
# 配置 storage(rootless 在 ~/.local/share/containers/)
podman info | grep -A 3 storage
基础用法(跟 Docker 几乎一样)
podman pull nginx:alpine
podman run -d --name web -p 8080:80 nginx:alpine
podman ps
podman logs -f web
podman exec -it web sh
podman stop web
podman rm web
alias docker=podman 后大部分 docker 命令直接用。
rootless 网络
Rootless 容器不能 bind 80/443(< 1024 需 root)。
解决:
# 方案 A:bind 8080,前置 nginx 反代
podman run -d -p 8080:80 nginx
# 方案 B:开 unprivileged port range
sudo sysctl net.ipv4.ip_unprivileged_port_start=80
# 之后 rootless 也能 bind 80
方案 B 安全风险:任何用户能 bind 80。多人共享机器不建议。
podman generate systemd
杀手锏:把 container 转成 systemd unit:
podman run -d --name web -p 8080:80 nginx:alpine
# 生成 unit 文件
podman generate systemd --name web --files --new
# 输出:container-web.service
mkdir -p ~/.config/systemd/user/
mv container-web.service ~/.config/systemd/user/
systemctl --user daemon-reload
systemctl --user enable --now container-web.service
# 开机自启(必须 enable linger)
loginctl enable-linger $USER
之后 systemctl 全程管理 container:
systemctl --user status container-web
systemctl --user restart container-web
journalctl --user -u container-web -f
容器 = systemd service。一致性极佳。
Quadlet(podman 4.4+ 推荐)
更现代的方式:.container 文件直接被 systemd 当 unit:
~/.config/containers/systemd/web.container:
[Unit]
Description=Web server
[Container]
Image=docker.io/library/nginx:alpine
PublishPort=8080:80
Volume=/home/me/www:/usr/share/nginx/html:Z
AutoUpdate=registry
[Service]
Restart=always
[Install]
WantedBy=default.target
systemctl --user daemon-reload
systemctl --user start web # 注意是 web 不是 web.container
比 generate systemd 简洁得多。每改 image / volume / port 直接改 .container
文件 + daemon-reload。
Pod(多容器组)
K8s 风格的 Pod(共享 network + IPC):
podman pod create --name myapp -p 8080:80
podman run -d --pod myapp --name api myapi:latest
podman run -d --pod myapp --name worker myworker:latest
podman pod ls
api 和 worker 共享网络(同 localhost),共享 IPC namespace。
适合"sidecar" 模式。
K8s YAML 直接转 podman pod:
podman play kube k8s-pod.yaml
支持基础 K8s YAML。
auto-update
# 容器加 label
podman run -d --label io.containers.autoupdate=registry nginx:alpine
# 系统级 timer 自动检查 + 升级
systemctl --user enable --now podman-auto-update.timer
每天检查 registry 上 image 新版,有就 pull + restart 容器。Watchtower 等价。
docker-compose 兼容
sudo apt install -y podman-compose
# 或:pip install podman-compose
podman-compose up -d # 大部分 docker-compose.yml 直接 work
或者用 podman compose(subcommand,跟 Docker Compose v2 接近)。
少数 docker-only feature(如 network_mode: bridge 的特定行为)
偶尔不兼容,看具体场景。
与 Docker 对比
| Docker | podman | |
|---|---|---|
| daemon | dockerd (root) | 无 daemon(每容器自己进程) |
| rootless | 实验性 + 有限 | 默认 + 一等公民 |
| systemd 集成 | 弱 | 极强(Quadlet) |
| Docker CLI 兼容 | 原生 | 极高 |
| Compose | docker compose | podman-compose / podman compose |
| K8s 友好 | Pod 概念无 | 原生 Pod |
| 性能 | 略好(daemon overhead 摊销) | 接近 |
| 生态成熟度 | 极高 | 高 + 增长中 |
| RHEL / Fedora 默认 | ❌ | ✅ |
Red Hat 系(RHEL / CentOS Stream / Fedora)官方推 podman。
其它 distro 都装得上。
适用场景
✅ podman 适合:
- 单机部署 + 喜欢 systemd 集成
- 多用户开发机(rootless 安全)
- 不需要 docker swarm
- RHEL / Fedora 用户
- K8s 学习(pod 概念友好)
❌ 保 Docker 适合:
- 重度用 docker swarm / docker compose 高级 feature
- 团队工具链都基于 docker
- 公司 SaaS 工具明确支持 Docker(如 GitHub Actions docker-container action)
我的实际迁移
家用服务器(10+ 容器:nginx / db / 监控 / 个人 app)从 docker 迁
podman + Quadlet:
# ~/.config/containers/systemd/postgres.container
[Container]
Image=postgres:16-alpine
PublishPort=127.0.0.1:5432:5432
Environment=POSTGRES_PASSWORD=...
Volume=postgres-data.volume:/var/lib/postgresql/data
HealthCmd=pg_isready -U postgres
HealthInterval=10s
[Install]
WantedBy=default.target
每个容器一个 .container 文件,git 管。
重启服务器后 systemd 自动按顺序起所有容器。
效果
- 总内存:少 200 MB(无 dockerd 常驻)
- 部署 / 重启容器跟 systemctl service 一致
- 容器崩溃 / OOM / 异常退出:journal 里完整 log + restart 历史
- rootless 让"容器漏洞 → 拿 host root" 这条路被堵
- 一致 backup:备份 ~/.local/share/containers + ~/.config = 完整状态
踩过的坑
-
rootless 网络默认 slirp4netns 慢:吞吐量大幅低于 root docker。
高流量场景配pasta(新版默认) 或者 root pod。 -
rootless 不能跨用户访问 image:每个用户独立 storage。
podman --root=/path/to/system-storage可以共享但复杂。 -
某些 docker-only env var:如
DOCKER_HOSTsocket 路径。
podman 用 unix socket 在$XDG_RUNTIME_DIR/podman/podman.sock。 -
selinux 标签:volume mount 缺
:Z/:z后缀容器内访问权限错。
-v /path:/path:Z让 SELinux 自动 relabel。 -
GPU passthrough:rootless + GPU 不直接 work。
--device /dev/nvidia* - udev rule 配。生产推荐 root podman 跑 GPU 容器。
登录后参与评论。