podman —— 无守护进程的容器引擎

运维工具手册 06-容器与编排 7.0 KB 原文

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. 常见坑

  1. docker 命令不存在:装 podman-docker 或设 alias,但脚本里 docker 的某些子命令(如 docker system events)行为不同。
  2. rootless 绑不了 80 端口:见第 4 节,调 ip_unprivileged_port_start。
  3. SELinux 挂载被拒:必须 :z/:Z,报错形如 Permission denied 但权限看起来正常。
  4. rootless 容器写宿主目录变成 100000+ 属主:用 --userns=keep-id 或 podman unshare chown。
  5. 容器退出后 podman ps 看不到:-a。
  6. --restart 不生效:rootless 下需要 systemd 托管(generate systemd / Quadlet),Podman 本身不常驻,无法像 docker 那样自动拉起。
  7. 用户登出后容器停了:loginctl enable-linger。
  8. podman-compose 不完整:部分字段不支持,复杂项目用 docker compose + podman socket。
  9. 镜像短名解析:podman 会按 /etc/containers/registries.conf 补全,nginx 可能被解析成 docker.io/library/nginx,内网 registry 要显式写全。
  10. podman build 与 docker build 的缓存不共享,换工具后首次构建慢。
  11. podman generate systemd 在 5.x 已弃用:迁移到 Quadlet。
  12. cgroup v1 下 rootless 资源限制受限:--memory 可能不生效,建议 cgroup v2。
  13. 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
podman —— 无守护进程的容器引擎 - 知识库 - 起航社区