Podman
Quick Reference
# Run container
podman run -d --name nginx -p 8080:80 nginx
# List containers
podman ps -a
# Stop/start/remove
podman stop nginx
podman start nginx
podman rm nginx
# Images
podman images
podman pull alpine
podman rmi alpine
# Pods
podman pod create --name mypod
podman run -d --pod mypod nginx
# Rootless (as regular user)
podman run --rm alpine echo "No root needed"
# Generate systemd service
podman generate systemd --name nginx --files
Understanding Podman
Podman vs Docker
| Feature | Docker | Podman |
|---|---|---|
Architecture |
Client-server daemon |
Daemonless (fork/exec) |
Root requirement |
Requires root daemon |
Rootless by design |
systemd integration |
Separate daemon |
Native systemd units |
Pod support |
Swarm/Compose |
Native Kubernetes pods |
Command compatibility |
|
|
Socket |
|
Per-user or root socket |
Security |
Root daemon = attack surface |
No daemon = smaller surface |
Architecture
┌─────────────────────────────────────────────────────────────┐
│ User Space │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────┐ │
│ │ podman │ │ buildah │ │ skopeo │ │
│ │ (CLI/API) │ │ (build imgs)│ │ (copy images) │ │
│ └─────────────┘ └─────────────┘ └─────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ libpod │
│ (container management library) │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ conmon │
│ (container monitor process) │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ OCI Runtime (runc/crun) │
└─────────────────────────────────────────────────────────────┘
Installation
Package Installation
# Arch Linux
pacman -S podman
# Fedora/RHEL
dnf install podman
# Debian/Ubuntu
apt install podman
# Verify
podman --version
podman info
Rootless Setup
# Check subuid/subgid (required for rootless)
grep $USER /etc/subuid
grep $USER /etc/subgid
# If missing, add:
sudo usermod --add-subuids 100000-165535 --add-subgids 100000-165535 $USER
# Enable lingering (keep user services after logout)
loginctl enable-linger $USER
# Verify rootless works
podman run --rm alpine echo "Rootless works!"
Container Operations
Run Containers
# Basic run
podman run alpine echo "Hello"
# Interactive
podman run -it alpine sh
# Detached with name
podman run -d --name mycontainer nginx
# Port mapping
podman run -d -p 8080:80 nginx
podman run -d -p 8080:80/tcp -p 8443:443/tcp nginx
# Environment variables
podman run -d -e MYSQL_ROOT_PASSWORD=secret mysql
# Volume mounts
podman run -d -v /host/path:/container/path nginx
podman run -d -v myvolume:/data nginx
# Resource limits
podman run -d --memory=512m --cpus=1 nginx
# Auto-remove on exit
podman run --rm alpine echo "Temporary"
# Run as specific user
podman run --user 1000:1000 alpine id
# Read-only filesystem
podman run --read-only alpine sh
List Containers
# Running containers
podman ps
# All containers (including stopped)
podman ps -a
# Just IDs
podman ps -q
# With size
podman ps -s
# Filter
podman ps --filter "status=running"
podman ps --filter "name=nginx"
# Format output
podman ps --format "{{.ID}} {{.Names}} {{.Status}}"
Container Lifecycle
# Start stopped container
podman start mycontainer
# Stop container
podman stop mycontainer
podman stop -t 30 mycontainer # 30s timeout
# Restart
podman restart mycontainer
# Pause/unpause
podman pause mycontainer
podman unpause mycontainer
# Kill (SIGKILL)
podman kill mycontainer
# Remove
podman rm mycontainer
podman rm -f mycontainer # Force (running)
podman rm -v mycontainer # Remove with volumes
# Remove all stopped
podman container prune
podman rm $(podman ps -aq)
Inspect and Logs
# Container details
podman inspect mycontainer
podman inspect -f '{{.NetworkSettings.IPAddress}}' mycontainer
# Logs
podman logs mycontainer
podman logs -f mycontainer # Follow
podman logs --tail 100 mycontainer
podman logs --since 1h mycontainer
# Stats
podman stats
podman stats mycontainer
# Top (processes)
podman top mycontainer
# Diff (filesystem changes)
podman diff mycontainer
Image Management
Pull Images
# Pull from default registry
podman pull nginx
podman pull nginx:alpine
# From specific registry
podman pull docker.io/library/nginx
podman pull quay.io/podman/hello
# All tags
podman pull --all-tags nginx
List Images
# All images
podman images
# Just IDs
podman images -q
# With digests
podman images --digests
# Filter
podman images --filter "dangling=true"
# Format
podman images --format "{{.Repository}}:{{.Tag}}"
Build Images
# Build from Dockerfile
podman build -t myimage .
# With specific Dockerfile
podman build -t myimage -f Dockerfile.prod .
# Build arguments
podman build --build-arg VERSION=1.0 -t myimage .
# No cache
podman build --no-cache -t myimage .
# Multi-stage target
podman build --target builder -t myimage .
Image Operations
# Tag image
podman tag nginx myregistry/nginx:v1
# Push to registry
podman push myregistry/nginx:v1
# Save to tar
podman save -o nginx.tar nginx
# Load from tar
podman load -i nginx.tar
# Export container filesystem
podman export mycontainer -o container.tar
# Import as image
podman import container.tar myimage
# Remove image
podman rmi nginx
podman rmi -f nginx
# Remove unused images
podman image prune
podman image prune -a # All unused
Pods
Understanding Pods
Pods group containers sharing: - Network namespace (same IP, ports) - IPC namespace - PID namespace (optional)
Pod Operations
# Create pod
podman pod create --name mypod
# Create with port mapping
podman pod create --name mypod -p 8080:80
# Run container in pod
podman run -d --pod mypod --name nginx nginx
podman run -d --pod mypod --name app myapp
# List pods
podman pod ls
podman pod ps
# Inspect pod
podman pod inspect mypod
# Pod stats
podman pod stats mypod
# Stop/start/restart pod (all containers)
podman pod stop mypod
podman pod start mypod
podman pod restart mypod
# Remove pod (and containers)
podman pod rm mypod
podman pod rm -f mypod
Networking
Network Modes
# Bridge (default) - isolated network with NAT
podman run -d --network bridge nginx
# Host - use host network directly
podman run -d --network host nginx
# None - no networking
podman run -d --network none alpine
# Container - share another container's network
podman run -d --name web nginx
podman run -d --network container:web alpine
# Slirp4netns (rootless default)
podman run -d --network slirp4netns nginx
Custom Networks
# Create network
podman network create mynet
# With subnet
podman network create --subnet 10.10.0.0/24 mynet
# List networks
podman network ls
# Inspect
podman network inspect mynet
# Run container on network
podman run -d --network mynet --name web nginx
podman run -d --network mynet --name app myapp
# Containers can reach each other by name
podman exec app ping web
# Connect running container
podman network connect mynet existing-container
# Disconnect
podman network disconnect mynet existing-container
# Remove network
podman network rm mynet
Port Mapping
# Basic mapping
podman run -d -p 8080:80 nginx
# Specific host IP
podman run -d -p 127.0.0.1:8080:80 nginx
# UDP
podman run -d -p 53:53/udp dns-server
# Random host port
podman run -d -p 80 nginx
podman port <container> # See assigned port
# Publish all exposed ports
podman run -d -P nginx
DNS and Hosts
# Custom DNS
podman run --dns 8.8.8.8 alpine cat /etc/resolv.conf
# DNS search domain
podman run --dns-search example.com alpine cat /etc/resolv.conf
# Add hosts entry
podman run --add-host myhost:192.168.1.100 alpine cat /etc/hosts
# Hostname
podman run --hostname mycontainer alpine hostname
Volumes and Storage
Volume Types
# Named volume (managed by Podman)
podman run -d -v myvolume:/data nginx
# Bind mount (host path)
podman run -d -v /host/path:/container/path nginx
# tmpfs (memory)
podman run -d --tmpfs /tmp nginx
# Read-only
podman run -d -v myvolume:/data:ro nginx
Volume Management
# Create volume
podman volume create myvolume
# List volumes
podman volume ls
# Inspect
podman volume inspect myvolume
# Remove
podman volume rm myvolume
# Prune unused
podman volume prune
Bind Mount Options
# Read-only
podman run -v /host:/container:ro nginx
# SELinux labels (RHEL/Fedora)
podman run -v /host:/container:Z nginx # Private label
podman run -v /host:/container:z nginx # Shared label
# Rootless with proper permissions
podman run -v /host:/container:Z --userns=keep-id nginx
systemd Integration
Generate systemd Units
# Generate unit file for container
podman generate systemd --name mycontainer > mycontainer.service
# With automatic creation
podman generate systemd --new --name mycontainer > mycontainer.service
# For pod
podman generate systemd --name mypod --files
# Options
podman generate systemd --name mycontainer \
--restart-policy=always \
--time 30 \
--files
Install as User Service
# Create service directory
mkdir -p ~/.config/systemd/user/
# Generate and install
podman generate systemd --name nginx --files
mv container-nginx.service ~/.config/systemd/user/
# Reload and enable
systemctl --user daemon-reload
systemctl --user enable --now container-nginx.service
# Check status
systemctl --user status container-nginx.service
# View logs
journalctl --user -u container-nginx.service
Install as Root Service
# Generate
sudo podman generate systemd --name nginx --files
# Move to system directory
sudo mv container-nginx.service /etc/systemd/system/
# Enable
sudo systemctl daemon-reload
sudo systemctl enable --now container-nginx.service
Auto-Update with systemd
# Create container with auto-update label
podman run -d --label "io.containers.autoupdate=registry" \
--name nginx nginx:latest
# Generate service
podman generate systemd --new --name nginx > ~/.config/systemd/user/nginx.service
# Enable auto-update timer
systemctl --user enable --now podman-auto-update.timer
# Check for updates manually
podman auto-update
# Dry run
podman auto-update --dry-run
Podman Compose
Registry Configuration
Configure Registries
/etc/containers/registries.conf (system) or ~/.config/containers/registries.conf (user)
[registries.search]
registries = ['docker.io', 'quay.io', 'registry.fedoraproject.org']
[registries.insecure]
registries = ['myregistry.local:5000']
[registries.block]
registries = ['docker.io/badimage']
Security
Run as Non-Root
# Run as specific user
podman run --user 1000:1000 alpine id
# Keep host UID (rootless)
podman run --userns=keep-id alpine id
# No new privileges
podman run --security-opt no-new-privileges alpine
Capabilities
# Drop all capabilities
podman run --cap-drop=all alpine
# Add specific capability
podman run --cap-add=NET_ADMIN alpine
# Check capabilities
podman run --rm alpine cat /proc/1/status | grep Cap
SELinux
# Run with SELinux disabled (not recommended)
podman run --security-opt label=disable alpine
# Custom SELinux type
podman run --security-opt label=type:container_runtime_t alpine
# Volume labels
podman run -v /host:/container:Z alpine # Private
podman run -v /host:/container:z alpine # Shared
Troubleshooting
Common Issues
Permission Denied (Rootless)
# Check subuid/subgid
grep $USER /etc/subuid /etc/subgid
# Reset storage
podman system reset
# Check user namespace
podman unshare cat /proc/self/uid_map
Port Binding Failed
# Rootless cannot bind < 1024 by default
# Option 1: Use higher port
podman run -p 8080:80 nginx
# Option 2: Allow low ports (sysctl)
sudo sysctl net.ipv4.ip_unprivileged_port_start=80
Quick Command Reference
# Containers
podman run -d --name web -p 8080:80 nginx
podman ps -a
podman stop/start/restart web
podman rm web
podman exec -it web sh
podman logs -f web
# Images
podman images
podman pull nginx
podman build -t myimage .
podman rmi nginx
# Pods
podman pod create --name mypod -p 8080:80
podman run -d --pod mypod nginx
podman pod ls/stop/start/rm mypod
# Volumes
podman volume create mydata
podman run -v mydata:/data nginx
podman volume ls/rm mydata
# Networks
podman network create mynet
podman run --network mynet nginx
podman network ls/rm mynet
# systemd
podman generate systemd --name web --files
systemctl --user enable container-web.service
# Cleanup
podman system prune -a
podman volume prune
podman system reset