Podman 入门全指南:从零开始,用更安全的方式跑容器

一份面向零基础的 Podman 入门教程:讲清 Podman 是什么、和 Docker 的本质区别(无守护进程 + rootless)、Windows/macOS/Linux 三平台的安装路径、从第一个容器到 compose/pod/systemd 的完整命令对照、镜像构建与推送、常见踩坑与排错,以及从 Docker 迁移的实操清单。

如果你用 Docker Desktop 跑过容器,多半遇到过这几件事:开机后进程里常驻一个 com.docker.backend,风扇转个不停;公司发了通知说 Docker Desktop 商业授权要收费;或者只是想让容器以普通用户身份跑,却发现默认还得靠一个 root 权限的守护进程。

Podman 就是为解这些痛点而生的。 它和 Docker 的命令几乎一样,但架构完全不同:没有常驻的守护进程(daemonless),默认以普通用户身份运行容器(rootless)。换句话说,你的 docker run 换个词就能跑,但底层更干净、更安全。

这篇是写给新手的从零教程。不讲太多原理八卦,重点是把"装好 → 跑起来 → 会日常用 → 能排错 → 敢从 Docker 迁过来"这条路径走通。

说明:本文命令基于 Podman v5 及以上版本(当前最新为 v6.1.3,2026-09-29 发布),主要实验环境为 Windows 11 + WSL2 Ubuntu 与原生 Linux。macOS 与 Linux 的差异会单独标注。

目录

  1. Podman 到底是什么
  2. 它和 Docker 的本质区别
  3. 安装:三条路线选一条
  4. 第一个容器:从这里开始动手
  5. 日常命令速查:和 Docker 逐条对照
  6. 镜像:构建、推送与导入导出
  7. 进阶重点:Pod、compose 与 systemd
  8. rootless 权限模型:新手最容易卡的地方
  9. 常见问题与排错清单
  10. 从 Docker 迁移:一份可直接执行的清单
  11. 该不该换:适用与不适用场景

图:Podman 封面插画——海豹吉祥物与轻量容器

一、Podman 到底是什么

一句话定义:Podman(Pod Manager)是一个管理 OCI 容器与镜像的命令行工具,能跑容器、管镜像、管卷、管 Pod,且不需要守护进程。

它的几个身份标签:

属性说明
开源协议Apache-2.0
开发方Red Hat 主导,containers 组织维护
仓库热度GitHub 约 33,000 star、3,400 fork(podman-container-tools/podman)
官网https://podman.io
当前版本v6.1.3(2026-09-29);v5.x 是当前应用最广的稳定系列
图形界面Podman Desktop v1.29.3(CNCF Sandbox 项目)

这里要特别点出一个容易混淆的事:Podman 是一个 CLI 工具,Podman Desktop 是它的图形前端。两者可以分开装——你可以只用命令行 Podman,也可以只用 Desktop。新手如果想少打命令,建议两个都装(见第三节)。

它由哪几个工具组成

真正动手时你会发现,Podman 的生态里其实是一组分工明确的工具:

  • podman:主角,管容器的生老病死(run/stop/rm/ps/inspect…)
  • buildah:专职构建镜像(podman build 底层就调它)
  • skopeo:不落地地搬运、检查、复制镜像,比如把镜像从 Docker Hub 直接同步到私有仓库
  • crun / runc:真正的运行时,负责创建内核 namespace 和 cgroup。Podman 默认用 crun(Red Hat 自研,C 语言写的,启动更快、内存占用更低)

给新手的建议:一开始只需要 podman 一个命令就够了。buildah 和 skopeo 等你需要写 CI 脚本或做镜像搬运时再深入。


二、它和 Docker 的本质区别

这是全篇最值得花时间理解的一节。命令的相似是"表面功夫",架构的不同才是"为什么用它"的答案。

2.1 核心架构对比

Docker 的模式是"客户端 - 服务端":你敲 docker run,本质上只是给后台常驻的 dockerd 发了个请求,真正建容器的是那个 root 权限的守护进程。所有容器都挂在这一个进程底下,它是单点,也是权限放大的来源。

Podman 的模式是"直接 fork":你敲 podman run,Podman 进程自己就去创建容器了,做完就退出。没有中间商。容器直接是 Podman 的子进程,用普通用户的身份创建,天然不需要 root。

2.2 六个关键差异

维度DockerPodman
守护进程必须常驻 dockerd(root)无守护进程,用完即退
默认权限容器由 root 守护进程创建默认 rootless,以当前用户身份运行
安全边界攻破 dockerd ≈ 拿到 root攻破容器 ≈ 只拿到普通用户权限
Pod 概念需要 Kubernetes 才有原生支持 podman pod
systemd 集成需额外配置原生 podman generate systemd / Quadlet
开机自启由 Docker 服务统一管理由 systemd 用户服务管理,可精确到单个容器
命令兼容—高度兼容 Docker CLI,多数命令直接换名可用
授权成本Docker Desktop 对部分企业收费完全免费开源

2.3 一句话记法

Docker 像"总公司 + 派工单":所有活都由总部那个大管家接单再分派。 Podman 像"个体户自己上手":你叫它干活,它自己就干完了,不用惊动任何人。

2.4 那 Docker 还有什么优势

不吹不黑,交换条件在这里:

  • 生态成熟度:Docker Compose、Docker Desktop 的图形化体验、插件市场、文档量,仍然是第一梯队。Podman 的 compose 靠 podman-compose 或 podman compose 提供,偶有兼容边角问题。
  • 单机开发体验:Docker Desktop 在 macOS/Windows 上的"开箱即用"做得更顺(Podman 需要先 podman machine init)。
  • Kubernetes 本地开发:kind、minikube 默认以 Docker 为主。

结论:学习/个人/安全敏感场景,Podman 很香;企业重度依赖 Docker Compose 复杂编排时,迁移要评估成本。 好消息是二者可以共存,后面第十节会给共存方案。


三、安装:三条路线选一条

Podman 在 Linux 上是"原生居民",在 Windows / macOS 上则需要一个 Linux 虚拟机(Podman Machine)。请先确认你在哪个平台,再走对应的路。

3.1 路线 A:Linux(最推荐,体验最完整)

以 Ubuntu / Debian 为例:

sudo apt update
sudo apt install -y podman
podman --version

Fedora / RHEL / CentOS Stream(原生支持最好,版本最新):

sudo dnf install -y podman

⚠️ 踩坑预警:Ubuntu 22.04 官方源里的 Podman 版本偏旧(3.4.x 级别),可能导致 Podman Desktop 连不上。若要新版本,改用官方仓库:

. /etc/os-release
echo "deb https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/xUbuntu_${VERSION_ID}/ /" \
  | sudo tee /etc/apt/sources.list.d/devel:kubic:libcontainers:stable.list
curl -L "https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/xUbuntu_${VERSION_ID}/Release.key" \
  | sudo apt-key add -
sudo apt update && sudo apt install -y podman buildah skopeo

Linux 上装完直接用,不需要初始化虚拟机,也没有 podman machine 这一步。

3.2 路线 B:Windows(主流做法是走 WSL2)

Windows 上跑 Podman 有两种姿势,按你的需求选:

姿势 1:装 Podman Desktop(图形界面,新手友好)

  1. 到 https://podman-desktop.io 下载 Windows 安装包
  2. 建议下载官网的 .exe 安装包,而不是 Microsoft Store 的 MSIX 版本(MSIX 版本偶有权限与路径问题)
  3. 安装时勾选 “Add to PATH”,方便后续命令行调用
  4. 首次启动会引导你创建一个 Podman Machine(本质是 WSL2 里的一台轻量虚拟机)

姿势 2:直接在 WSL2 的 Ubuntu 里装(推荐给开发人员)

如果你本来就有 WSL2,这是最舒服的方式——Podman 直接装在一个真正的 Linux 里,行为与服务器完全一致:

# 在 WSL2 Ubuntu 中执行
sudo apt update && sudo apt install -y podman
podman --version

💡 重要差异:WSL2 里不用 podman machine。因为你已经在 Linux 里了,Podman 直接跑在 WSL2 的内核上。podman machine 是给"在 Windows 上模拟 Linux"准备的,WSL2 路线不需要。

如果你的网络环境访问 download.opensuse.org 较慢,也可以先在 WSL2 里用系统源装,够用即可。

关于 WSL2 的补充:Podman 与 Docker 在 WSL2 里可以并存。如果你之前用 Docker Desktop 的 WSL 集成,注意两者对 docker 命令的接管关系(见第十节)。

3.3 路线 C:macOS

  1. 通过 Homebrew 安装 CLI:
brew install podman
  1. 初始化虚拟机(macOS 上没有原生 Linux 内核,必须有这一步):
podman machine init --cpus 4 --memory 8192 --disk-size 50
podman machine start
  1. 想用图形界面就再装 Podman Desktop(https://podman-desktop.io)。

⚠️ macOS 上的资源要提前给够:默认虚拟机的 CPU / 内存偏小,跑稍重的镜像会卡。建议至少 --cpus 4 --memory 8192(8 GB),磁盘 50 GB。如果虚拟机已建好才发现不够,需要先 podman machine rm 再重新 init,或在 Desktop 里调整机器配置。

3.4 安装后的第一步自检

不管哪条路线,装完先跑这三条命令确认环境健康:

podman --version      # 版本号
podman info           # 环境详情:runtime、rootless 与否、存储驱动
podman run --rm hello-world

podman info 里重点看两处:

host:
  security:
    rootless: true          # ← Windows/macOS 下通常是 false(在虚拟机里是 root)
                          #   Linux 下应为 true,说明 rootless 生效

如果最后一条 hello-world 能打印出提示语,说明拉镜像、建容器、跑进程、销毁容器这条完整链路已经通了。


四、第一个容器:从这里开始动手

这一节的所有命令,在 Linux / WSL2 里可以直接跑;Windows、macOS 用户请先确认 podman machine 已在运行(podman machine list)。

4.1 跑一个一次性容器

podman run --rm hello-world

拆解这四个部分,这是 Podman(也是 Docker)命令的通用结构:

片段含义
podman主命令
run子命令:创建并启动一个容器
--rm选项:容器退出后自动删除
hello-world镜像名(不含 --,说明它是位置参数)

口诀:podman [全局选项] 子命令 [子命令选项] 镜像 [容器内执行的命令]

4.2 跑一个能交互的容器

podman run -it --rm ubuntu:24.04 bash
  • -i = 保持标准输入打开
  • -t = 分配一个伪终端(pseudo-TTY)
  • --rm = 退出后清理
  • ubuntu:24.04 = 镜像名 + 标签
  • bash = 容器启动后要执行的命令

进去之后,你会发现自己在一个全新的 Ubuntu 里。敲 exit 退出,容器随即消失。

💡 初学者最容易犯的错:不加 -it 就想进交互式 shell,结果容器瞬间退出,podman ps 什么都看不到。记住:没有前台进程,容器就会退出。

4.3 后台运行 + 端口映射

podman run -d --name web -p 8080:80 nginx:alpine
片段含义
-d后台运行(detached)
--name web给容器起名 web,方便后续引用
-p 8080:80宿主机 8080 端口 映射到 容器 80 端口

然后验证:

podman ps                       # 看到 web 正在运行
curl http://localhost:8080      # 应返回 nginx 欢迎页 HTML
podman logs web                 # 看日志
podman exec -it web sh          # 进入这个正在运行的容器

⚠️ -p 的冒号方向别记反:-p 宿主机端口:容器端口。-p 8080:80 是"外面 8080,里面 80"。写反了会连不上。

4.4 挂载数据卷

容器一删,里面的数据就没了。要持久化,得挂卷:

# 方式一:命名卷(Podman 管理存储位置)
podman run -d --name db -v pgdata:/var/lib/postgresql/data \
  -e POSTGRES_PASSWORD=secret postgres:16-alpine

# 方式二:绑定挂载(挂宿主机目录,开发时常用)
podman run -d --name web2 -v $(pwd)/html:/usr/share/nginx/html:ro -p 8081:80 nginx:alpine
  • -v pgdata:/path 中 pgdata 不以 / 开头 → 命名卷
  • -v $(pwd)/html:/path 中左边是绝对路径 → 绑定挂载
  • 结尾 :ro 表示只读挂载(容器改不了宿主机文件,更安全)

💡 rootless 下的挂载权限坑:绑定挂载宿主机目录时,容器里的用户 UID 与宿主机不一致,常出现"容器写不进去"的情况。这是 rootless 的正常现象,解法见第八节。

4.5 清理:容器跑多了怎么收场

podman ps -a                      # 看全部容器(含已停止)
podman stop web                   # 停
podman rm web                     # 删容器
podman rm -f web                  # 强制删(运行中也删)

podman images                     # 看本地镜像
podman rmi nginx:alpine           # 删镜像

# 一键清理(危险,但很省事)
podman system prune -a            # 删除所有未使用的容器、镜像、网络、卷
podman system prune -af --volumes # 连未使用的卷一起删(数据会丢!)

⚠️ podman system prune -a 会删掉所有没在跑的镜像,下次用要重新拉。别在赶时间的时候手滑。带 --volumes 更要小心,卷里可能是数据库数据。


五、日常命令速查:和 Docker 逐条对照

这是本文最实用的一张表。Podman 对 Docker CLI 的兼容度非常高,绝大多数场景就是把 docker 换成 podman。

用途DockerPodman是否直接换名可用
查看版本docker versionpodman version✅
环境信息docker infopodman info✅
拉镜像docker pull nginxpodman pull nginx✅
看镜像docker imagespodman images✅
跑容器docker run -d -p 80:80 nginxpodman run -d -p 80:80 nginx✅
看运行中容器docker pspodman ps✅
看全部容器docker ps -apodman ps -a✅
进容器docker exec -it web shpodman exec -it web sh✅
看日志docker logs -f webpodman logs -f web✅
停 / 启 / 重启docker stop/start/restartpodman stop/start/restart✅
删容器docker rm -f webpodman rm -f web✅
删镜像docker rmi nginxpodman rmi nginx✅
构建镜像docker build -t x .podman build -t x .✅
打标签docker tagpodman tag✅
推/拉仓库docker push/pullpodman push/pull✅
镜像导入导出docker save/loadpodman save/load✅
看卷docker volume lspodman volume ls✅
看网络docker network lspodman network ls✅
看详情docker inspectpodman inspect✅
编排docker compose uppodman compose up(依赖外部)⚠️ 见第七节
Pod 概念无(靠 K8s)podman pod create/ps❌ 独有功能
systemd 集成手工配置podman generate systemd / Quadlet❌ 独有功能
虚拟机管理Docker Desktop 内部podman machine init/start/stop❌ 独有功能

5.1 更省事的做法:直接用 docker 命令

Podman 提供了一个兼容包 podman-docker,装好后会创建一个指向 podman 的 docker 别名:

# Fedora / RHEL
sudo dnf install -y podman-docker

# Ubuntu / Debian
sudo apt install -y podman-docker

装上之后,你现有的 docker ... 脚本不用改一个字符:

docker run -d --name web -p 8080:80 nginx   # 实际由 podman 执行

⚠️ 重要澄清:podman-docker 只是符号链接/包装脚本,它不会启动 Docker 守护进程。有人以为装了它就"有了 Docker",是误解。另外,如果你同时装了 Docker Desktop,注意两者对 /usr/bin/docker 的争夺——先装的赢。

5.2 高频组合命令备忘

# 停止并删除所有容器
podman stop $(podman ps -q) && podman rm $(podman ps -aq)

# 删除所有 <none> 悬空镜像
podman image prune -f

# 看容器资源占用(类似 top)
podman stats

# 看容器端口映射
podman port web

# 复制文件进出容器
podman cp ./config.yml web:/etc/app/config.yml
podman cp web:/var/log/app.log ./

# 导出容器为新镜像(把改动固化下来)
podman commit web my-web:v1

给新手的建议:先把 run / ps / logs / exec / stop / rm / images / rmi 这 8 个命令练熟,日常 90% 的操作就够了。


六、镜像:构建、推送与导入导出

6.1 写第一个 Containerfile

Podman 用 Containerfile(和 Dockerfile 完全同格式,只是名字更中性):

# Containerfile
FROM docker.io/library/python:3.13-slim

WORKDIR /app

# 先拷依赖清单,利用层缓存
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

# 再拷代码
COPY . .

EXPOSE 8000
CMD ["python", "-m", "http.server", "8000"]

构建:

podman build -t myapp:v1 .

💡 几点新手要点:

  • .containerignore 与 .dockerignore 作用一致,用来排除不需要进镜像的文件(如 .git、node_modules),能显著减小体积、加快构建
  • 层缓存:把变化少的指令(装依赖)放前面,变化多的(拷代码)放后面
  • 镜像名规范:podman build 时不写仓库前缀,默认是本地镜像;要推送必须带注册表前缀

6.2 完整镜像名长什么样

片段名称说明
docker.io注册表(registry)不写默认 Docker Hub
/library命名空间官方镜像在 library 下,不写默认
nginx仓库名(repository)镜像名
:alpine标签(tag)不写默认 latest

所以 nginx:alpine 的完整形式是 docker.io/library/nginx:alpine。 理解这一点,后面配私有仓库就不会懵。

⚠️ 生产环境别用 latest:它会随上游更新而变化,今天跑通的版本明天可能挂。永远锁具体标签(如 nginx:1.27-alpine),或者直接用 digest(nginx@sha256:...)。

6.3 推送到 Docker Hub 或私有仓库

# 登录
podman login docker.io
# 或私有仓库
podman login registry.example.com -u myuser

# 打标签(必须带注册表前缀)
podman tag myapp:v1 docker.io/myusername/myapp:v1

# 推送
podman push docker.io/myusername/myapp:v1

💡 登录凭据存在哪:默认在 ${XDG_RUNTIME_DIR}/containers/auth.json,比 Docker 的明文 ~/.docker/config.json 更安全。可以配 podman login --get-login 查看当前登录用户。

6.4 镜像搬运三件套(Podman 的独门优势)

场景:把镜像从 A 仓库同步到 B 仓库,中间不想落地、不想跑容器。

# 用 skopeo:直接从源仓库复制到目标仓库
skopeo copy docker://docker.io/library/nginx:alpine \
           docker://registry.example.com/mirror/nginx:alpine

# 只看远程镜像信息,不下载镜像本体
skopeo inspect docker://docker.io/library/nginx:alpine

# 列出远程仓库所有标签
skopeo list-tags docker://docker.io/library/nginx

场景:离线环境传输。

# 有网机器:导出成 tar
podman save -o nginx.tar docker.io/library/nginx:alpine

# 离线机器:导入
podman load -i nginx.tar

# 也可以用 skopeo 直接导出为归档
skopeo copy docker://docker.io/library/nginx:alpine \
            docker-archive:nginx.tar:nginx:alpine

这就是 buildah + skopeo 的价值:它们把"构建"和"搬运"从"运行"里拆了出来,做 CI 时特别顺手。


七、进阶重点:Pod、compose 与 systemd

这一节是 Podman 真正区别于 Docker 的地方。如果只学一个进阶功能,我建议学 Pod。

7.1 Pod:Podman 的特色功能

Pod 是一组共享网络与命名空间的容器集合。 这个概念来自 Kubernetes——同一个 Pod 里的容器像"住在同一间房":共享 IP、共享端口空间、可以用 localhost 互相访问。

# 1. 创建一个 Pod,把 8080 端口暴露在 Pod 层面
podman pod create --name mypod -p 8080:80

# 2. 往 Pod 里塞两个容器(注意:端口已由 pod 占用,容器内不再写 -p)
podman run -d --pod mypod --name web nginx:alpine
podman run -d --pod mypod --name logger alpine sh -c 'while true; do echo hi; sleep 5; done'

# 3. 看 Pod 及其内部的容器
podman pod ps
podman ps --pod

# 4. 在 Pod 内一个容器里访问另一个
podman exec web curl -s http://localhost:80 | head -3

为什么有用:这正是 Kubernetes 里 Pod 的模型。你在本地用 podman pod 练会了,上 K8s 时概念是通的。而且 podman generate kube 能直接把 Pod 导出成 K8s YAML:

podman generate kube mypod > mypod.yaml     # 导出为 Kubernetes 清单
podman play kube mypod.yaml                 # 从 K8s 清单直接拉起

这是 Podman 最漂亮的用法之一:本地开发 → 一键生成 K8s 清单 → 直接上集群。

7.2 compose:怎么用 docker-compose.yml

Podman 本身不内置 compose,但有两条路:

方式一:podman-compose(轻量,独立实现)

pip install podman-compose
# 或
sudo apt install -y podman-compose

podman-compose up -d
podman-compose down
podman-compose ps

它读取同样的 docker-compose.yml / compose.yaml,把每个 service 翻译成 podman run。

方式二:podman compose(推荐,作为 docker-compose 的前端)

新版本 Podman 提供了 podman compose 子命令,它会调用系统上已安装的 compose provider(docker-compose 或 podman-compose),兼容性更好:

podman compose up -d
podman compose down

Podman Desktop 里还支持一键把 compose 项目转成 Pod,图形化点几下就行。

⚠️ 兼容性提醒:podman-compose 对复杂 compose 特性(depends_on 的健康检查条件、某些 deploy 段、profiles)支持不如 Docker Compose 完整。如果你的 compose 文件很复杂,建议直接用 podman compose 走 docker-compose provider,或干脆评估是否留用 Docker。

7.3 systemd 集成:让容器开机自启

这是 Podman 比 Docker 更优雅的地方——把容器变成真正的 systemd 服务。

方式一:Quadlet(Podman 4.4+ 起推荐,Podman 5+ 是主流做法)

在 ~/.config/containers/systemd/web.container 写声明式配置:

[Unit]
Description=Nginx Web Container

[Container]
Image=docker.io/library/nginx:alpine
PublishPort=8080:80
Volume=%h/html:/usr/share/nginx/html:ro

[Service]
Restart=always

[Install]
WantedBy=default.target

然后:

systemctl --user daemon-reload
systemctl --user start web.service
systemctl --user enable web.service       # 开机自启
systemctl --user status web.service

💡 命名规则很关键:.container 文件生成的服务名 = 文件名 + .service(web.container → web.service),不要自己去 enable 一个不存在的同名服务。

💡 还想让用户退出登录后容器继续跑(服务器场景):

sudo loginctl enable-linger $USER

方式二:podman generate systemd(旧版方式,仍可用)

podman generate systemd --new --name web --files
# 会把 web.service 生成到当前目录,拷到 ~/.config/systemd/user/ 后 daemon-reload 即可

⚠️ podman generate systemd 在新版本中已被标记为 deprecated,新项目请优先用 Quadlet。

方式三:Linux 系统级服务(root 运行)

如果确实需要 root 容器(如监听 80 端口),可以 sudo podman ... + 放 /etc/systemd/system/。但优先考虑 rootless + 端口转发,安全性更好。


八、rootless 权限模型:新手最容易卡的地方

这一节专门给被"权限不够"卡住的人。

8.1 rootless 是怎么做到的

Linux 内核从 3.8 起提供 user namespace(用户命名空间)。Podman 利用它做了一层 UID 映射:

你在容器里是 root(UID 0),但在宿主机上实际只是你的普通用户(UID 1000)。 就算容器里把 root 玩坏了,攻击者拿到的也只是你这份普通权限,碰不到系统。

这个映射区间记录在 /etc/subuid 和 /etc/subgid 里:

grep $USER /etc/subuid /etc/subgid
# 应输出类似:youruser:100000:65536

如果这里是空的,rootless 会出问题。 修复:

sudo usermod --add-subuids 100000-165535 --add-subgids 100000-165535 $USER
podman system migrate     # 重建存储

8.2 三个高频权限坑

坑 1:绑定挂载后容器写不进去

现象:

podman run -v $(pwd)/data:/data alpine touch /data/test.txt
# touch: /data/test.txt: Permission denied

原因:宿主机目录属于 UID 1000,但容器里你是 UID 0,映射后实际身份对不上宿主机文件属主。

三种解法(按推荐度排):

# 解法一(推荐):让容器以宿主机 UID 运行
podman run --userns=keep-id -v $(pwd)/data:/data alpine touch /data/test.txt

# 解法二:指定容器内用户与你的 UID 一致
podman run --user $(id -u):$(id -g) -v $(pwd)/data:/data alpine touch /data/test.txt

# 解法三:只读挂载(不需要写就用这个)
podman run -v $(pwd)/data:/data:ro alpine ls /data

💡 --userns=keep-id 是 rootless 场景下的万能解:它让容器里的 UID 直接等于你在宿主机的 UID,文件权限就对上了。

坑 2:想监听 1024 以下端口(如 80、443)

rootless 默认不允许绑定特权端口。

# 方案一:宿主端口用高位(最常用)
podman run -d -p 8080:80 nginx:alpine        # 宿主 8080 转发到容器 80

# 方案二:放行低位端口(一次性配置)
sudo sysctl -w net.ipv4.ip_unprivileged_port_start=80
# 永久生效:写入 /etc/sysctl.d/

# 方案三:用 systemd socket 激活或反向代理(生产更推荐)

坑 3:Podman Desktop 连不上 Podman

在 Windows 上,Podman Desktop 通过 socket 与 Podman 通信,依赖 dbus;dbus 不可用时会连接失败。

排查顺序:

# 1. 确认 machine 在跑
podman machine list

# 2. 看 socket 是否存在
podman info --format '{{.Host.RemoteSocket.Path}}'

# 3. 重启 machine 与 Desktop
podman machine stop && podman machine start

如果仍然连不上,优先检查是不是走 WSL2 路线——WSL2 里的 Podman 与外层 Desktop 的对接最容易出问题。最简单的绕法是:直接在 WSL2 里用命令行 Podman,不依赖 Desktop 的 GUI。


九、常见问题与排错清单

下面这张表是新手最可能撞上的问题,建议自查时直接对照。

现象可能原因解法
podman ps 什么都没有容器无前台进程已退出podman ps -a 看状态;交互式要加 -it,长驻进程要加 -d
Cannot connect to Podman socketmachine 未启动 / socket 路径错podman machine start;podman info 核对 socket
Error: image not known镜像名或标签拼错 / 未 pull先 podman pull,或用完整名 docker.io/library/nginx:alpine
Permission denied 挂载目录rootless UID 不匹配加 --userns=keep-id 或 --user $(id -u):$(id -g)
端口映射不生效-p 写反 / 防火墙 / 容器内未监听确认 -p 宿主:容器;podman port <容器> 核对
拉镜像超时 / TLS 错误网络 / 代理 / 证书吊销检查配 ~/.config/containers/registries.conf 镜像加速;必要时设 SSL_CERT_FILE
磁盘被撑满悬空镜像 + 停止的容器堆积podman system df 看占用;podman system prune -a 清理
subuid/subgid 相关报错/etc/subuid 未配置usermod --add-subuids/--add-subgids + podman system migrate
compose 启动失败podman-compose 兼容性不足改用 podman compose(走 docker-compose provider)
容器时间/时区不对未挂载时区-v /etc/localtime:/etc/localtime:ro -e TZ=Asia/Shanghai
中文乱码容器内缺 locale-e LANG=C.UTF-8

9.1 三个必备诊断命令

# 1. 看环境全貌(runtime、rootless、存储驱动、socket)
podman info

# 2. 看某容器为什么起不来(重点看 State 与 LogPath)
podman inspect mycontainer | head -50
podman logs mycontainer

# 3. 看磁盘占用明细
podman system df

9.2 调试容器的正确姿势

# 不进容器、只覆盖入口命令,看看环境长什么样
podman run --rm -it --entrypoint sh nginx:alpine
# 注意:基础镜像如果没有 sh(如 scratch),这条会失败

# 保留退出后的容器,方便事后 inspect
podman run --name debug1 nginx:alpine   # 不加 --rm

# 看容器退出码与原因
podman inspect debug1 --format '{{.State.ExitCode}} / {{.State.Error}}'

# 实时资源占用
podman stats --no-stream

💡 一条通用排错思路:先把 -d 去掉、把 --rm 去掉、把入口换成 sh,让容器"停在那里"让你看。这比盯着报错猜快得多。


十、从 Docker 迁移:一份可直接执行的清单

如果你决定从 Docker 转 Podman,不用一次全换,按这个顺序走最稳。

10.1 迁移前的心理准备

项目迁移难度说明
日常 docker run/ps/logs/exec⭐ 极低换名即用
Dockerfile / Containerfile⭐ 极低同格式
docker-compose.yml⭐⭐⭐ 中简单文件没问题,复杂编排要测
数据卷与镜像⭐⭐ 低可 save/load 或重新拉取
CI/CD 脚本⭐⭐ 低换命令名即可,或装 podman-docker
Kubernetes 本地开发⭐⭐⭐⭐ 较高依赖 kind/minikube 的链路要单独评估

10.2 五步迁移法

第 1 步:共存,不拆 Docker

先把 Podman 装上,让两者并存。 不要一上来就卸 Docker,否则出问题没法回退。

# Linux 上装 Podman(前面第三节的命令)
sudo apt install -y podman
podman run --rm hello-world      # 确认独立可用

第 2 步:把现有镜像与卷搬过来

# 导出 Docker 镜像列表并逐个搬运
docker images --format '{{.Repository}}:{{.Tag}}' | grep -v '<none>' > images.txt

while read img; do
  podman pull "docker.io/$img" || echo "FAILED: $img"
done < images.txt

卷的数据建议用应用层方式迁移(如 pg_dump)而不是直接拷目录,更可靠。

第 3 步:批量验证日常命令

把常用脚本里的 docker 换成 podman,跑一遍。新版本 Podman 提供了自动检测命令:

podman-compose --help      # 若用 compose
podman system check        # 检查存储健康

第 4 步:决定 compose 路线

# 试跑现有 compose 文件
podman compose up -d
podman compose ps

# 若报错,逐项比对不支持的特性

第 5 步:迁移 systemd 服务与清理

# 把需要开机自启的容器改成 Quadlet
mkdir -p ~/.config/containers/systemd
# 写 web.container(见 7.3)

systemctl --user daemon-reload
systemctl --user enable --now web.service
sudo loginctl enable-linger $USER

# 确认新服务稳定运行一周后,再考虑卸载 Docker Desktop

10.3 兼容层:让 docker 命令指向 Podman

# Linux
sudo apt install -y podman-docker    # 或 dnf install podman-docker
docker --version                     # 会显示 podman 的版本

⚠️ 注意:装 podman-docker 前先卸掉 Docker 的 docker CLI,否则会造成命令冲突(谁后装谁被覆盖,或直接报错)。这一步放在迁移的最后,且确认不再需要 Docker 之后再做。

10.4 别名兜底:最温和的过渡

不想动系统配置,可以在 ~/.bashrc / ~/.zshrc 里加别名:

alias docker=podman
alias docker-compose='podman compose'

这样你的所有习惯都能保留,行为却已经是 Podman。 成本最低,随时 unalias 回退。


十一、该不该换:适用与不适用场景

最后给一个决策参考,避免为了换而换。

11.1 强烈推荐用 Podman 的场景

具体来说,这些场景特别合适:

  • 安全敏感的环境:CI/CD 流水线、多租户开发机、给实习生开放的环境
  • 企业授权受限:不想为 Docker Desktop 商业授权付费
  • 个人开发与学习:完全免费,且能顺便理解 K8s 的 Pod 模型
  • 服务器上的常驻服务:systemd 集成比 Docker 更原生
  • 本地 K8s 开发:podman generate kube 这条捷径非常省事
  • 高性能计算 / 共享集群:rootless 无需管理员权限

11.2 建议暂时留用 Docker 的场景

  • 重度依赖 Docker Compose 全部特性(复杂 depends_on 健康检查、profiles、deploy 段)
  • 本地 K8s 工具链深度绑定 Docker(kind、minikube、部分 IDE 插件)
  • 团队协作规范已围绕 Docker 建立,迁移沟通成本高于收益
  • 依赖 Docker Desktop 独有功能(如某些扩展、内置 K8s 一键集群)

11.3 一个务实的结论

不用二选一。 Podman 和 Docker 可以在同一台机器上共存——新项目用 Podman,老项目继续用 Docker,慢慢迁。

对新手来说,最佳路径是:先装 Podman(或已在用的 WSL2 里装一个),用 hello-world、nginx、postgres 三个镜像把 run / ps / logs / exec / stop / rm 练熟。当你发现"我敲的命令和 Docker 一模一样,但少了一个常驻进程、还不用 root"的时候,这次迁移就已经值了。


附:速查卡

把下面这段存成 ~/.bashrc 的备忘,或抄在便签上:

# ===== Podman 新手速查 =====
podman run --rm hello-world              # 冒烟测试
podman run -it --rm ubuntu:24.04 bash    # 交互式
podman run -d --name web -p 8080:80 nginx:alpine   # 后台 + 端口
podman run -d --name db -v pgdata:/var/lib/postgresql/data -e POSTGRES_PASSWORD=x postgres:16
podman run --userns=keep-id -v $(pwd)/data:/data alpine   # 解决挂载权限

podman ps -a                             # 全部容器
podman logs -f web                       # 跟踪日志
podman exec -it web sh                   # 进容器
podman stats                             # 资源占用
podman port web                          # 端口映射

podman stop web && podman rm web         # 停 + 删
podman images                            # 镜像列表
podman rmi nginx:alpine                  # 删镜像
podman system df                         # 磁盘占用
podman system prune -a                   # 大扫除(谨慎)

podman pod create --name mypod -p 8080:80   # 创建 Pod
podman generate kube mypod > mypod.yaml     # 导出 K8s 清单

podman machine list / start / stop       # Windows/macOS 虚拟机
podman info                              # 环境诊断

官方资源

资源地址
项目官网https://podman.io
GitHub 仓库https://github.com/containers/podman
官方文档https://docs.podman.io
Podman Desktophttps://podman-desktop.io
镜像仓库https://hub.docker.com(Podman 兼容 Docker Hub)

版本提示:本文示例基于 Podman v5/v6 语法。podman generate systemd 已在 v5 起标记为 deprecated,新项目请用 Quadlet;podman compose 需要系统上装有 docker-compose 或 podman-compose 作为 provider。不同发行版打包版本差异较大(Ubuntu 官方源常落后),涉及 Desktop 联调时请优先安装较新版本。