更新日期:2026-10-18
如果工作负载只是拉取镜像、运行容器和查看日志,Podman 的命令会让 Docker 用户感到熟悉。但当系统里加入 Compose、数据卷、反向代理、自动更新器和监控,迁移就不能简化成把 docker 命令替换成 podman。
本文面向 Linux 单机容器环境,重点评估 rootless Podman 与现有 Docker 工作流的差异。桌面虚拟机、Kubernetes 集群和特定商业产品需要单独核对,不属于这套演练范围。
先找出应用依赖了哪些 Docker 能力
| 当前依赖 | 迁移时要验证 |
|---|---|
| OCI 镜像与基本运行参数 | 架构、入口点、用户、挂载与健康检查 |
| Compose 文件 | 实际 Compose provider 及其支持行为 |
| Docker socket | API 兼容范围、socket 路径与调用方 |
| 主机端口和容器 DNS | rootless 网络行为、服务名解析与绑定地址 |
| 数据卷 | 位置、UID/GID、标签与恢复方法 |
| 开机启动 | systemd 用户服务、登录状态与生命周期 |
先查谁挂载或访问了 Docker socket。只要存在通过 API 管理容器的面板、代理或自动化工具,就要对这些客户端逐个验证,不能只测应用容器本身。
rootless 改变的是权限边界
普通用户运行的 Podman 使用自己的容器存储与配置。它和 root 用户看到的容器集合不同,和 Docker 的存储也不相同。运行 sudo podman ps 没看到普通用户的容器,不代表数据消失了。
rootless 可以减少容器管理进程需要的主机权限,但不使容器自动成为完整安全边界。挂载敏感目录、暴露管理接口、运行不可信镜像,仍然要按实际权限评估。
安装后先记录环境:
podman version
podman info
podman ps -a
关注是否为 rootless、实际网络后端、存储位置和 cgroup 情况。不要照搬其他机器的内部目录路径,也不要直接把 Docker 存储目录复制给 Podman。
用一个无状态服务开始演练
以下示例要求已经按发行版文档安装 Podman,端口 18080 未被占用。它只把服务发布到本机回环地址,适合验证镜像、端口与日志链路。
podman run -d --name mf8-podman-demo \
-p 127.0.0.1:18080:80 \
docker.io/library/nginx:stable-alpine
curl --fail http://127.0.0.1:18080/
podman logs mf8-podman-demo
podman inspect mf8-podman-demo
教程使用可读镜像标签演示;生产部署应固定经过验证的版本或 digest,并记录升级与恢复所用制品。不要把“镜像能拉下来”当作可重复部署。
演练结束后,只清理这个无状态测试容器:
podman stop mf8-podman-demo
podman rm mf8-podman-demo
如果还要测试持久化数据,应另外创建专用测试目录或卷,避免把业务目录直接挂进练习容器。
Compose 兼容必须用自己的文件验证
podman compose 是调用外部 Compose provider 的入口,并不是所有 Compose 行为都由 Podman 自己实现。机器上安装的 provider、版本和选择顺序都会影响结果。官方 compose 说明
先确认版本和解析结果,再启动测试项目:
podman compose version
podman compose -f compose.yaml config
配置输出可能展开环境变量中的密码,应只在可信终端查看,不直接上传到公开工单。随后在独立目录、独立端口和独立数据卷上运行自己的项目。
需要验证的不是 YAML 能否解析,而是应用依赖:服务发现、健康检查、启动顺序、环境变量、资源限制、日志、重启和关闭是否符合预期。某些字段被接受,也不代表其运行效果与你的 Docker 环境完全相同。
数据卷最容易出现“能启动,不能写”
rootless 涉及用户命名空间,容器内 UID 与宿主 UID 不一定相同。遇到写入失败,应先检查容器用户、宿主目录属主和映射,而不是直接给目录设置所有人可写。
启用 SELinux 的环境还需要考虑标签。Podman 的 :Z 用于私有重标记,:z 用于共享情形;这些选项会改变挂载内容的标签,不能盲目用于系统目录或整个用户目录。挂载与标签说明
数据库迁移应使用数据库认可的备份与恢复方式,或满足停机一致性要求的数据迁移方式。不能让 Docker 和 Podman 中两个数据库进程同时写同一份数据目录来“对比效果”。
用 systemd 管理长期服务
在支持 Quadlet 的 Podman 环境,可把容器声明交给 systemd。普通用户配置可放在 ~/.config/containers/systemd/,例如文件 mf8-web.container:
[Unit]
Description=MF8 Podman web demo
[Container]
Image=docker.io/library/nginx:stable-alpine
PublishPort=127.0.0.1:18080:80
[Service]
Restart=on-failure
TimeoutStartSec=120
[Install]
WantedBy=default.target
先确认前面的演练容器已经移除、端口空闲,再加载与启动:
systemctl --user daemon-reload
systemctl --user start mf8-web.service
systemctl --user status mf8-web.service --no-pager
journalctl --user -u mf8-web.service -n 50 --no-pager
Quadlet 生成的单元应通过源文件的 Install 配置管理启动关系。若要求用户未登录时也运行,还需要管理员评估并配置该账号的 lingering;这会改变用户服务的持续运行方式,应使用专用服务账号并安排实际重启验收。Quadlet 官方文档
怎样判断可以迁移
至少完成以下检查,再替换现有工作负载:
- 核心业务请求与数据库读写正常。
- 重启和用户会话结束后的服务行为符合预期。
- 数据卷权限、备份和独立恢复已验证。
- 反向代理、监控和管理客户端能正确工作。
- 有旧镜像、旧配置和明确的数据回退方法。
如果迁移只是为了更换工具名称,而现有依赖非常复杂,可以先保留 Docker,同时用 Podman 运行独立测试工作负载。若 rootless 或 systemd 集成解决了具体维护问题,再逐个迁移更容易控制影响。
