TL;DR
Podman 是无守护进程、默认 Rootless 的容器引擎,提供 Docker 兼容 CLI 而无需后台守护进程。由 Red Hat 开发,使用用户命名空间将容器作为普通用户进程运行。原生支持 Pod、Kubernetes YAML、Quadlet systemd 集成和 Buildah OCI 镜像构建。2026 年 Podman 5.x 是 Fedora/RHEL/CentOS Stream 默认运行时。
Key Takeaways
- 无守护进程 — 容器作为用户子进程运行
- Rootless 使用用户命名空间,无需 root
- Docker 兼容 CLI — alias docker=podman
- 原生 Pod 支持,共享网络/IPC 命名空间
- podman generate/play kube 连接本地与 K8s
- Quadlet systemd 集成,容器即服务
Podman 是 Red Hat 开发的开源容器引擎,已成为 RHEL、Fedora 和 CentOS Stream 的默认容器工具。与 Docker 不同,无需中央守护进程——每个容器直接作为用户子进程运行。拥有 25,000+ GitHub 星标、Docker 兼容 CLI、原生 Pod 支持和深度 Kubernetes 集成。
什么是 Podman 及为什么无守护进程很重要
Podman 是 OCI 兼容的容器引擎。与 Docker 关键区别:Docker CLI 与 root dockerd 守护进程通信,Podman 完全消除守护进程——容器进程直接 fork 为子进程。
无守护进程设计意味着没有特权进程被攻破的风险。容器隔离在用户进程树中,没有单点故障。
- 无守护进程
- 默认 Rootless
- Docker 兼容 CLI
- 原生 Pod
- K8s 集成
- Buildah 镜像构建
- systemd Quadlet
Podman vs Docker vs containerd vs nerdctl
了解容器工具生态有助于选择。
| 特性 | Podman | Docker | containerd | nerdctl |
|---|---|---|---|---|
| 守护进程 | 否 | 是 | 是 | 用containerd |
| Rootless | 原生 | 实验性 | rootlesskit | rootlesskit |
| CLI | Docker兼容 | docker | ctr | Docker兼容 |
| Pod | 原生 | 否 | 否 | 否 |
| K8s YAML | generate/play | 否 | 否 | 否 |
| Compose | podman-compose | docker compose | 否 | nerdctl compose |
| 构建 | Buildah | BuildKit | 需buildkit | BuildKit |
| Systemd | Quadlet | 手动 | 手动 | 手动 |
| GUI | Podman Desktop | Docker Desktop | 无 | 无 |
| 许可证 | Apache 2.0 | Apache 2.0 | Apache 2.0 | Apache 2.0 |
安装
Fedora/RHEL/CentOS Stream 已预装,其他平台可安装。
Fedora / RHEL / CentOS
# Pre-installed on Fedora/RHEL 8+/CentOS Stream
podman --version
# If not installed
sudo dnf install -y podman podman-compose buildah skopeoUbuntu / Debian
# Ubuntu 22.04+ / Debian 12+
sudo apt update && sudo apt install -y podman
# For older Ubuntu, add the Kubic repository
sudo mkdir -p /etc/apt/keyrings
curl -fsSL https://download.opensuse.org/repositories/\
devel:kubic:libcontainers:unstable/xUbuntu_22.04/Release.key \
| gpg --dearmor | sudo tee /etc/apt/keyrings/devel_kubic.gpg > /dev/null
sudo apt update && sudo apt install -y podmanmacOS
# Install Podman via Homebrew
brew install podman
# Initialize and start the Linux VM
podman machine init
podman machine start
# Verify installation
podman info
podman run hello-world
# Optional: Install Podman Desktop GUI
brew install --cask podman-desktopWindows
# Install via winget
winget install RedHat.Podman
# Initialize and start the machine
podman machine init
podman machine start
# Install Podman Desktop
winget install RedHat.Podman-DesktopPodman 基础
会 Docker 就会 Podman,可 alias docker=podman。
运行容器
# Run a container (identical to Docker syntax)
podman run -d --name webserver -p 8080:80 nginx:alpine
# Run interactively
podman run -it --rm ubuntu:24.04 bash
# With environment variables and volume
podman run -d --name postgres \
-e POSTGRES_PASSWORD=secret \
-e POSTGRES_DB=myapp \
-v pgdata:/var/lib/postgresql/data \
-p 5432:5432 \
postgres:16-alpine
# With resource limits
podman run -d --name app \
--memory=512m --cpus=1.5 \
--restart=always \
myapp:latest管理容器和镜像
# Container management
podman ps # list running
podman ps -a # list all
podman stop/start/restart webserver
podman logs -f webserver # follow logs
podman exec -it webserver sh # shell into container
podman inspect webserver
podman rm -f webserver
podman container prune
# Image management
podman pull docker.io/library/nginx:alpine
podman images
podman search nginx
podman tag nginx:alpine myregistry.io/nginx:v1
podman push myregistry.io/nginx:v1
podman rmi nginx:alpine
podman image prune -aRootless 容器
Rootless 是核心特性。使用用户命名空间,容器内是 root 但主机上是非特权用户。
即使逃逸也只是非特权用户,结合 SELinux/seccomp 提供纵深防御。
# Verify rootless setup
podman unshare cat /proc/self/uid_map
# Check subuid/subgid allocation
cat /etc/subuid # username:100000:65536
cat /etc/subgid # username:100000:65536
# If missing, add entries
sudo usermod --add-subuids 100000-165535 --add-subgids 100000-165535 $USER
podman system migrate
# User namespace mapping:
# Host UID 1000 -> Container UID 0 (root)
# Host UID 100000 -> Container UID 1
# Host UID 165535 -> Container UID 65536
# Verify: container sees root, host sees your UID
podman run --rm alpine id # uid=0(root)
podman top <ctr> user huser # root -> 1000Podman Compose vs Docker Compose
支持 podman-compose 或通过兼容套接字使用 docker-compose。
# Option 1: Install and use podman-compose
pip install podman-compose
podman-compose up -d
podman-compose logs -f
podman-compose down
# Option 2: Use docker-compose with Podman socket
systemctl --user enable --now podman.socket
export DOCKER_HOST=unix:///run/user/\$(id -u)/podman/podman.sock
# Now docker-compose works with Podman backend
docker-compose up -d
docker-compose ps
docker-compose down# docker-compose.yml (works with both)
version: "3.9"
services:
app:
image: node:20-alpine
ports: ["3000:3000"]
environment:
- DATABASE_URL=postgresql://user:pass@db:5432/mydb
depends_on: [db, redis]
db:
image: postgres:16-alpine
environment:
POSTGRES_USER: user
POSTGRES_PASSWORD: pass
volumes: [pgdata:/var/lib/postgresql/data]
redis:
image: redis:7-alpine
volumes:
pgdata:Pod 管理
Pod 将容器分组共享命名空间,与 Kubernetes Pod 一致。
# Create a pod with port mapping
podman pod create --name webapp -p 8080:80 -p 5432:5432
# Add containers to the pod
podman run -d --pod webapp --name webapp-nginx nginx:alpine
podman run -d --pod webapp --name webapp-db \
-e POSTGRES_PASSWORD=secret postgres:16-alpine
# Containers in a pod share localhost
# nginx reaches postgres at localhost:5432
podman run -d --pod webapp --name webapp-app \
-e DATABASE_URL=postgresql://user:pass@localhost:5432/mydb myapp:latest
# Manage pods
podman pod ls
podman pod inspect webapp
podman ps --pod --filter pod=webapp
podman pod stop webapp && podman pod rm webappKubernetes YAML
可生成和部署 Kubernetes YAML,连接本地开发与生产。
# Generate Kubernetes YAML from a pod
podman generate kube webapp > webapp.yaml
podman generate kube webapp -s > webapp-with-service.yaml
# Deploy Kubernetes YAML locally
podman play kube webapp.yaml
podman play kube --down webapp.yaml # tear down
podman play kube --replace webapp.yaml # update
# Deploy with configmap
podman play kube webapp.yaml --configmap=config.yaml
# Workflow: develop locally -> export -> test -> deploy
# 1. podman pod create / podman run --pod ...
# 2. podman generate kube webapp > webapp.yaml
# 3. podman play kube webapp.yaml (local test)
# 4. kubectl apply -f webapp.yaml (deploy to K8s cluster)构建镜像:Buildah
底层用 Buildah,支持 Containerfile 和脚本化接口。
# Containerfile (identical to Dockerfile syntax)
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
FROM node:20-alpine
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
RUN addgroup -S app && adduser -S app -G app
USER app
EXPOSE 3000
CMD ["node", "dist/index.js"]# Build commands
podman build -t myapp:latest .
podman build -t myapp:prod -f Containerfile.prod .
podman build --build-arg NODE_ENV=production -t myapp:prod .
podman build --no-cache -t myapp:latest .# Go application — multi-stage with scratch
FROM golang:1.23-alpine AS build
WORKDIR /src
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -o /app/server ./cmd/server
FROM scratch
COPY --from=build /app/server /server
COPY --from=build /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
EXPOSE 8080
ENTRYPOINT ["/server"]Podman Desktop 和 Machine
跨平台 GUI 管理容器。macOS/Windows 通过 Podman Machine 运行轻量 VM。
# Install Podman Desktop
brew install --cask podman-desktop # macOS
winget install RedHat.Podman-Desktop # Windows
flatpak install flathub io.podman_desktop.PodmanDesktop # Linux
# Features: container/pod management, image building,
# Kubernetes cluster connection, extension ecosystem
# (Kind, Minikube, OpenShift), Docker Desktop migration# Podman Machine — VM management for macOS/Windows
podman machine init --cpus 4 --memory 4096 --disk-size 60
podman machine start
podman machine ls
podman machine ssh # SSH into the VM
podman machine set --rootful # enable rootful mode
podman machine stop
podman machine rm # remove and recreate if issues
podman machine init && podman machine start网络:Netavark
Podman 4+ 用 Netavark + Aardvark-dns,自动 DNS 解析。
# Create custom network
podman network create mynet
podman network create --subnet 10.89.0.0/24 --gateway 10.89.0.1 mynet
# Run containers on custom network
podman run -d --name db --network mynet postgres:16-alpine
podman run -d --name app --network mynet myapp:latest
# Aardvark-dns provides automatic DNS resolution by container name
# Inside "app" container:
podman exec app ping db
# PING db (10.89.0.2): 56 data bytes
# 64 bytes from 10.89.0.2: seq=0 ttl=64 time=0.089 ms
# Port mapping for external access
podman run -d --name web --network mynet -p 8080:80 nginx:alpine
# Network management
podman network ls
podman network inspect mynet
podman network connect mynet existing-container
podman network disconnect mynet existing-container
podman network rm mynet卷管理
支持命名卷、绑定挂载和 tmpfs。
# Create and use named volume
podman volume create mydata
podman run -d --name db \
-v mydata:/var/lib/postgresql/data \
postgres:16-alpine
# Bind mount (host directory) with SELinux labels
podman run -d --name web \
-v ./html:/usr/share/nginx/html:Z \
nginx:alpine
# :Z = SELinux private label (single container access)
# :z = SELinux shared label (multiple containers)
# :ro = read-only mount
# tmpfs mount (in-memory, no persistence)
podman run -d --tmpfs /tmp:size=100m myapp:latest
# Volume management
podman volume ls
podman volume inspect mydata
podman volume rm mydata
podman volume prune # remove all unused volumes注册表管理
通过 registries.conf 支持多注册表优先级搜索。
# /etc/containers/registries.conf
# Podman searches these registries in order for unqualified images
[registries.search]
registries = ["docker.io", "quay.io", "ghcr.io"]
# Login to multiple registries
podman login docker.io
podman login quay.io
podman login ghcr.io
# Credentials stored in: \${XDG_RUNTIME_DIR}/containers/auth.json
# Pull from specific registry
podman pull docker.io/library/nginx:alpine
podman pull quay.io/podman/stable
podman pull ghcr.io/owner/image:tag
# Use skopeo for advanced registry operations
skopeo inspect docker://docker.io/library/nginx:alpine
skopeo copy docker://src-registry/img docker://dst-registry/imgQuadlet
.container 文件放入 systemd 目录即可管理容器生命周期。
# ~/.config/containers/systemd/webapp.container
[Unit]
Description=Web Application
After=network-online.target
[Container]
Image=docker.io/library/nginx:alpine
PublishPort=8080:80
Volume=./html:/usr/share/nginx/html:Z
AutoUpdate=registry
HealthCmd=curl -f http://localhost/ || exit 1
HealthInterval=30s
[Service]
Restart=always
[Install]
WantedBy=default.target# Enable and manage
systemctl --user daemon-reload
systemctl --user enable --now webapp.service
journalctl --user -u webapp.service -f
# Auto-update (checks registry for new digests)
systemctl --user enable --now podman-auto-update.timer
podman auto-update --dry-run
podman auto-update密钥管理
安全传递敏感数据,不包含在镜像或环境变量中。
# Create a secret from stdin
echo "my-database-password" | podman secret create db-password -
# Create from file
podman secret create tls-cert ./server.crt
podman secret create tls-key ./server.key
# List secrets
podman secret ls
# Use as file (mounted at /run/secrets/)
podman run -d --name db \
--secret db-password \
-e POSTGRES_PASSWORD_FILE=/run/secrets/db-password \
postgres:16-alpine
# Use as environment variable
podman run -d --name app \
--secret db-password,type=env,target=DB_PASS \
myapp:latest
# Inspect and remove
podman secret inspect db-password
podman secret rm db-password多架构构建
通过 podman manifest 和 QEMU 支持跨平台构建。
# Create a manifest list for multi-arch image
podman manifest create myapp:latest
# Build for each architecture
podman build --platform linux/amd64 -t myapp:amd64 .
podman build --platform linux/arm64 -t myapp:arm64 .
# Add platform images to manifest
podman manifest add myapp:latest myapp:amd64
podman manifest add myapp:latest myapp:arm64
# Inspect and push
podman manifest inspect myapp:latest
podman manifest push myapp:latest docker://registry.io/myapp:latest
# Or build all platforms in one command
podman build --platform linux/amd64,linux/arm64 \
--manifest myapp:latest .CI/CD
无守护进程架构适合共享 CI 运行器。
GitHub Actions
# .github/workflows/build.yml
name: Build with Podman
on: { push: { branches: [main] } }
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: podman build -t myapp:latest .
- run: podman run --rm myapp:latest npm test
- run: |
echo \${{ secrets.GITHUB_TOKEN }} | \
podman login ghcr.io -u \${{ github.actor }} --password-stdin
podman tag myapp:latest ghcr.io/\${{ github.repository }}:latest
podman push ghcr.io/\${{ github.repository }}:latestGitLab CI
# .gitlab-ci.yml
build:
image: quay.io/podman/stable
script:
- podman build -t \$CI_REGISTRY_IMAGE:\$CI_COMMIT_SHA .
- podman login -u \$CI_REGISTRY_USER -p \$CI_REGISTRY_PASSWORD \$CI_REGISTRY
- podman push \$CI_REGISTRY_IMAGE:\$CI_COMMIT_SHA从 Docker 迁移
大多数工作流迁移简单,CLI 兼容。
- 安装并别名 docker=podman
- 替换 socket 路径
- 用 podman-compose 或配置套接字
- 用 Podman Desktop
- 转 Quadlet
- 更新 CI/CD
- 测试 Compose 兼容性
# Step 1: Install Podman and compatibility layer
sudo dnf install podman podman-docker # provides /usr/bin/docker
# Step 2: Create Docker alias
echo "alias docker=podman" >> ~/.bashrc
source ~/.bashrc
# Step 3: Enable Podman socket for Docker Compose
systemctl --user enable --now podman.socket
export DOCKER_HOST=unix:///run/user/\$(id -u)/podman/podman.sock
# Step 4: Test with existing Docker workflows
docker run hello-world # uses Podman
docker-compose up -d # uses Podman backend
docker build -t myapp . # uses Buildah性能对比
性能相当,无守护进程略快,Rootless 约 2-5% 开销。
- 启动略快
- 拉取相同
- 运行时相同
- 内存更少
- Rootless ~2-5%
- 构建相当
安全最佳实践
强安全默认值,额外加固确保纵深防御。
- 始终 Rootless
- SELinux :Z/:z
- seccomp 限制
- cap-drop=all
- 只读根文件系统
- cosign 签名
- Trivy 扫描
- no-new-privileges
# Security-hardened container
podman run -d --name secure-app \
--cap-drop=all --cap-add=NET_BIND_SERVICE \
--read-only --tmpfs /tmp:size=50m \
--security-opt=no-new-privileges \
--security-opt label=type:container_t \
--user 1000:1000 --memory=256m --cpus=0.5 \
-v ./data:/app/data:Z,ro myapp:latest
# Verify image and scan
cosign verify --key cosign.pub myregistry.io/myapp:latest
podman run --rm aquasec/trivy image myapp:latest生产部署
Quadlet + 自动更新 + 健康检查,无需编排器。
# /etc/containers/systemd/myapp.container
[Unit]
Description=Production App
After=network-online.target myapp-db.service
Requires=myapp-db.service
[Container]
Image=ghcr.io/myorg/myapp:latest
PublishPort=443:8443
Network=myapp.network
Secret=db-password,type=env,target=DATABASE_PASSWORD
Secret=tls-cert,target=/etc/ssl/server.crt
Volume=app-data:/app/data:Z
Environment=NODE_ENV=production
AutoUpdate=registry
HealthCmd=curl -fk https://localhost:8443/health || exit 1
HealthInterval=15s
HealthRetries=5
[Service]
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target# /etc/containers/systemd/myapp-db.container
[Unit]
Description=Production Database
After=network-online.target
[Container]
Image=docker.io/library/postgres:16-alpine
Network=myapp.network
Secret=db-password,type=env,target=POSTGRES_PASSWORD
Volume=pgdata:/var/lib/postgresql/data:Z
Environment=POSTGRES_DB=myapp
HealthCmd=pg_isready -U postgres
HealthInterval=10s
[Service]
Restart=always
[Install]
WantedBy=multi-user.target# /etc/containers/systemd/myapp.network
[Network]
Subnet=10.89.1.0/24
Gateway=10.89.1.1
# Deploy the full production stack
sudo systemctl daemon-reload
sudo systemctl enable --now myapp-db.service
sudo systemctl enable --now myapp.service
sudo systemctl enable --now podman-auto-update.timer
# Monitor
systemctl status myapp.service
journalctl -u myapp.service -f故障排查
- 权限拒绝:检查 subuid/subgid
- 网络不通:安装 pasta
- 低端口:设 sysctl
- 拉取失败:检查 registries.conf
- 不启动:查 podman logs
- SELinux:加 :Z
- Machine 故障:重建 VM
- Compose:用 1.1+
# Debugging commands
podman info # system info
podman system check # storage consistency
podman events # real-time events
podman logs -f <container> # container logs
podman healthcheck run <ctr> # manual health check
podman system df # disk usage
podman system prune -a # clean everything
podman system reset # nuclear reset
podman info --format "{{.Host.NetworkBackend}}"常见问题
能替代 Docker 吗?
绝大多数场景可以,CLI 兼容,Compose 兼容,主要缺少 Swarm。
比 Docker 安全吗?
是,无 root 守护进程、默认 Rootless、SELinux 集成。
Rootless 原理?
用户命名空间映射容器 root 到主机非特权用户。
Pod vs K8s Pod?
直接对应,共享命名空间,可 generate kube 导出。
podman-compose 还是 docker-compose?
简单栈用前者,复杂文件用后者通过套接字。
Quadlet 是什么?
systemd 原生集成,.container 文件替代 docker-compose 用于生产。
能运行 Docker 镜像吗?
能,任何 OCI/Docker 格式镜像。
macOS Machine 原理?
创建 Fedora CoreOS VM,CLI 透明通信,virtiofs 共享文件。