Getting Started with Podman
Podman vs Docker
Section titled “Podman vs Docker”Podman is a container engine developed primarily by Red Hat. The key differences from Docker are:
| Feature | Podman | Docker |
|---|---|---|
| Daemon | Daemonless | Requires dockerd daemon |
| Root privileges | Native rootless container support | Requires extra configuration |
| Command compatibility | Compatible with Docker CLI | - |
| Pod support | Native Pod support (similar to Kubernetes) | Not supported |
| System integration | Uses systemd for container lifecycle management | Own daemon management |
| Default availability | Included in RHEL/CentOS/AlmaLinux default repositories | Requires third-party repository |
Install Podman
Section titled “Install Podman”sudo dnf install -y podmansudo dnf module install -y container-toolssudo yum install -y podmanVerify the installation:
podman --versionpodman infoPulling and Running Containers
Section titled “Pulling and Running Containers”Pull Images
Section titled “Pull Images”# Pull an image from Docker Hubpodman pull docker.io/library/nginx:latest
# Pull an image from Quay.iopodman pull quay.io/centos/centos:stream9
# List local imagespodman imagesRun Containers
Section titled “Run Containers”# Run in the foreground, automatically remove on exitpodman run --rm -it centos:stream9 /bin/bash
# Run Nginx in the background, map port 8080 to container port 80podman run -d --name my-nginx -p 8080:80 docker.io/library/nginx:latest
# Mount a local directory to the containerpodman run -d --name my-web \ -p 8080:80 \ -v /srv/www:/usr/share/nginx/html:Z \ docker.io/library/nginx:latestManaging Containers
Section titled “Managing Containers”Check Container Status
Section titled “Check Container Status”# View running containerspodman ps
# View all containers (including stopped ones)podman ps -a
# View container detailspodman inspect my-nginx
# View container logspodman logs my-nginx
# Follow logs in real timepodman logs -f my-nginxStop and Remove Containers
Section titled “Stop and Remove Containers”# Stop a containerpodman stop my-nginx
# Start a stopped containerpodman start my-nginx
# Restart a containerpodman restart my-nginx
# Remove a stopped containerpodman rm my-nginx
# Force remove a running containerpodman rm -f my-nginx
# Remove all stopped containerspodman container pruneEnter a Running Container
Section titled “Enter a Running Container”# Enter a container with an interactive terminalpodman exec -it my-nginx /bin/bash
# Execute a single command inside a containerpodman exec my-nginx cat /etc/nginx/nginx.confBuilding Images
Section titled “Building Images”Write a Containerfile
Section titled “Write a Containerfile”Create a Containerfile (equivalent to a Dockerfile):
FROM docker.io/library/almalinux:9-minimal
# Install applicationRUN microdnf install -y httpd && microdnf clean all
# Copy configuration and web filesCOPY index.html /var/www/html/index.htmlCOPY httpd.conf /etc/httpd/conf/httpd.conf
# Expose portEXPOSE 80
# Start commandCMD ["/usr/sbin/httpd", "-D", "FOREGROUND"]Build and Run
Section titled “Build and Run”# Build the image, -t specifies name and tagpodman build -t my-httpd:v1 .
# View the built imagepodman images
# Run a container using the custom imagepodman run -d --name web -p 8080:80 my-httpd:v1Export and Import Images
Section titled “Export and Import Images”# Save an image to a tar filepodman save -o my-httpd-v1.tar my-httpd:v1
# Load an image from a tar filepodman load -i my-httpd-v1.tarUsing podman-compose
Section titled “Using podman-compose”podman-compose is a compatible alternative to Docker Compose.
Install podman-compose
Section titled “Install podman-compose”sudo dnf install -y python3-pippip3 install podman-composeWrite a Compose File
Section titled “Write a Compose File”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:Start and Manage
Section titled “Start and Manage”# Start all services (in the background)podman-compose up -d
# View service statuspodman-compose ps
# View logspodman-compose logs -f
# Stop and remove all servicespodman-compose downRootless Containers
Section titled “Rootless Containers”Rootless containers are one of Podman’s core advantages, allowing regular users to run containers without root privileges.
Configure a Rootless Environment
Section titled “Configure a Rootless Environment”-
Verify that UID mapping is configured for the user:
Terminal window cat /etc/subuidcat /etc/subgidIf 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) -
Run a container as a regular user:
Terminal window podman run -d --name rootless-nginx -p 8080:80 docker.io/library/nginx:latest -
Verify container process ownership:
Terminal window ps aux | grep nginxpodman top rootless-nginx
Manage Rootless Containers with systemd
Section titled “Manage Rootless Containers with systemd”Podman can generate systemd user service units to automatically start containers when the user logs in:
# Generate a systemd unit file for an existing containerpodman generate systemd --name rootless-nginx --files --new
# Move the generated file to the user systemd directorymkdir -p ~/.config/systemd/user/mv container-rootless-nginx.service ~/.config/systemd/user/
# Reload and enable the servicesystemctl --user daemon-reloadsystemctl --user enable --now container-rootless-nginx.service
# Allow user services to continue running after the user logs outloginctl enable-linger $(whoami)Check the service status:
systemctl --user status container-rootless-nginx.serviceQuadlet: the recommended approach on EL 9+
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:
[Unit]Description=Nginx (managed by Quadlet)After=network-online.target
[Container]Image=docker.io/library/nginx:latestPublishPort=8080:80# Volume mounts get SELinux labels automatically, equivalent to :ZVolume=%h/nginx/html:/usr/share/nginx/html:Z
[Service]Restart=always
[Install]# Start automatically on boot (user login)WantedBy=default.targetApply the configuration:
# Have systemd re-read the files and generate nginx.servicesystemctl --user daemon-reloadsystemctl --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 outloginctl 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).
Podman Pod Management
Section titled “Podman Pod Management”Pods are a unique Podman feature, similar to the Kubernetes Pod concept, where multiple containers share the same network namespace.
# Create a Pod with port mappingspodman pod create --name my-pod -p 8080:80 -p 3306:3306
# Run Nginx in the Podpodman run -d --pod my-pod --name pod-nginx docker.io/library/nginx:latest
# Run MariaDB in the same Podpodman run -d --pod my-pod --name pod-db \ -e MYSQL_ROOT_PASSWORD=changeme \ docker.io/library/mariadb:10.11
# View Pod statuspodman pod pspodman pod inspect my-pod
# Stop and remove a Pod (affects all containers in the Pod)podman pod stop my-podpodman pod rm my-podCommon Maintenance Commands
Section titled “Common Maintenance Commands”# Clean up unused imagespodman image prune
# Clean up all unused resources (images, containers, volumes)podman system prune -a
# View disk usagepodman system df
# View container resource usagepodman statsEL 10 Notes: Podman 5
Section titled “EL 10 Notes: Podman 5”EL 10 upgrades Podman from 4.x to Podman 5.x. Key changes:
| Feature | Podman 4.x (EL 9) | Podman 5.x (EL 10) |
|---|---|---|
| Rootless network backend | slirp4netns | pasta (default) |
| Performance | Baseline | Better 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:
sudo dnf install slirp4netnspodman --versionpodman info | grep -i network