1.2 Podman 的出身与三条设计信条


1.2 Podman 的出身与三条设计信条

本节摘要:Podman 诞生于 Red Hat 与 Docker 公司维护合作破裂的 2016 年前后,最初只是 libpod 库,后成长为完整容器引擎。它带着三条明确的设计信条:无守护进程(Fork-Exec)、默认最小权限(rootless 优先)、命令行兼容(Docker 用户的肌肉记忆可以直接复用)。本节讲清三条信条的来龙去脉,以及它们各自对应第 1.1 节账单的哪一栏。

一段被动的出身,一次主动的转向

Podman 的历史常被讲成"Red Hat 看不惯 Docker 就自己写了一个",真实版本更曲折。2016 年前后,Red Hat 在 RHEL 中维护 Docker 的成本越来越高:Docker 引擎把客户端、守护进程、镜像分发、构建逻辑全部揉在一个快速迭代的大二进制里,每次上游更新都牵动发行版的稳定性承诺。双方在拆分与维护方式上没能达成一致,Red Hat 最终决定自建工具链——先有了专注镜像传输的 Skopeo,再有了专注构建的 Buildah,而运行与管理容器的部分,最初只是两者共用的一个库,名字叫 libpod。

2018 年前后 libpod 长出了 CLI,改名 Podman 发布。所以 Podman 不是从零设计的"反 Docker 产品",它是把 Docker 一体化引擎按 Unix 哲学拆开之后,"运行与管理"那一块的独立成品。这个出身解释了它的很多气质:与 Buildah、Skopeo 共享存储与镜像格式(第 3 章),没有自己的守护进程(本章),对 Docker CLI 高度兼容(本节)。

验证这个出身最直接的办法是看版本与运行时信息:

# 查看 Podman 版本与它调用的 OCI 运行时 podman version # Client: 4.9.4-rhel # API Version: 4.9.4-rhel # Go Version: go1.21.9 # Built: Wed May 1 00:00:00 2024 # OS/Arch: linux/amd64 podman info --format '{{.Host.OCIRuntime.Name}} {{.Host.OCIRuntime.Version}}' # crun 1.14.4 # 解读:Podman 自己不创建容器进程,它调用 OCI 运行时 crun 完成。 # 这印证了它的定位——管理器与编排器,而不是运行时本身

信条一:无守护进程

Podman 把"没有 daemon"放在一切设计之前。执行 podman run 时,CLI 进程 fork/exec 出 OCI 运行时,容器进程成为该调用链的子进程,命令结束后容器由独立的监控进程 conmon 照看(第 2 章解剖它)。第 1.1 节账单的第一栏(单点故障)就此消失:没有常驻管理面,就没有管理面的升级窗口与崩溃半径。

工程上要为这条信条付出的代价也不少:状态(容器列表、卷、网络)全部落在文件系统与数据库文件里而不是守护进程内存里;API 服务变成可选组件按需启动(第 10 章);跨进程的容器操作要靠文件锁协调。这些代价换来的收益贯穿全册。

信条二:默认最小权限

第二条信条更激进:Podman 的 rootless 模式不是"高级特性",而是普通用户的默认体验。一个从未配置过任何东西的普通账号,登录后直接 podman run 就能跑容器——容器内的 root 通过用户命名空间映射到宿主机的无特权高位 UID。账单第二栏(逃逸放大)与第三栏(socket 越权)同时失效:没有 root socket 可挂载,没有宿主机 UID 0 可继承。

信条二的另一面是诚实的局限:rootless 模式绑定特权端口(1024 以下)、挂载某些文件系统、访问某些设备时会受限。Podman 的态度是不掩盖差异——能做就做,做不了就明确报错,而不是悄悄提权。第 2.2 节会展开这些边界的成因与绕法。

信条三:命令行兼容

第三条信条最务实:Docker 十年积累的用户习惯不该被浪费。podman runpodman buildpodman pspodman exec 的参数与语义和 Docker 高度一致,官方甚至建议直接 alias docker=podman 让脚本无感切换。下面这段实验可以立刻验证兼容的边界:

# 一行别名之后,肌肉记忆完全复用 alias docker=podman docker run --rm alpine:3.19 echo "compatibility check" # compatibility check # 输出正常——run、echo、--rm 语义一致 # 但兼容不是全等:查一下各自的存储位置 docker info | grep -i "graph\|store" # graphRoot: /home/dev/.local/share/containers/storage # 解读:rootless 模式下镜像与容器层放在用户家目录, # 与 Docker 的 /var/lib/docker 互不可见。命令兼容,状态不共享

这个实验值得每个迁移者亲手做一次:它同时展示了信条三的诚意(命令层无感)与边界(数据层是两套独立世界)。镜像互不通用是迁移时最常被问的问题之一,答案在第 5 章与第 9 章。

三条信条与账单的对应关系

设计信条 针对的账单栏目 直接机制 付出的代价
无守护进程 单点故障 Fork-Exec,容器是用户进程的子进程 状态管理落到文件与锁
默认最小权限 逃逸放大、socket 越权 用户命名空间 UID 映射 特权端口等操作受限
命令行兼容 迁移成本 保留 Docker CLI 习惯与语义 数据目录互不相通

三条信条不是并列的口号,而是互相支撑的整体:没有守护进程,最小权限才可能成为默认(不存在一个需要特权的常驻管理面);最小权限成为默认,命令兼容才敢做到如此彻底(反正出不了安全格)。理解了这个整体性,后续章节里那些"奇怪的设计"——比如 conmon 的存在理由、Quadlet 的形态——都会变得顺理成章。

本节要点回顾

  • 出身决定气质:Podman 从 libpod 库成长为引擎,是 Docker 一体化架构被 Unix 哲学拆解后的产物
  • 无守护进程是第一信条:容器是调用链的子进程,状态落文件系统,没有管理面单点
  • rootless 是默认而非特性:普通用户开箱即用,容器 root 映射为宿主机无特权 UID
  • 兼容是立场性的:命令习惯全保留,但存储目录、状态数据是两套独立世界
  • 三条信条互为前提:去掉了守护进程,最小权限才可能成为默认体验

作者与出处
原作者: 灏天文库
来源:灏天文库
整理: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U