饮墨

子安饮墨馀三斗,留与卿儿作赋来

3 个运维场景用 Podman 替代 Docker:无 daemon、rootless、systemd 原生集成实操

痛点

Docker 在生产环境有几个绕不开的问题:

  1. dockerd 单点故障 — daemon 挂了,所有容器失联,docker ps 都执行不了,运维只能盲操作
  2. Root 权限依赖 — 默认要 root 或 docker 组,一旦容器逃逸直接拿到宿主机最高权限
  3. 与 systemd 割裂 — 容器生命周期靠 dockerd 管理,和系统服务管理体系两套逻辑,重启策略、日志收集都要单独配

Podman 是红帽主导的开源容器引擎,API 兼容 Docker,但架构完全不同 — 无 daemon、fork-exec 模型、原生支持 rootless 和 systemd 集成。以下用 3 个实操场景说明怎么迁移。

方案概览

对比项 Docker Podman
架构 C/S,依赖 dockerd 无 daemon,直接调用 OCI runtime
权限 默认需 root 原生 rootless
systemd 集成 需第三方工具 podman generate systemd 原生生成
CLI 兼容 alias docker=podman 直接替换
镜像格式 OCI/Docker OCI/Docker(完全兼容)

实操步骤

场景一:无 daemon 运行容器(消除单点故障)

# CentOS/RHEL 9+ / Fedora
sudo dnf install -y podman

# Ubuntu 22.04+
sudo apt install -y podman

# 验证安装(注意没有任何 daemon 进程)
podman --version
# podman version 4.9.3

# 直接运行容器 — 无需启动任何后台服务
podman run -d --name nginx-test -p 8080:80 docker.io/library/nginx:alpine

# 验证容器运行
podman ps
curl -s http://localhost:8080 | head -5

# 关键区别:kill 掉 podman 进程,容器依然运行
# 因为容器进程由 conmon 托管,和 podman CLI 解耦
ps aux | grep conmon

场景二:Rootless 容器(非 root 用户运行生产服务)

# 用普通用户运行(无需 sudo、无需加入 docker 组)
# 前提:确保 /etc/subuid 和 /etc/subgid 已配置
grep $USER /etc/subuid
# ops:100000:65536

# 如果没有,手动添加:
sudo usermod --add-subuids 100000-165535 --add-subgids 100000-165535 $USER

# 普通用户直接运行容器
podman run -d --name redis-rootless \
  -p 6379:6379 \
  docker.io/library/redis:7-alpine

# 验证:容器进程属于当前用户,非 root
ps aux | grep redis-server
# ops  12345  ... redis-server

# 端口绑定 >1024 无需特权;如需 80/443,用 sysctl 放开:
sudo sysctl net.ipv4.ip_unprivileged_port_start=80

场景三:systemd 原生集成(容器即服务)

# 先创建容器
podman create --name monitoring-agent \
  -v /proc:/host/proc:ro \
  -p 9100:9100 \
  docker.io/prom/node-exporter:latest \
  --path.procfs=/host/proc

# 生成 systemd unit 文件
podman generate systemd --new --name monitoring-agent \
  --restart-policy=always > ~/.config/systemd/user/container-monitoring-agent.service

# 启用并启动(用户级 systemd,无需 root)
systemctl --user daemon-reload
systemctl --user enable --now container-monitoring-agent.service

# 查看状态 — 和普通 systemd 服务一样管理
systemctl --user status container-monitoring-agent

# 设置 lingering,让用户服务在登出后持续运行
sudo loginctl enable-linger $USER

# 日志直接走 journald,统一收集
journalctl --user -u container-monitoring-agent -f

避坑指南

坑 1:镜像拉取默认不走 Docker Hub

Podman 默认搜索多个 registry,可能报 short-name resolution 错误。

# 解决:指定完整镜像路径
podman pull docker.io/library/nginx:alpine  # ✅
podman pull nginx:alpine                     # ❌ 可能交互确认

# 或配置默认 registry
cat >> /etc/containers/registries.conf <<EOF
unqualified-search-registries = ["docker.io"]
EOF

坑 2:Rootless 模式下 volume 权限问题

容器内 UID 经过 user namespace 映射,挂载目录可能出现权限拒绝。

# 现象
podman run -v /data/app:/app myimage
# Permission denied

# 解决:用 :Z 标签让 Podman 自动修复 SELinux 上下文
podman run -v /data/app:/app:Z myimage

# 或使用 --userns=keep-id 保持 UID 映射一致
podman run --userns=keep-id -v /data/app:/app myimage

坑 3:Docker Compose 项目迁移

Podman 4.x+ 原生支持 podman compose,但部分 Compose 特性有差异。

# 安装 podman-compose(Python 实现)
pip install podman-compose

# 或使用 Docker Compose 本身(Podman 提供 socket 兼容)
systemctl --user enable --now podman.socket
export DOCKER_HOST=unix://$XDG_RUNTIME_DIR/podman/podman.sock
docker-compose up -d  # 直接使用原有 docker-compose.yml

总结

迁移场景 核心收益 迁移成本
无 daemon 消除 dockerd 单点,容器独立存活 几乎为零,CLI 兼容
Rootless 容器逃逸也只拿到普通用户权限 需配 subuid/subgid,注意 volume 权限
systemd 集成 容器即服务,统一生命周期和日志 一条命令生成 unit 文件

迁移建议:新部署直接用 Podman;存量 Docker 环境先在非核心服务试点,alias docker=podman 验证兼容性后再全量切换。对于 K8s 节点,containerd 仍是首选运行时,Podman 更适合单机或边缘节点的容器化场景。

您还没有登录,请登录后发表评论。