Complete Guide to Podman and Buildah: Installation, Setup, and Hands-on Labs

Introduction

Podman and Buildah represent the next generation of container management tools, offering a Docker-compatible experience without requiring a daemon. This comprehensive guide will walk you through everything from installation to advanced configurations, complete with hands-on labs to reinforce your learning.

What You’ll Learn:

  • Install and configure Podman and Buildah on various platforms
  • Understand the architecture and benefits over Docker
  • Master container management with practical examples
  • Build custom images using Buildah
  • Configure rootless containers for enhanced security
  • Implement best practices for production environments

Understanding Podman and Buildah

What is Podman?

Podman (Pod Manager) is a daemonless container engine for developing, managing, and running OCI containers. Unlike Docker, Podman runs containers directly as child processes, eliminating the need for a central daemon.

Key Features:

  • Daemonless architecture
  • Rootless container support
  • Docker CLI compatibility
  • Pod management capabilities
  • Enhanced security model

What is Buildah?

Buildah is a tool for building OCI container images. It provides fine-grained control over image creation and can build images from Dockerfiles or through scripting.

Key Features:

  • Build images without Docker daemon
  • Create images from scratch
  • Mount working containers for direct manipulation
  • Dockerfile compatibility
  • Lightweight and efficient

Installation Guide

Installing on Red Hat Enterprise Linux / CentOS / Fedora

Method 1: Using Package Manager (Recommended)

# For RHEL/CentOS 8+
sudo dnf install podman buildah

# For RHEL/CentOS 7
sudo yum install podman buildah

# For Fedora
sudo dnf install podman buildah

Method 2: Enable Container Tools Module (RHEL 8+)

# Enable the container-tools module
sudo dnf module enable container-tools

# Install Podman and Buildah
sudo dnf install podman buildah

Installing on Ubuntu/Debian

# Update package list
sudo apt update

# Install prerequisite packages
sudo apt install -y software-properties-common

# Add the 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

# Add the GPG key
curl -L "https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/xUbuntu_$(lsb_release -rs)/Release.key" | sudo apt-key add -

# Update and install
sudo apt update
sudo apt install -y podman buildah

Installing on macOS

# Install using Homebrew
brew install podman

# For Buildah on macOS, you'll need to use a Linux VM or container
# as Buildah doesn't run natively on macOS

Installing on Windows

# Install using Chocolatey
choco install podman-desktop

# Or download from GitHub releases
# https://github.com/containers/podman/releases

Initial Configuration

Basic Podman Configuration

1. Verify Installation

# Check Podman version
podman --version

# Check system information
podman system info

# Check Buildah version
buildah --version

2. Configure Registries

Create or edit the registries configuration:

sudo mkdir -p /etc/containers
sudo vim /etc/containers/registries.conf

Add the following configuration:

[registries.search]
registries = ['docker.io', 'quay.io', 'registry.fedoraproject.org']

[registries.insecure]

registries = []

[registries.block]

registries = []

3. Configure Storage

Edit the storage configuration:

sudo vim /etc/containers/storage.conf

Example configuration:

[storage]
driver = "overlay"
runroot = "/run/containers/storage"
graphroot = "/var/lib/containers/storage"

[storage.options]

additionalimagestores = []

[storage.options.overlay]

mountopt = “nodev,metacopy=on”

Rootless Configuration

1. Enable User Namespaces

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

# If the value is 0, enable user namespaces
echo 'user.max_user_namespaces=28633' | sudo tee -a /etc/sysctl.d/userns.conf
sudo sysctl -p /etc/sysctl.d/userns.conf

2. Configure Subuid and Subgid

# Add subuid and subgid ranges for your user
sudo usermod --add-subuids 10000-75535 --add-subgids 10000-75535 $(whoami)

# Verify the configuration
grep $(whoami) /etc/subuid /etc/subgid

3. Configure Rootless Networking

# Install slirp4netns for rootless networking
sudo dnf install slirp4netns  # RHEL/Fedora
sudo apt install slirp4netns  # Ubuntu/Debian

Lab 1: Your First Podman Container

Objective

Learn basic Podman commands by running your first container.

Steps

1. Run a Simple Container

# Pull and run a container
podman run hello-world

# Run an interactive container
podman run -it alpine sh

2. List Containers

# List running containers
podman ps

# List all containers (including stopped)
podman ps -a

3. Container Lifecycle Management

# Run a container in the background
podman run -d --name web-server nginx

# Check container status
podman ps

# View container logs
podman logs web-server

# Stop the container
podman stop web-server

# Remove the container
podman rm web-server

4. Port Mapping

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

# Test the connection
curl http://localhost:8080

# Clean up
podman stop nginx-server
podman rm nginx-server

Expected Output

You should see the nginx welcome page when accessing http://localhost:8080.

Lab 2: Building Images with Buildah

Objective

Learn to build custom container images using Buildah.

Steps

1. Create a Simple Web Application

# Create a project directory
mkdir ~/webapp-demo
cd ~/webapp-demo

# Create a simple HTML file
cat > index.html << 'EOF'
<!DOCTYPE html>
<html>
<head>
    <title>My Web App</title>
</head>
<body>
    <h1>Hello from Buildah!</h1>
    <p>This container was built using Buildah.</p>
</body>
</html>
EOF

2. Build Image Using Buildah Script

# Create a build script
cat > build-image.sh << 'EOF'
#!/bin/bash

# Create a new container from base image
container=$(buildah from alpine:latest)

# Install nginx
buildah run $container -- apk add --no-cache nginx

# Copy our HTML file
buildah copy $container index.html /var/www/localhost/htdocs/

# Create nginx configuration
buildah run $container -- mkdir -p /run/nginx

# Set up nginx to run in foreground
buildah run $container -- sh -c 'echo "daemon off;" >> /etc/nginx/nginx.conf'

# Expose port 80
buildah config --port 80 $container

# Set the working directory
buildah config --workingdir /var/www/localhost/htdocs $container

# Set the default command
buildah config --cmd "nginx" $container

# Commit the container to an image
buildah commit $container webapp-demo:latest

# Clean up
buildah rm $container

echo "Image built successfully!"
EOF

# Make the script executable
chmod +x build-image.sh

# Run the build script
./build-image.sh

3. Test the Built Image

# List images
podman images

# Run the custom image
podman run -d -p 8080:80 --name my-webapp webapp-demo:latest

# Test the application
curl http://localhost:8080

# Clean up
podman stop my-webapp
podman rm my-webapp

Expected Output

You should see your custom HTML page with “Hello from Buildah!” when accessing the container.

Lab 3: Advanced Podman Features

Objective

Explore advanced Podman features including pods, volumes, and networking.

Steps

1. Working with Pods

# Create a pod
podman pod create --name webapp-pod -p 8080:80

# List pods
podman pod list

# Add containers to the pod
podman run -d --pod webapp-pod --name frontend nginx
podman run -d --pod webapp-pod --name backend alpine sleep 3600

# List containers in the pod
podman ps --pod

# Get pod information
podman pod inspect webapp-pod

2. Volume Management

# Create a named volume
podman volume create webapp-data

# List volumes
podman volume list

# Run a container with the volume
podman run -d -v webapp-data:/data --name data-container alpine sleep 3600

# Create some data in the volume
podman exec data-container sh -c 'echo "Hello Volume!" > /data/message.txt'

# Verify data persistence
podman exec data-container cat /data/message.txt

# Clean up container but keep volume
podman rm -f data-container

# Create new container with same volume
podman run -d -v webapp-data:/data --name new-data-container alpine sleep 3600

# Verify data is still there
podman exec new-data-container cat /data/message.txt

3. Custom Networks

# Create a custom network
podman network create webapp-network

# List networks
podman network list

# Run containers on custom network
podman run -d --network webapp-network --name web-app nginx
podman run -d --network webapp-network --name app-db postgres:13

# Test network connectivity
podman exec web-app ping -c 3 app-db

Expected Output

Containers should be able to communicate with each other using their names as hostnames.

Lab 4: Dockerfile with Buildah

Objective

Build container images using Dockerfiles with Buildah.

Steps

1. Create a Dockerfile

# Create a new project directory
mkdir ~/python-app
cd ~/python-app

# Create a simple Python application
cat > app.py << 'EOF'
from flask import Flask
import os

app = Flask(__name__)

@app.route('/')
def hello():
    return f"Hello from Python! Container ID: {os.uname().nodename}"

@app.route('/health')
def health():
    return "OK"

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000)
EOF

# Create requirements file
cat > requirements.txt << 'EOF'
Flask==2.3.3
EOF

# Create Dockerfile
cat > Dockerfile << 'EOF'
FROM python:3.9-slim

WORKDIR /app

COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

COPY app.py .

EXPOSE 5000

CMD ["python", "app.py"]
EOF

2. Build with Buildah

# Build the image using Buildah
buildah bud -t python-webapp:latest .

# Alternative: Build with Podman
podman build -t python-webapp:latest .

# List images
podman images | grep python-webapp

3. Test the Application

# Run the container
podman run -d -p 5000:5000 --name python-app python-webapp:latest

# Test the application
curl http://localhost:5000
curl http://localhost:5000/health

# View logs
podman logs python-app

# Clean up
podman stop python-app
podman rm python-app

Expected Output

The application should respond with “Hello from Python!” and the health endpoint should return “OK”.

Lab 5: Multi-stage Builds

Objective

Learn to create efficient images using multi-stage builds.

Steps

1. Create a Go Application

# Create project directory
mkdir ~/go-app
cd ~/go-app

# Create main.go
cat > main.go << 'EOF'
package main

import (
    "fmt"
    "net/http"
    "log"
)

func handler(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "Hello from Go! Path: %s\n", r.URL.Path)
}

func main() {
    http.HandleFunc("/", handler)
    fmt.Println("Server starting on :8080")
    log.Fatal(http.ListenAndServe(":8080", nil))
}
EOF

# Create go.mod
cat > go.mod << 'EOF'
module webapp

go 1.21
EOF

2. Create Multi-stage Dockerfile

cat > Dockerfile << 'EOF'
# Build stage
FROM golang:1.21-alpine AS builder

WORKDIR /app

# Copy go mod files
COPY go.mod go.sum* ./

# Download dependencies
RUN go mod download

# Copy source code
COPY . .

# Build the application
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o main .

# Runtime stage
FROM alpine:latest

# Install ca-certificates for HTTPS
RUN apk --no-cache add ca-certificates

WORKDIR /root/

# Copy the binary from builder stage
COPY --from=builder /app/main .

# Expose port
EXPOSE 8080

# Run the application
CMD ["./main"]
EOF

3. Build and Test

# Build the multi-stage image
buildah bud -t go-webapp:latest .

# Check image size
podman images | grep go-webapp

# Run the container
podman run -d -p 8080:8080 --name go-app go-webapp:latest

# Test the application
curl http://localhost:8080
curl http://localhost:8080/test

# Clean up
podman stop go-app
podman rm go-app

Expected Output

The final image should be much smaller than a full Go development image, containing only the compiled binary and minimal runtime dependencies.

Security Best Practices

1. Rootless Containers

Always prefer rootless containers when possible:

# Run as non-root user
podman run --user 1000:1000 alpine id

# Create and use a custom user
podman run --user $(id -u):$(id -g) alpine id

2. Read-only Filesystems

# Run container with read-only filesystem
podman run --read-only -d nginx

# With temporary filesystem for writable areas
podman run --read-only --tmpfs /tmp --tmpfs /var/run -d nginx

3. Resource Limits

# Set memory and CPU limits
podman run --memory=512m --cpus=1.0 -d nginx

# Set process limits
podman run --pids-limit=100 -d nginx

4. Security Scanning

# Scan images for vulnerabilities (requires additional tools)
# Example with Trivy
trivy image nginx:latest

Troubleshooting Common Issues

Issue 1: Permission Denied

Problem: Getting permission denied errors when running containers.

Solution:

# Check if user is in necessary groups
groups $USER

# Add user to necessary groups
sudo usermod -aG containers $USER

# Restart session or run
newgrp containers

Issue 2: Network Connectivity

Problem: Containers cannot reach external networks.

Solution:

# Check network configuration
podman network list

# Reset network configuration
podman system reset --force

# Recreate default network
podman network create default

Issue 3: Storage Issues

Problem: Running out of storage space.

Solution:

# Clean up unused containers and images
podman system prune -a

# Remove unused volumes
podman volume prune

# Check storage usage
podman system df

Production Deployment Considerations

1. Systemd Integration

Create systemd service files for production deployments:

# Generate systemd service file
podman generate systemd --name webapp --files

# Enable and start service
sudo systemctl enable container-webapp.service
sudo systemctl start container-webapp.service

2. Health Checks

# Run container with health check
podman run -d --health-cmd "curl -f http://localhost:8080/health" \
  --health-interval=30s --health-timeout=10s --health-retries=3 \
  --name webapp nginx

3. Logging Configuration

# Configure logging driver
podman run -d --log-driver=journald --log-opt tag=webapp nginx

# View logs
journalctl -u container-webapp.service

Advanced Configuration

1. Custom Registries

# Configure private registry
podman login registry.example.com

# Push to private registry
podman tag webapp:latest registry.example.com/webapp:latest
podman push registry.example.com/webapp:latest

2. Secrets Management

# Create a secret
echo "mysecretpassword" | podman secret create db-password -

# Use secret in container
podman run -d --secret db-password postgres:13

3. Configuration Files

Create comprehensive configuration files for complex deployments:

# docker-compose.yml equivalent using podman-compose
version: '3.8'
services:
  web:
    image: nginx:latest
    ports:
      - "80:80"
    volumes:
      - web-data:/var/www/html
    depends_on:
      - db
  
  db:
    image: postgres:13
    environment:
      POSTGRES_PASSWORD: secretpassword
    volumes:
      - db-data:/var/lib/postgresql/data

volumes:
  web-data:
  db-data:

Monitoring and Maintenance

1. Container Monitoring

# Monitor container resources
podman stats

# Get detailed container information
podman inspect webapp

# Monitor logs in real-time
podman logs -f webapp

2. Regular Maintenance

# Update images
podman pull nginx:latest

# Regular cleanup
podman system prune -a --volumes

# Check system health
podman system info

Conclusion

Podman and Buildah provide powerful, secure alternatives to Docker with enhanced security features and better integration with Linux systems. This guide has covered:

  • Complete installation and configuration procedures
  • Hands-on labs demonstrating core functionality
  • Advanced features like pods, volumes, and networking
  • Security best practices and troubleshooting
  • Production deployment considerations

The daemonless architecture, rootless containers, and enhanced security model make Podman and Buildah excellent choices for modern container deployments. Continue practicing with these tools to master container management in your environment.

Next Steps

  1. Explore Kubernetes integration with Podman
  2. Learn about container orchestration with Podman pods
  3. Implement CI/CD pipelines using Buildah
  4. Study advanced security features and compliance
  5. Practice with real-world application deployments

Remember to always follow security best practices and keep your container tools updated for the best experience and security posture.

Share: