Skip to main content

Podman - Daemonless Container Engine

Overview

Podman (Pod Manager) is a daemonless, open-source container engine designed to develop, manage, and run containers on Linux systems. Developed by Red Hat, Podman provides a Docker-compatible command line interface while offering unique features like rootless containers and systemd integration without requiring a central daemon.

Architecture

Daemonless Design

┌─────────────────────────────────────────────────────┐
│ Podman CLI │
├─────────────────────────────────────────────────────┤
│ libpod API │
├─────────────────────────────────────────────────────┤
│ ┌─────────────┐ ┌──────────┐ ┌───────────────┐ │
│ │ Container │ │ Image │ │ Network │ │
│ │ Runtime │ │ Store │ │ Management │ │
│ │ (crun/runc) │ │ │ │ (CNI/Netavark)│ │
│ └─────────────┘ └──────────┘ └───────────────┘ │
├─────────────────────────────────────────────────────┤
│ Storage Backend (overlay) │
├─────────────────────────────────────────────────────┤
│ Linux Kernel │
│ (namespaces, cgroups, seccomp, SELinux) │
└─────────────────────────────────────────────────────┘

Key Differences from Docker

  • No Daemon: Each Podman command runs in its own process
  • Rootless by Default: Can run containers without root privileges
  • Pod Support: Native support for Kubernetes-style pods
  • Systemd Integration: Can generate systemd unit files for containers
  • Docker Compatibility: Drop-in replacement for most Docker commands

Installation and Configuration

Installing Podman

Fedora/RHEL/CentOS

# RHEL 8/CentOS 8/Fedora
sudo dnf install podman

# RHEL 7/CentOS 7
sudo yum install podman

Ubuntu/Debian

# Ubuntu 20.04 and later
sudo apt update
sudo apt install podman

# For newer versions from Kubic repository
echo "deb https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/xUbuntu_$(lsb_release -rs)/ /" | sudo tee /etc/apt/sources.list.d/devel:kubic:libcontainers:stable.list
curl -L "https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/xUbuntu_$(lsb_release -rs)/Release.key" | sudo apt-key add -
sudo apt update
sudo apt install podman

macOS

# Using Homebrew
brew install podman

# Initialize and start Podman machine
podman machine init
podman machine start

Configuration Files

System Configuration

# /etc/containers/registries.conf
unqualified-search-registries = ["docker.io", "quay.io"]

[[registry]]
location = "docker.io"
insecure = false
blocked = false

[[registry.mirror]]
location = "mirror.gcr.io"

# /etc/containers/storage.conf
[storage]
driver = "overlay"
runroot = "/run/containers/storage"
graphroot = "/var/lib/containers/storage"

[storage.options]
size = "10G"
override_kernel_check = "true"

User Configuration (Rootless)

# ~/.config/containers/containers.conf
[containers]
userns = "auto"
cgroups = "enabled"
cgroupns = "private"
default_sysctls = [
"net.ipv4.ping_group_range=0 0",
]

[network]
default_subnet = "10.88.0.0/16"

[engine]
runtime = "crun"
stop_timeout = 10

Rootless Containers

Setting Up Rootless Podman

1. Enable User Namespaces

# Check if user namespaces are enabled
sysctl user.max_user_namespaces

# Enable if needed
echo "user.max_user_namespaces=28633" | sudo tee /etc/sysctl.d/99-rootless.conf
sudo sysctl -p /etc/sysctl.d/99-rootless.conf

2. Configure subuid and subgid

# Check current mappings
grep $USER /etc/subuid /etc/subgid

# Add if missing
sudo usermod --add-subuids 100000-165535 --add-subgids 100000-165535 $USER

# Verify
podman unshare cat /proc/self/uid_map

3. Configure Storage

# Reset storage for rootless
podman system reset

# Configure storage location
mkdir -p ~/.config/containers
cat > ~/.config/containers/storage.conf <<EOF
[storage]
driver = "overlay"
runroot = "/run/user/$(id -u)/containers"
graphroot = "$HOME/.local/share/containers/storage"

[storage.options.overlay]
mount_program = "/usr/bin/fuse-overlayfs"
EOF

Rootless Networking

Using slirp4netns (default)

# Run container with port mapping
podman run -d -p 8080:80 nginx

# Check network configuration
podman inspect nginx | jq '.[0].NetworkSettings'

Using pasta (Performance Mode)

# Install pasta
sudo dnf install passt

# Configure Podman to use pasta
podman --network-backend=pasta run -d -p 8080:80 nginx

Pod Management

Creating and Managing Pods

Create a Pod

# Create a new pod
podman pod create --name mypod --publish 8080:80

# Create pod with resource limits
podman pod create --name limited-pod \
--cpus 2 \
--memory 2g \
--publish 8080:80,8443:443

Add Containers to Pod

# Add nginx to pod
podman run -d --pod mypod --name nginx nginx:latest

# Add application container
podman run -d --pod mypod --name app \
-e DATABASE_URL=localhost:5432 \
myapp:latest

Pod Operations

# List pods
podman pod ps

# Inspect pod
podman pod inspect mypod

# Stop/start pod
podman pod stop mypod
podman pod start mypod

# Remove pod and all containers
podman pod rm -f mypod

Kubernetes YAML Support

Generate Kubernetes YAML

# Create pod from Kubernetes YAML
cat <<EOF > nginx-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: nginx-pod
spec:
containers:
- name: nginx
image: nginx:latest
ports:
- containerPort: 80
- name: redis
image: redis:latest
EOF

podman play kube nginx-pod.yaml

Export to Kubernetes

# Generate Kubernetes YAML from existing pod
podman generate kube mypod > mypod.yaml

# Generate with persistent volume claims
podman generate kube -s mypod > mypod-with-storage.yaml

Integration with Kubernetes

Using Podman as CRI

Install CRI-O for Kubernetes

# CRI-O provides Kubernetes runtime using Podman libraries
sudo dnf install cri-o

# Configure CRI-O
sudo systemctl enable --now crio

Configure Kubernetes to use Podman/CRI-O

# /var/lib/kubelet/kubeadm-flags.env
KUBELET_KUBEADM_ARGS="--container-runtime=remote --container-runtime-endpoint=unix:///var/run/crio/crio.sock"

# Initialize cluster
kubeadm init --cri-socket unix:///var/run/crio/crio.sock

Building Images for Kubernetes

Multi-architecture Builds

# Build for multiple platforms
podman build --platform linux/amd64,linux/arm64 \
-t myapp:latest \
--manifest myapp:latest .

# Push manifest
podman manifest push myapp:latest docker://registry.example.com/myapp:latest

Security Features

SELinux Integration

Container SELinux Contexts

# Run with specific SELinux context
podman run -d \
--security-opt label=type:svirt_apache_t \
httpd

# Disable SELinux separation
podman run -d \
--security-opt label=disable \
nginx

# View SELinux labels
podman inspect nginx | jq '.[0].ProcessLabel'

Seccomp Profiles

Custom Seccomp Profile

{
"defaultAction": "SCMP_ACT_ERRNO",
"architectures": ["SCMP_ARCH_X86_64"],
"syscalls": [
{
"names": ["accept", "bind", "clone", "close"],
"action": "SCMP_ACT_ALLOW"
}
]
}
# Use custom seccomp profile
podman run --security-opt seccomp=./custom-seccomp.json nginx

User Namespace Remapping

# Run with specific UID/GID mapping
podman run --uidmap 0:100000:5000 \
--gidmap 0:100000:5000 \
alpine id

# Auto user namespace mapping
podman run --userns=auto alpine id

Capabilities Management

# Drop all capabilities and add specific ones
podman run --cap-drop ALL \
--cap-add NET_BIND_SERVICE \
--cap-add SETUID \
nginx

# List container capabilities
podman exec nginx capsh --print

Systemd Integration

Generate Systemd Units

Container as Service

# Create container
podman create --name myapp -p 8080:8080 myapp:latest

# Generate systemd unit
podman generate systemd --new --name myapp > ~/.config/systemd/user/myapp.service

# Enable and start service
systemctl --user enable --now myapp.service

Pod as Service

# Generate systemd units for entire pod
podman generate systemd --new --files --name mypod

# Move to systemd directory
mv *.service ~/.config/systemd/user/

# Enable pod service
systemctl --user enable --now pod-mypod.service

Systemd in Containers

# Run systemd inside container
podman run -d --systemd=always \
--name systemd-container \
-v /sys/fs/cgroup:/sys/fs/cgroup:ro \
fedora:latest /usr/lib/systemd/systemd

# Exec into systemd container
podman exec -it systemd-container /bin/bash

Performance Optimization

Storage Driver Optimization

Native Overlay (Root)

# Configure native overlay
cat > /etc/containers/storage.conf <<EOF
[storage]
driver = "overlay"
runroot = "/run/containers/storage"
graphroot = "/var/lib/containers/storage"

[storage.options.overlay]
skip_mount_home = "true"
mount_program = "" # Use kernel overlay
mountopt = "nodev,metacopy=on"
EOF

FUSE-OverlayFS (Rootless)

# Install fuse-overlayfs
sudo dnf install fuse-overlayfs

# Configure for performance
cat > ~/.config/containers/storage.conf <<EOF
[storage]
driver = "overlay"

[storage.options.overlay]
mount_program = "/usr/bin/fuse-overlayfs"
mountopt = "nodev,fsync=0,metacopy=on"
EOF

Network Performance

Use Host Network

# Maximum network performance
podman run --network host nginx

Configure MTU

# Create network with custom MTU
podman network create --opt mtu=9000 jumbo-net

# Run container on jumbo network
podman run --network jumbo-net alpine ping -c 3 google.com

Resource Limits

# CPU limits
podman run -d \
--cpus="2.5" \
--cpu-shares=512 \
--cpuset-cpus="0,1" \
nginx

# Memory limits
podman run -d \
--memory="1g" \
--memory-swap="2g" \
--memory-reservation="750m" \
nginx

# I/O limits
podman run -d \
--device-read-bps /dev/sda:10mb \
--device-write-bps /dev/sda:10mb \
nginx

Common Operations

Image Management

# Search images
podman search nginx --limit 5

# Pull with specific platform
podman pull --platform linux/arm64 nginx

# List images with formatting
podman images --format "table {{.Repository}}\t{{.Tag}}\t{{.Size}}"

# Build with advanced options
podman build \
--layers \
--cache-from registry.example.com/cache:latest \
--build-arg VERSION=1.0 \
-t myapp:latest .

# Push to registry
podman login registry.example.com
podman push myapp:latest registry.example.com/myapp:latest

Container Operations

# Run with health check
podman run -d \
--health-cmd='curl -f http://localhost/ || exit 1' \
--health-interval=30s \
--health-retries=3 \
--health-start-period=30s \
nginx

# Auto-remove on exit
podman run --rm -it alpine sh

# Run with init process
podman run -d --init nginx

# Export/Import containers
podman export nginx > nginx.tar
podman import nginx.tar mynginx:backup

Volume Management

# Create named volume
podman volume create mydata

# Mount volume with options
podman run -d \
-v mydata:/data:Z,U \
-v /host/path:/container/path:ro,rslave \
nginx

# Backup volume
podman run --rm \
-v mydata:/source:ro \
-v /backup:/backup \
alpine tar czf /backup/mydata.tar.gz -C /source .

Troubleshooting

Common Issues

1. Rootless Networking Issues

# Check slirp4netns
podman info | grep slirp4netns

# Enable port forwarding for rootless
echo "net.ipv4.ip_unprivileged_port_start=80" | sudo tee /etc/sysctl.d/99-rootless.conf
sudo sysctl -p /etc/sysctl.d/99-rootless.conf

2. Storage Space Issues

# Check storage usage
podman system df

# Clean up storage
podman system prune -a --volumes

# Reset storage completely
podman system reset

3. Permission Denied Errors

# Check user namespaces
cat /proc/sys/user/max_user_namespaces

# Verify subuid/subgid mappings
podman unshare cat /proc/self/uid_map

# Fix storage permissions
podman unshare chown -R 0:0 ~/.local/share/containers/storage

Debug Commands

# Verbose output
podman --log-level debug run alpine echo hello

# Inspect container namespace
podman inspect nginx | jq '.[0].NetworkSettings.SandboxKey'

# Check cgroup configuration
podman exec nginx cat /proc/self/cgroup

# System information
podman system info

Best Practices for Production

1. Image Security Scanning

# Install skopeo for image inspection
sudo dnf install skopeo

# Scan image before running
skopeo inspect docker://nginx:latest

# Use Clair or Trivy for vulnerability scanning
podman run --rm \
-v /var/run/docker.sock:/var/run/docker.sock \
aquasec/trivy image nginx:latest

2. Container Hardening

# podman-compose.yml with security settings
version: '3'
services:
web:
image: nginx:latest
security_opt:
- label:type:svirt_apache_t
- no-new-privileges
cap_drop:
- ALL
cap_add:
- NET_BIND_SERVICE
read_only: true
tmpfs:
- /tmp
- /var/cache/nginx

3. Monitoring and Logging

# JSON logging
podman run -d --log-driver json-file \
--log-opt max-size=10m \
--log-opt max-file=3 \
nginx

# Forward logs to syslog
podman run -d --log-driver syslog \
--log-opt syslog-address=tcp://192.168.1.100:514 \
nginx

# Container metrics
podman stats --format "table {{.Container}}\t{{.CPUPerc}}\t{{.MemUsage}}"

4. High Availability with Podman

#!/bin/bash
# Health check and restart script
CONTAINER_NAME="myapp"

if ! podman healthcheck run $CONTAINER_NAME; then
echo "Container $CONTAINER_NAME is unhealthy, restarting..."
podman restart $CONTAINER_NAME
fi

# Auto-restart with systemd
# ~/.config/systemd/user/myapp.service
[Service]
Restart=always
RestartSec=10
StartLimitInterval=400
StartLimitBurst=3

5. Backup and Disaster Recovery

#!/bin/bash
# Backup script for Podman containers and volumes

BACKUP_DIR="/backup/podman/$(date +%Y%m%d)"
mkdir -p $BACKUP_DIR

# Backup all container configurations
for container in $(podman ps -aq); do
podman inspect $container > $BACKUP_DIR/${container}_config.json
done

# Backup all volumes
for volume in $(podman volume ls -q); do
podman run --rm -v ${volume}:/source:ro \
-v $BACKUP_DIR:/backup \
alpine tar czf /backup/${volume}.tar.gz -C /source .
done

# Backup images
podman save -o $BACKUP_DIR/images.tar $(podman images -q)

Docker Compose Compatibility

Using podman-compose

# Install podman-compose
pip3 install podman-compose

# Use existing docker-compose.yml
podman-compose up -d

# View logs
podman-compose logs -f

# Scale services
podman-compose up -d --scale web=3

Native Podman Compose Support

# Using Podman 3.0+ native support
podman compose up

# Custom compose file
podman compose -f production.yml up

Advanced Features

Checkpoint and Restore

# Enable checkpoint/restore
sudo dnf install criu

# Checkpoint running container
podman container checkpoint myapp

# Restore container
podman container restore myapp

# Migration between hosts
podman container checkpoint myapp --export=/tmp/checkpoint.tar.gz
# On target host:
podman container restore --import=/tmp/checkpoint.tar.gz

Auto-Updates

# Label container for auto-updates
podman run -d \
--label io.containers.autoupdate=registry \
--name myapp \
myapp:latest

# Enable auto-update timer
systemctl --user enable --now podman-auto-update.timer

# Manual update check
podman auto-update

Resources

Official Documentation

Tools and Ecosystem

Community Resources

Learning Resources

Enterprise Resources