podman —— 无守护进程的容器引擎
podman —— 无守护进程的容器引擎
分类:06 容器与编排 适用:Podman 3.x / 4.x / 5.x(RHEL 8+、CentOS Stream、Fedora、部分信创系统默认) 一句话:命令与 docker 基本一致,但没有 daemon、可以 rootless 运行,安全模型更贴近 Linux 原生。
1. 它解决什么问题
- 不想跑一个 root 权限的
dockerd常驻进程。 - 多用户环境下,每个用户管理自己的容器(rootless)。
- K8s YAML 直接在本机跑起来验证(
podman play kube)。 - 用 systemd 原生托管容器,而不是靠
--restart策略。
2. 与 docker 的核心差异
| 维度 | docker | podman |
|---|---|---|
| 架构 | C/S,需 dockerd | 无守护进程,直接 fork/exec |
| root | 默认 root 守护进程 | 支持完全 rootless |
| 命令 | docker ... |
podman ...(高度兼容) |
| 编排 | docker compose | podman-compose / podman play kube |
| 开机自启 | --restart |
podman generate systemd / Quadlet |
| 镜像构建 | docker build |
podman build(底层 buildah) |
| Pod 概念 | 无 | 有(podman pod,贴近 K8s) |
别名兼容:
alias docker=podman
# 或安装 podman-docker 包,提供 docker 命令与 socket 兼容层
3. 常用命令(与 docker 基本一致)
podman run -d --name web -p 8080:80 nginx:1.25
podman ps / podman ps -a
podman logs -f --tail 100 web
podman exec -it web sh
podman inspect web
podman stats
podman images
podman pull / push
podman rm / rmi
podman stop / start / restart
podman system df
podman system prune -a
podman cp web:/etc/nginx/nginx.conf ./
podman save / load
差异命令:
podman generate systemd --new --name web > ~/.config/systemd/user/container-web.service
podman play kube deploy.yaml
podman pod create --name mypod -p 8080:80
podman pod ps
4. rootless 运行
普通用户直接执行即可,无需 sudo:
podman run -d --name web -p 8080:80 nginx
podman ps
前提配置:
# 检查 subuid/subgid 映射
grep "$USER" /etc/subuid /etc/subgid
# 典型输出:alice:100000:65536
# 没有则添加
sudo usermod --add-subuids 100000-165535 --add-subgids 100000-165535 alice
podman system migrate
rootless 的端口限制
非特权用户默认不能绑定 <1024 端口。三种解决方式:
# 1. 调内核参数(推荐,全局)
sudo sysctl -w net.ipv4.ip_unprivileged_port_start=80
echo 'net.ipv4.ip_unprivileged_port_start=80' | sudo tee /etc/sysctl.d/99-podman.conf
# 2. 用高位端口 + 反代
podman run -d -p 8080:80 nginx
# 3. 给二进制加 capability(不推荐,范围过大)
挂载权限与 SELinux
# rootless 下容器内 UID 与宿主映射,需保持 ID
podman run --userns=keep-id -v $PWD:/work:Z myimage
# SELinux enforcing 时必须加 :z(共享)或 :Z(私有)
podman run -v /data/html:/usr/share/nginx/html:Z nginx
# 修复宿主目录属主(容器内写文件后宿主要能访问)
podman unshare chown -R 1000:1000 /data/html
podman unshare 进入用户命名空间执行命令,是处理 rootless 权限问题的关键工具。
5. Pod(贴近 K8s)
podman pod create --name app -p 8080:80
podman run -d --pod app --name web nginx
podman run -d --pod app --name redis redis:7
podman pod ps
podman pod stats
podman pod stop app
podman pod rm -f app
同一 Pod 内的容器共享网络命名空间,localhost 互通,端口在 Pod 层映射。
用 K8s YAML 直接跑
podman play kube deploy.yaml
podman play kube deploy.yaml --down # 停止并清理
podman generate kube app > app.yaml # 反向导出
适合本地验证 K8s 清单,不支持所有字段(Service、Ingress 等只做有限映射)。
6. 用 systemd 托管容器
方式一:generate systemd(经典)
podman run -d --name web -p 8080:80 nginx:1.25
mkdir -p ~/.config/systemd/user
podman generate systemd --new --name web --files --restart-policy=always
mv container-web.service ~/.config/systemd/user/
systemctl --user daemon-reload
systemctl --user enable --now container-web.service
loginctl enable-linger $USER # 用户退出后仍运行
--new 表示每次启动都重新创建容器(推荐,避免配置漂移)。
方式二:Quadlet(Podman 4.4+,推荐)
~/.config/containers/systemd/web.container:
[Unit]
Description=Nginx web
[Container]
Image=docker.io/library/nginx:1.25
PublishPort=8080:80
Volume=/data/html:/usr/share/nginx/html:Z
Environment=TZ=Asia/Shanghai
[Service]
Restart=always
[Install]
WantedBy=default.target
systemctl --user daemon-reload
systemctl --user start web.service
systemctl --user enable web.service
Quadlet 是官方推荐方向,generate systemd 已标记为将弃用。
7. 兼容 docker 生态
提供 docker socket
systemctl --user enable --now podman.socket
export DOCKER_HOST=unix:///run/user/$UID/podman/podman.sock
docker ps # 走 podman 后端
系统级:
sudo systemctl enable --now podman.socket # /run/podman/podman.sock
docker-compose 兼容
pip install podman-compose
podman-compose up -d
podman-compose down
# 或用 docker compose 指向 podman socket
DOCKER_HOST=unix:///run/user/$UID/podman/podman.sock docker compose up -d
镜像操作:skopeo / buildah
# 不落地直接复制镜像(跨 registry)
skopeo copy docker://registry/a/app:1.0 docker://registry/b/app:1.0
skopeo inspect docker://nginx:1.25
skopeo copy docker://nginx:1.25 dir:/tmp/nginx-dir
# 用 buildah 构建(podman build 底层就是它)
buildah bud -t app:1.0 .
buildah from alpine
8. 实战场景
8.1 信创/受限环境替代 docker
dnf install -y podman
podman run -d --name mysql -p 3306:3306 \
-e MYSQL_ROOT_PASSWORD=secret \
-v /data/mysql:/var/lib/mysql:Z \
docker.io/library/mysql:8.0
无外网时先在有网机器 podman save 再 podman load。
8.2 开机自启一个容器(rootless)
podman run -d --name app -p 8080:8080 app:1.0
podman generate systemd --new --name app --files
mkdir -p ~/.config/systemd/user && mv container-app.service ~/.config/systemd/user/
systemctl --user daemon-reload && systemctl --user enable --now container-app
sudo loginctl enable-linger $USER
8.3 本地验证 K8s 清单
podman play kube deployment.yaml
podman pod ps
curl localhost:8080/healthz
podman play kube deployment.yaml --down
8.4 排查 rootless 权限问题
podman run -it --rm -v /data:/data:Z alpine sh
# 容器内写文件后,宿主看到属主是 100000+ 的映射 ID
ls -ln /data
# 用 unshare 修正
podman unshare chown -R $(id -u):$(id -g) /data
8.5 清理
podman system df
podman system prune -a --volumes # ⚠️ 慎用
podman image prune -a
podman volume prune
9. 常见坑
docker命令不存在:装podman-docker或设 alias,但脚本里docker的某些子命令(如docker system events)行为不同。- rootless 绑不了 80 端口:见第 4 节,调
ip_unprivileged_port_start。 - SELinux 挂载被拒:必须
:z/:Z,报错形如Permission denied但权限看起来正常。 - rootless 容器写宿主目录变成 100000+ 属主:用
--userns=keep-id或podman unshare chown。 - 容器退出后
podman ps看不到:-a。 --restart不生效:rootless 下需要 systemd 托管(generate systemd/ Quadlet),Podman 本身不常驻,无法像 docker 那样自动拉起。- 用户登出后容器停了:
loginctl enable-linger。 podman-compose不完整:部分字段不支持,复杂项目用docker compose+ podman socket。- 镜像短名解析:podman 会按
/etc/containers/registries.conf补全,nginx可能被解析成docker.io/library/nginx,内网 registry 要显式写全。 podman build与docker build的缓存不共享,换工具后首次构建慢。podman generate systemd在 5.x 已弃用:迁移到 Quadlet。- cgroup v1 下 rootless 资源限制受限:
--memory可能不生效,建议 cgroup v2。 - podman socket 权限:
DOCKER_HOST指错用户会permission denied。
10. 速查表
podman run -d --name x -p 8080:80 img
podman ps -a
podman logs -f --tail 100 x
podman exec -it x sh
podman inspect x
podman stats
podman pod create --name p -p 8080:80
podman play kube app.yaml
podman generate kube p > p.yaml
podman generate systemd --new --name x --files
podman system df / prune
podman unshare chown -R 1000:1000 /data
systemctl --user enable --now container-x
loginctl enable-linger $USER
# rootless 低端口
sysctl -w net.ipv4.ip_unprivileged_port_start=80
# 兼容
podman-docker / podman.socket / podman-compose / skopeo / buildah