Podman 是什么
Podman 的命令行和 Docker 很像,最大的区别是它没有常驻的守护进程。Docker 靠一个以 root 身份常驻的 dockerd 管理容器,Podman 没有这个角色。这带来两个直接的后果:容器可以由普通用户创建和运行(rootless 模式),也可以交给 systemd 当作服务来管理。
Podman 还有几个 Docker 没有的子命令,比如 pod(容器组)、kube、quadlet 和 auto-update,后两个下面会用到。
在 Ubuntu 26.04 上安装
sudo apt install podman
我在 Ubuntu 26.04.1 LTS(arm64)的容器里装的是 podman 5.7.0。同一个软件源里还有 podman-compose(1.5.0)、podman-docker、buildah、skopeo、crun 和 netavark。以 root 身份运行 podman info,显示 Rootless 为 false,存储驱动是 overlay,运行时是 crun,网络后端是 netavark。
验证一下:
podman --version
podman run --rm docker.io/library/alpine:3.20 echo hello-from-podman
输出 hello-from-podman 就说明能跑容器了。镜像名我写的是完整的 docker.io/library/alpine:3.20,带上仓库域名最不容易出歧义。说明一下我的测试环境:我是在另一个 Docker 容器里嵌套测试的,受 cgroup 限制,需要多加一个参数才能运行,你在真实主机上不需要。
会用 docker,就会用 podman
podman --help 列出的子命令几乎涵盖了 Docker 日常用到的那些:build、run、create、start、stop、restart、rm、ps、images、rmi、pull、push、logs、exec、inspect、cp、port、stats、top、volume、network、secret 等。podman run 也支持 -p/--publish、-v/--volume、--userns,--restart 可以取 always、no、never、on-failure、unless-stopped。
有一点要留意:podman ps 只看得到当前用户创建的容器。普通用户创建的容器,别的用户看不到,root 运行的 Podman 也看不到。"容器去哪了"这个问题,先确认自己是用哪个用户执行的命令。
两种过渡方式
装 podman-docker。 装上这个包之后,/usr/bin/docker 是一个很短的 shell 脚本:先检查 /etc/containers/nodocker(或 ~/.config/containers/nodocker)在不在,不在就往标准错误输出一行 Emulate Docker CLI using podman. Create /etc/containers/nodocker to quiet msg.,然后 exec /usr/bin/podman "$@"。所以 docker --version 实际输出的是 podman version 5.7.0。嫌提示烦,创建那个文件即可:
sudo apt install podman-docker
sudo touch /etc/containers/nodocker
它只是把命令转给 Podman。你的脚本里用到的每个 docker 子命令和参数,在 Podman 里是否都有对应,需要自己试;依赖 Docker 守护进程的 API 接口(比如 docker.sock)的程序,我没有验证过。
用 podman compose。 podman compose 自己不实现 compose,帮助里写的是通过外部提供者来运行,比如 docker-compose 或 podman-compose。我在容器里执行 podman compose version,它先打印了正在调用的外部提供者的路径,再输出该提供者自己的版本号(Docker Compose version 2.40.3+ds1-0ubuntu1)。所以用它之前,机器上要先有一个 compose 提供者。
rootless 之前先配 subuid 和 subgid
用普通用户运行 Podman 时,它会自动为这个用户创建用户命名空间,可用的范围写在 /etc/subuid 和 /etc/subgid 里。手册页的要求是:用户必须在这两个文件里有多段 UID/GID 范围。手册给出的添加方法:
sudo usermod --add-subuids 10000-75535 用户名
sudo usermod --add-subgids 10000-75535 用户名
rootless 的数据位置也和 root 不同:配置从 $XDG_CONFIG_HOME 读取,没设置时在 ~/.config/containers;镜像存在 $XDG_DATA_HOME,没设置时在 ~/.local/share/containers/storage;临时数据放在 ${XDG_RUNTIME_DIR}/containers。排查 rootless 的问题,先看这几个目录。
用 Quadlet 让容器随系统启动
podman generate systemd 在 5.7.0 的帮助里已经标成 [DEPRECATED]。现在的做法是 Quadlet:它是 Podman 的 systemd 生成器,读取 .container、.volume、.network、.build、.pod、.kube、.artifact 这些文件,为每个文件生成一个同名的 .service。这些文件在开机时和执行 systemctl daemon-reload 时被读取,系统级和用户级的 systemd 都支持。
放在哪里。 root 的搜索路径按优先级是:/run/containers/systemd/(临时、测试用)、/etc/containers/systemd/(管理员定义)、/usr/share/containers/systemd/(发行版定义)。普通用户是 $XDG_RUNTIME_DIR/containers/systemd/、~/.config/containers/systemd/,以及 /etc/containers/systemd/users/ 下的目录。
怎么写。 下面是我实际用过的一个例子,保存为 /etc/containers/systemd/web.container:
[Unit]
Description=Demo web server
[Container]
Image=docker.io/library/nginx:1.27-alpine
PublishPort=8080:80
AutoUpdate=registry
[Service]
Restart=always
[Install]
WantedBy=default.target
[Container] 段是 Quadlet 自己的语法,Image= 指定镜像,PublishPort= 对应 podman run 的 --publish。[Service]、[Install] 这些段会原样交给 systemd,所以 Restart=always 和平常写 systemd 服务的方式一样。
生成了什么。 不用手写那份服务文件,想看生成结果,用 dry-run,它只打印、不安装:
/usr/lib/systemd/system-generators/podman-system-generator --dryrun
对上面的文件,它输出的 web.service 里,ExecStart 是:
/usr/bin/podman run --name systemd-%N --replace --rm --cgroups=split --sdnotify=conmon -d --label io.containers.autoupdate=registry --publish 8080:80 docker.io/library/nginx:1.27-alpine
另外增加了 Type=notify、Delegate=yes、KillMode=mixed,ExecStop 是 /usr/bin/podman rm -v -f -i systemd-%N,[Unit] 里增加了 After=network-online.target。从中能读出三点:容器名固定为 systemd-<单元名>;容器带 --rm,服务一停容器就被删掉,不会留下一堆已退出的容器;AutoUpdate=registry 变成了标签 io.containers.autoupdate=registry,这就是自动更新的开关。
这个生成结果是我用 dry-run 验证的。我的测试环境里没有运行 systemd,所以没有实际执行过 systemctl 启动它。标准的操作是 sudo systemctl daemon-reload 加 sudo systemctl start web.service,容器没起来就用 journalctl -u web.service 看日志。要看系统级单元创建的容器,用 root 身份执行 sudo podman ps,别忘了前面说的:不同用户的容器互相看不到。
此外还有 podman quadlet 这一组子命令,install、list、print、rm,用来管理这些文件本身。
自动更新
podman auto-update 的帮助说,它处理的是由 systemd 单元运行的容器,更新策略用标签 io.containers.autoupdate 指定。上面 AutoUpdate=registry 生成的正是这个标签。手动触发一次:
sudo podman auto-update
用 sudo 是因为系统级单元创建的容器属于 root。registry 这个策略的完整含义,以及怎么让它定时执行,我没有展开验证,查 man podman-auto-update。
几个常见问题
- docker 命令每次多一行提示: 创建
/etc/containers/nodocker(给所有用户)或~/.config/containers/nodocker(给当前用户)。 - podman compose 找不到提供者: 先装
podman-compose或 docker-compose。 - rootless 容器起不来: 检查
/etc/subuid、/etc/subgid里当前用户有没有多段范围。 - 改了 .container 文件没生效: Quadlet 文件只在开机和
daemon-reload时被读取,改完先sudo systemctl daemon-reload,再重启对应的服务。



