Skip to content

Getting Started with Podman

Podman is a container engine developed primarily by Red Hat. The key differences from Docker are:

FeaturePodmanDocker
DaemonDaemonlessRequires dockerd daemon
Root privilegesNative rootless container supportRequires extra configuration
Command compatibilityCompatible with Docker CLI-
Pod supportNative Pod support (similar to Kubernetes)Not supported
System integrationUses systemd for container lifecycle managementOwn daemon management
Default availabilityIncluded in RHEL/CentOS/AlmaLinux default repositoriesRequires third-party repository
Terminal window
sudo dnf install -y podman

Verify the installation:

Terminal window
podman --version
podman info
Terminal window
# Pull an image from Docker Hub
podman pull docker.io/library/nginx:latest
# Pull an image from Quay.io
podman pull quay.io/centos/centos:stream9
# List local images
podman images
Terminal window
# Run in the foreground, automatically remove on exit
podman run --rm -it centos:stream9 /bin/bash
# Run Nginx in the background, map port 8080 to container port 80
podman run -d --name my-nginx -p 8080:80 docker.io/library/nginx:latest
# Mount a local directory to the container
podman run -d --name my-web \
-p 8080:80 \
-v /srv/www:/usr/share/nginx/html:Z \
docker.io/library/nginx:latest
Terminal window
# View running containers
podman ps
# View all containers (including stopped ones)
podman ps -a
# View container details
podman inspect my-nginx
# View container logs
podman logs my-nginx
# Follow logs in real time
podman logs -f my-nginx
Terminal window
# Stop a container
podman stop my-nginx
# Start a stopped container
podman start my-nginx
# Restart a container
podman restart my-nginx
# Remove a stopped container
podman rm my-nginx
# Force remove a running container
podman rm -f my-nginx
# Remove all stopped containers
podman container prune
Terminal window
# Enter a container with an interactive terminal
podman exec -it my-nginx /bin/bash
# Execute a single command inside a container
podman exec my-nginx cat /etc/nginx/nginx.conf

Create a Containerfile (equivalent to a Dockerfile):

FROM docker.io/library/almalinux:9-minimal
# Install application
RUN microdnf install -y httpd && microdnf clean all
# Copy configuration and web files
COPY index.html /var/www/html/index.html
COPY httpd.conf /etc/httpd/conf/httpd.conf
# Expose port
EXPOSE 80
# Start command
CMD ["/usr/sbin/httpd", "-D", "FOREGROUND"]
Terminal window
# Build the image, -t specifies name and tag
podman build -t my-httpd:v1 .
# View the built image
podman images
# Run a container using the custom image
podman run -d --name web -p 8080:80 my-httpd:v1
Terminal window
# Save an image to a tar file
podman save -o my-httpd-v1.tar my-httpd:v1
# Load an image from a tar file
podman load -i my-httpd-v1.tar

podman-compose is a compatible alternative to Docker Compose.

Terminal window
sudo dnf install -y python3-pip
pip3 install podman-compose

Create docker-compose.yml:

version: "3"
services:
web:
image: docker.io/library/nginx:latest
ports:
- "8080:80"
volumes:
- ./html:/usr/share/nginx/html:Z
depends_on:
- app
app:
image: docker.io/library/python:3.11-slim
working_dir: /app
volumes:
- ./app:/app:Z
command: python3 -m http.server 5000
ports:
- "5000:5000"
db:
image: docker.io/library/mariadb:10.11
environment:
MYSQL_ROOT_PASSWORD: changeme
MYSQL_DATABASE: myapp
volumes:
- db_data:/var/lib/mysql
volumes:
db_data:
Terminal window
# Start all services (in the background)
podman-compose up -d
# View service status
podman-compose ps
# View logs
podman-compose logs -f
# Stop and remove all services
podman-compose down

Rootless containers are one of Podman’s core advantages, allowing regular users to run containers without root privileges.

  1. Verify that UID mapping is configured for the user:

    Terminal window
    cat /etc/subuid
    cat /etc/subgid

    If the current user has no entry, add one manually:

    Terminal window
    sudo usermod --add-subuids 100000-165535 $(whoami)
    sudo usermod --add-subgids 100000-165535 $(whoami)
  2. Run a container as a regular user:

    Terminal window
    podman run -d --name rootless-nginx -p 8080:80 docker.io/library/nginx:latest
  3. Verify container process ownership:

    Terminal window
    ps aux | grep nginx
    podman top rootless-nginx

Podman can generate systemd user service units to automatically start containers when the user logs in:

Terminal window
# Generate a systemd unit file for an existing container
podman generate systemd --name rootless-nginx --files --new
# Move the generated file to the user systemd directory
mkdir -p ~/.config/systemd/user/
mv container-rootless-nginx.service ~/.config/systemd/user/
# Reload and enable the service
systemctl --user daemon-reload
systemctl --user enable --now container-rootless-nginx.service
# Allow user services to continue running after the user logs out
loginctl enable-linger $(whoami)

Check the service status:

Terminal window
systemctl --user status container-rootless-nginx.service
Section titled “Quadlet: the recommended approach on EL 9+”

Where Quadlet files go:

  • System level (root): /etc/containers/systemd/
  • User level (rootless): ~/.config/containers/systemd/

Create a .container file describing the container:

~/.config/containers/systemd/nginx.container
[Unit]
Description=Nginx (managed by Quadlet)
After=network-online.target
[Container]
Image=docker.io/library/nginx:latest
PublishPort=8080:80
# Volume mounts get SELinux labels automatically, equivalent to :Z
Volume=%h/nginx/html:/usr/share/nginx/html:Z
[Service]
Restart=always
[Install]
# Start automatically on boot (user login)
WantedBy=default.target

Apply the configuration:

Terminal window
# Have systemd re-read the files and generate nginx.service
systemctl --user daemon-reload
systemctl --user start nginx.service
# Check status (the service name is the filename: .container -> .service)
systemctl --user status nginx.service
# Keep rootless containers running after the user logs out
loginctl enable-linger $(whoami)

To change the container config, just edit the .container file and daemon-reload — no need to regenerate the unit as with podman generate systemd. For system-level units, place the file in /etc/containers/systemd/ and use systemctl (without --user).

Pods are a unique Podman feature, similar to the Kubernetes Pod concept, where multiple containers share the same network namespace.

Terminal window
# Create a Pod with port mappings
podman pod create --name my-pod -p 8080:80 -p 3306:3306
# Run Nginx in the Pod
podman run -d --pod my-pod --name pod-nginx docker.io/library/nginx:latest
# Run MariaDB in the same Pod
podman run -d --pod my-pod --name pod-db \
-e MYSQL_ROOT_PASSWORD=changeme \
docker.io/library/mariadb:10.11
# View Pod status
podman pod ps
podman pod inspect my-pod
# Stop and remove a Pod (affects all containers in the Pod)
podman pod stop my-pod
podman pod rm my-pod
Terminal window
# Clean up unused images
podman image prune
# Clean up all unused resources (images, containers, volumes)
podman system prune -a
# View disk usage
podman system df
# View container resource usage
podman stats

EL 10 upgrades Podman from 4.x to Podman 5.x. Key changes:

FeaturePodman 4.x (EL 9)Podman 5.x (EL 10)
Rootless network backendslirp4netnspasta (default)
PerformanceBaselineBetter network performance
API compatibility-Mostly compatible with Podman 4.x

Rootless network backend change

On EL 10, rootless containers use pasta as the network backend by default (replacing slirp4netns), which generally offers better performance with no extra configuration. If needed, you can switch back:

Install slirp4netns (for legacy behavior)
sudo dnf install slirp4netns
Verify Podman version
podman --version
podman info | grep -i network