从容器与镜像开始,区分 Podman 的本地管理模式、rootless 权限和可选 API 服务。
前置:什么是容器?(零基础版)#
一个比喻
想象你给朋友寄一台组装好的电脑。有两个方案:
- 虚拟机:把整台电脑(含机箱、电源、主板)装箱寄走 → 笨重,每台电脑都自带完整操作系统
- 容器:把 CPU + 内存 + 硬盘拆下来,装进统一规格的泡沫箱寄走 → 轻量,只包含应用程序和它的直接依赖
容器的核心思想:把应用程序和它需要的所有依赖打成一个标准包,在支持相应 CPU 架构、内核能力和运行时条件的 Linux 环境中提供一致的用户态依赖。
容器 vs 虚拟机
虚拟机:
┌─────────────────────────────┐
│ App A │ App B │ ← 每个 App 带自己的 OS
├──────────┼──────────────────┤
│ Guest OS │ Guest OS │ ← 完整操作系统(几 GB)
├──────────┴──────────────────┤
│ Hypervisor (KVM/VirtualBox) │
├─────────────────────────────┤
│ Host OS (Linux) │
└─────────────────────────────┘
容器:
┌────────────┬────────────┐
│ App A │ App B │ ← 各自独立的依赖
├────────────┴────────────┤
│ Container Runtime │ ← 轻量运行时
├─────────────────────────┤
│ Host OS (Linux) │ ← 只有一个操作系统
└─────────────────────────┘关键区别:容器共享宿主机的 Linux 内核,不需要每个容器里装一个完整操作系统。所以:
- 容器通常省去独立 guest kernel 的启动成本,轻量任务常启动较快。
- 实际时间受镜像拉取、应用初始化、挂载和网络影响。
- 可运行数量取决于工作负载、内存和资源限制,不能用固定内存容量推出实例数。
容器的两个核心原料
- 镜像 (Image):一个只读的模板,包含运行程序所需的一切——代码、库、配置文件。比如
docker.io/library/nginx:alpine镜像里包含了 Nginx Web 服务器和它需要的所有文件。 - 容器 (Container):镜像的"运行实例"。镜像像程序安装包,容器像正在运行的程序本身。
# 镜像 → 容器 的关系
podman pull docker.io/library/nginx:alpine # 下载镜像(安装包)
podman run docker.io/library/nginx:alpine # 从镜像启动容器(运行程序)Podman 是什么?#
Podman(Pod Manager) 是 Red Hat 开源的容器管理工具。它的命令行接口和 Docker 几乎完全相同——大多数情况下你只需要把 docker 换成 podman。
但这只是表面。Podman 和 Docker 的底层架构完全不同。
核心差异:Daemonless 架构
graph TD
subgraph "Docker 架构"
DC["docker CLI"] -->|REST API| DD["dockerd<br/>守护进程<br/>(通常常驻,可 rootful/rootless)"]
DD -->|gRPC| CR["containerd"]
CR --> RUNC["runc"]
end
subgraph "Podman 架构"
PC["podman CLI"] -->|直接 fork/exec| PM["conmon<br/>容器监控进程"]
PM --> CRUN["crun / runc"]
endDocker 的问题:
- 本地 Docker CLI 通常通过
dockerd的 API 管理资源;daemon 有管理状态与资源成本。 - 常见 rootful Docker daemon 具有宿主管理员能力;Docker 也提供 rootless 模式。
- daemon 不可用会影响管理操作;已运行容器是否持续运行受 live-restore 与运行时设计影响,不能概括为全停。
dockerd的 API socket 是著名的安全攻击面
Podman 的做法:
- 本地 CLI 管理不要求常驻中心 daemon,但运行容器仍有 conmon/OCI runtime 等进程。
- 普通用户可以运行 rootless Podman;具体容器 UID 还取决于 userns 映射及镜像应用用户。
- 一个容器挂掉不影响其他容器
- API socket 和远程工作流可按需启用 Podman 服务,不等于完全没有后台进程。
一句话总结
Docker 是"客户端-服务器"模式(你告诉管家去干活),Podman 是"直接执行"模式(你自己干活)。这是管理入口的差别,安全性仍需按 rootful/rootless、socket 权限和运行配置判断。
Rootless:不需要 root 就能跑容器#
这是 Podman 在安全方面的最大卖点。
什么是 Rootless?
未启用用户命名空间映射的 rootful 配置中,容器 UID 0 对应宿主 UID 0,但仍受 namespace、capabilities、seccomp 和 SELinux 等限制。危险尤其来自过宽的宿主挂载和额外权限:
- 删除容器自己的
/通常影响其文件系统视图;若可写挂载宿主目录,则可能破坏该目录数据。 - 可写宿主挂载结合高权限可能暴露宿主文件,必须限制授权范围。
Podman 的 Rootless 模式下,容器内的 root 被映射为宿主机上一个普通用户。容器进程"以为"自己是 root,实际上在宿主机只是普通用户权限。
默认 rootful 无 userns 映射:容器 UID 0 通常对应宿主 UID 0
默认 rootless 映射:容器 UID 0 通常对应调用者普通 UID实际效果:rootless 降低宿主管理员权限暴露,但共享内核、可访问 socket 和用户数据仍是风险;不能视为容器被攻破后的绝对隔离保证。
用户映射的关键前提
/etc/subuid 和 /etc/subgid 文件为每个用户分配了一段"虚拟 UID 范围":
# /etc/subuid
user:100000:65536
# 含义:user 可以"扮演"100000 到 165535 这 65536 个 UID
# subordinate 区间不意味着 UID 0 自动映射到 100000;默认通常把调用者映射为容器 root创建 rootless 容器时,Podman 自动使用 newuidmap/newgidmap 设置用户命名空间隔离。
版本变化:不要把所有新特性归入 5.0#
| 变化 | 影响 |
|---|---|
| SQLite 数据库 | 5.0 完成新的容器状态数据库迁移方向;不是直接把镜像层存储称为 SQLite |
| Podman Machine | VM provider、平台支持和启动表现依具体版本与平台 |
native podman quadlet 命令 |
较新版本提供管理 Quadlet 文件的命令;install、生成与启动仍需分别核对 |
| Quadlet 生产推荐 | podman generate systemd 已弃用,Quadlet 是官方推荐方式 |
| Podman AI Lab | Podman Desktop 生态的独立扩展,不等于 5.0 核心引擎能力 |
什么时候用 Podman,什么时候用 Docker?#
| 场景 | 推荐 | 理由 |
|---|---|---|
| 学习容器 | Podman | OCI 工具链与常用 CLI 接近,适合已有 Linux 环境 |
| 个人开发环境 | Podman | 可 rootless 本地使用,不要求常驻中心 daemon |
| 公司必须用 Docker | Docker | 团队统一工具链 |
| 需要 Docker Swarm | Docker | Podman 不支持 Swarm |
| CI/CD 流水线 | Podman | 本地构建可不依赖 daemon socket,仍须限制构建与凭据权限 |
| 生产服务器部署 | Podman + Quadlet | 适合 Linux/systemd 的声明资源管理,需验证应用需求 |
| 用 VS Code Dev Containers | 都可以 | 需按工具与版本验证 CLI/API 兼容性 |
参考与延伸
根据技术笔记重新整理,示例使用通用名称。