โˆ‰
::
+
+
+
+
go
+
kali
0b
+
+
htmx
+
+
protobuf
+
soap
pytest
&&
+
+
+
=
+
+
+
+
+
java
+
+
+
delphi
+
+
websocket
+
+
+
+
//
+
graphql
+
composer
vault
parcel
elasticsearch
pytest
+
unix
xcode
+
cypress
flask
+
+
+
+
abap
cassandra
express
+
โˆ‘
debian
+
+
gin
gradle
actix
+
zorin
+
+
+
grafana
gcp
lua
gcp
+
unix
+
symfony
+
linux
!
sklearn
+
+
Back to Blog
๐Ÿณ Container Management with Podman in AlmaLinux: Docker Alternative
AlmaLinux Containers Podman

๐Ÿณ Container Management with Podman in AlmaLinux: Docker Alternative

Published Aug 20, 2025

Learn container management using Podman in AlmaLinux. Run rootless containers, build images, manage pods, and migrate from Docker with practical beginner examples.

12 min read
0 views
Table of Contents

๐Ÿณ Container Management with Podman in AlmaLinux: Docker Alternative

Docker, Docker everywhereโ€ฆ but wait, thereโ€™s Podman! ๐Ÿš€ When I first heard about Podman, I thought โ€œOh great, another container tool to learn.โ€ But then I discovered it runs containers WITHOUT a daemon, WITHOUT root, and is 100% Docker-compatible! Mind = blown! ๐Ÿคฏ Today Iโ€™m showing you how to use Podman on AlmaLinux - itโ€™s like Docker but more secure and already installed! No more Docker daemon eating your RAM. Letโ€™s dive into the wonderful world of daemonless containers! ๐ŸŽ‰

๐Ÿค” Why Podman Over Docker?

Hereโ€™s why Podman is becoming the go-to choice:

  • ๐Ÿ”’ Rootless Containers - Run without sudo/root!
  • ๐Ÿšซ No Daemon - No background service hogging resources
  • ๐Ÿ”„ Docker Compatible - Your Docker commands just work
  • ๐Ÿ“ฆ Pod Support - Like Kubernetes pods on your laptop
  • ๐Ÿ›ก๏ธ SELinux Integration - Better security out of the box
  • ๐ŸŽฏ Systemd Integration - Containers as system services

True story: Our Docker daemon crashed and took down 50 containers. With Podman? Each container is independent. One crashes, others keep running! ๐Ÿ’ช

๐ŸŽฏ What You Need

Before we start containerizing everything, ensure you have:

  • โœ… AlmaLinux 8/9 system
  • โœ… Regular user account (no root needed!)
  • โœ… 2GB RAM minimum
  • โœ… 10GB free disk space
  • โœ… 30 minutes to master containers
  • โœ… Excitement for rootless containers! ๐ŸŽŠ

๐Ÿ“ Step 1: Installing and Setting Up Podman

Letโ€™s get Podman running!

Install Podman

# Podman is in AppStream repo - easy!
sudo dnf install -y podman

# Install additional tools
sudo dnf install -y podman-compose podman-docker buildah skopeo

# Verify installation
podman --version

# Check info
podman info

# Enable user namespaces for rootless
sudo sysctl user.max_user_namespaces=15000
echo "user.max_user_namespaces=15000" | sudo tee /etc/sysctl.d/99-rootless.conf

Configure Rootless Podman

# Setup rootless (as regular user, NOT root!)
podman system migrate

# Check subuid/subgid mappings
cat /etc/subuid
cat /etc/subgid

# Should see something like:
# yourusername:100000:65536

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

# Set registries
sudo nano /etc/containers/registries.conf
# Add/verify:
unqualified-search-registries = ["docker.io", "quay.io", "registry.fedoraproject.org"]

# Test rootless
podman run hello-world

Docker Compatibility Setup

# Install podman-docker (provides docker command)
sudo dnf install -y podman-docker

# Now docker commands work!
docker ps  # Actually runs podman ps

# Create docker-compose alias
echo "alias docker-compose='podman-compose'" >> ~/.bashrc
source ~/.bashrc

# Test compatibility
docker run -it alpine echo "Hello from Podman!"

๐Ÿ”ง Step 2: Basic Container Operations

Time to run some containers!

Running Containers

# Run a simple container
podman run -it alpine sh

# Run in background
podman run -d --name webserver nginx

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

# Run with volume mount
podman run -v /host/path:/container/path:Z alpine ls /container/path
# Note: :Z for SELinux context

# Run with environment variables
podman run -e MY_VAR=value -e DB_HOST=localhost alpine env

# Run with resource limits
podman run --memory 512m --cpus 1 nginx

# Auto-remove after exit
podman run --rm alpine echo "I'll self-destruct!"

Managing Containers

# List running containers
podman ps

# List all containers
podman ps -a

# Stop container
podman stop container_name

# Start container
podman start container_name

# Restart container
podman restart container_name

# Remove container
podman rm container_name

# Remove all stopped containers
podman container prune

# View logs
podman logs container_name
podman logs -f container_name  # Follow logs

# Execute command in running container
podman exec -it container_name bash

# Inspect container
podman inspect container_name

# View stats
podman stats

Working with Images

# Pull image
podman pull ubuntu:latest

# List images
podman images

# Search images
podman search nginx

# Remove image
podman rmi image_name

# Clean unused images
podman image prune

# Tag image
podman tag image_id myrepo/myimage:tag

# Save image to file
podman save -o image.tar nginx

# Load image from file
podman load -i image.tar

๐ŸŒŸ Step 3: Building and Managing Images

Letโ€™s create custom containers!

Building with Dockerfile

# Create Dockerfile
cat > Dockerfile << 'EOF'
FROM almalinux:9
RUN dnf install -y httpd
RUN echo "Hello from Podman!" > /var/www/html/index.html
EXPOSE 80
CMD ["/usr/sbin/httpd", "-DFOREGROUND"]
EOF

# Build image
podman build -t myapp:latest .

# Build with different file
podman build -f Containerfile -t myapp:v2 .

# Build with build args
podman build --build-arg VERSION=1.0 -t myapp:1.0 .

# Multi-stage build
cat > Dockerfile.multi << 'EOF'
# Build stage
FROM golang:alpine AS builder
WORKDIR /app
COPY . .
RUN go build -o myapp

# Runtime stage
FROM alpine:latest
RUN apk --no-cache add ca-certificates
WORKDIR /root/
COPY --from=builder /app/myapp .
CMD ["./myapp"]
EOF

podman build -f Dockerfile.multi -t myapp:slim .

Using Buildah (Advanced)

# Create container from scratch
container=$(buildah from scratch)

# Mount container filesystem
mountpoint=$(buildah mount $container)

# Install packages
dnf install --installroot $mountpoint --releasever 9 \
    --setopt=tsflags=nodocs -y coreutils bash

# Copy files
cp myapp $mountpoint/usr/local/bin/

# Configure container
buildah config --cmd "/usr/local/bin/myapp" $container
buildah config --port 8080 $container
buildah config --env APP_ENV=production $container

# Commit to image
buildah commit $container myapp:custom

# Unmount and remove working container
buildah umount $container
buildah rm $container

โœ… Step 4: Advanced Podman Features

Level up your container game!

Working with Pods

# Create a pod (like Kubernetes!)
podman pod create --name mypod -p 8080:80

# Add containers to pod
podman run -d --pod mypod --name web nginx
podman run -d --pod mypod --name app myapp:latest

# List pods
podman pod list

# View pod details
podman pod inspect mypod

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

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

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

# Play Kubernetes YAML
podman play kube mypod.yaml

Systemd Integration

# Generate systemd service for container
podman generate systemd --name mycontainer > container.service

# Install as user service
mkdir -p ~/.config/systemd/user/
podman generate systemd --name mycontainer --new \
    > ~/.config/systemd/user/container.service

# Enable and start
systemctl --user daemon-reload
systemctl --user enable container.service
systemctl --user start container.service

# Auto-start on boot (lingering)
loginctl enable-linger $USER

# Generate for root service
sudo podman generate systemd --name mycontainer --new \
    > /etc/systemd/system/container.service
sudo systemctl daemon-reload
sudo systemctl enable --now container.service

Container Networking

# Create custom network
podman network create mynet

# List networks
podman network ls

# Run container on custom network
podman run -d --network mynet --name db mariadb
podman run -d --network mynet --name web nginx

# Containers can reach each other by name!
podman exec web ping db

# Inspect network
podman network inspect mynet

# Connect running container to network
podman network connect mynet existing_container

# Disconnect from network
podman network disconnect mynet container_name

# Remove network
podman network rm mynet

๐ŸŽฎ Quick Examples

Example 1: Complete Web Stack ๐ŸŒ

#!/bin/bash
# Deploy complete LAMP stack with Podman

deploy_lamp_stack() {
    echo "๐Ÿš€ Deploying LAMP Stack with Podman"
    
    # Create pod
    podman pod create --name lamp-pod \
        -p 8080:80 \
        -p 3306:3306
    
    # Run MariaDB
    podman run -d --pod lamp-pod \
        --name lamp-db \
        -e MYSQL_ROOT_PASSWORD=secretpass \
        -e MYSQL_DATABASE=myapp \
        -e MYSQL_USER=appuser \
        -e MYSQL_PASSWORD=apppass \
        -v lamp-db-data:/var/lib/mysql:Z \
        mariadb:latest
    
    # Wait for DB to be ready
    echo "โณ Waiting for database..."
    sleep 10
    
    # Run PHP Apache
    cat > index.php << 'EOF'
<?php
$conn = new mysqli("localhost", "appuser", "apppass", "myapp");
if ($conn->connect_error) {
    die("Connection failed: " . $conn->connect_error);
}
echo "<h1>๐ŸŽ‰ Podman LAMP Stack Working!</h1>";
echo "<p>Connected to MariaDB successfully!</p>";
phpinfo();
?>
EOF
    
    # Create custom PHP image
    cat > Dockerfile.php << 'EOF'
FROM php:apache
RUN docker-php-ext-install mysqli pdo pdo_mysql
COPY index.php /var/www/html/
EOF
    
    podman build -f Dockerfile.php -t lamp-php .
    
    # Run PHP container
    podman run -d --pod lamp-pod \
        --name lamp-web \
        lamp-php
    
    echo "โœ… LAMP Stack deployed!"
    echo "๐Ÿ“ Access at: http://localhost:8080"
    echo ""
    echo "๐Ÿ”ง Management commands:"
    echo "  View logs: podman pod logs lamp-pod"
    echo "  Stop: podman pod stop lamp-pod"
    echo "  Start: podman pod start lamp-pod"
    echo "  Remove: podman pod rm -f lamp-pod"
}

deploy_lamp_stack

Example 2: CI/CD Pipeline Runner ๐Ÿ”ง

#!/bin/bash
# Run CI/CD jobs in containers

run_ci_pipeline() {
    PROJECT_NAME=$1
    REPO_URL=$2
    
    echo "๐Ÿ”ง Running CI Pipeline for $PROJECT_NAME"
    
    # Create workspace
    WORKSPACE="/tmp/ci-$PROJECT_NAME-$(date +%s)"
    mkdir -p "$WORKSPACE"
    
    # Clone repository
    git clone "$REPO_URL" "$WORKSPACE/source"
    
    # Build stage
    echo "๐Ÿ“ฆ Build Stage"
    podman run --rm \
        -v "$WORKSPACE/source:/workspace:Z" \
        -w /workspace \
        node:alpine \
        sh -c "npm install && npm run build"
    
    # Test stage
    echo "๐Ÿงช Test Stage"
    podman run --rm \
        -v "$WORKSPACE/source:/workspace:Z" \
        -w /workspace \
        node:alpine \
        sh -c "npm test"
    
    # Security scan
    echo "๐Ÿ”’ Security Scan"
    podman run --rm \
        -v "$WORKSPACE/source:/src:Z" \
        aquasec/trivy fs /src
    
    # Build Docker image
    echo "๐Ÿณ Building Container Image"
    cd "$WORKSPACE/source"
    podman build -t "$PROJECT_NAME:latest" .
    
    # Push to registry (if configured)
    if [ ! -z "$REGISTRY_URL" ]; then
        podman tag "$PROJECT_NAME:latest" "$REGISTRY_URL/$PROJECT_NAME:latest"
        podman push "$REGISTRY_URL/$PROJECT_NAME:latest"
    fi
    
    # Cleanup
    rm -rf "$WORKSPACE"
    
    echo "โœ… CI Pipeline Complete!"
}

# Usage
run_ci_pipeline "myapp" "https://github.com/user/repo.git"

Example 3: Development Environment Manager ๐Ÿ’ป

#!/bin/bash
# Manage development environments with Podman

create_dev_env() {
    ENV_NAME=$1
    LANGUAGE=$2
    
    echo "๐Ÿ’ป Creating Dev Environment: $ENV_NAME ($LANGUAGE)"
    
    case $LANGUAGE in
        python)
            IMAGE="python:3.11"
            PACKAGES="pip install flask django pytest"
            PORT="5000"
            ;;
        node)
            IMAGE="node:18"
            PACKAGES="npm install -g express nodemon jest"
            PORT="3000"
            ;;
        go)
            IMAGE="golang:1.20"
            PACKAGES="go install github.com/gin-gonic/gin@latest"
            PORT="8080"
            ;;
        *)
            echo "โŒ Unsupported language: $LANGUAGE"
            return 1
            ;;
    esac
    
    # Create persistent volume for code
    podman volume create "${ENV_NAME}-code"
    
    # Create development container
    podman run -d \
        --name "dev-$ENV_NAME" \
        -v "${ENV_NAME}-code:/workspace:Z" \
        -v "$HOME/.ssh:/root/.ssh:ro,Z" \
        -p "$PORT:$PORT" \
        -w /workspace \
        --hostname "$ENV_NAME" \
        "$IMAGE" \
        tail -f /dev/null
    
    # Install packages
    echo "๐Ÿ“ฆ Installing packages..."
    podman exec "dev-$ENV_NAME" sh -c "$PACKAGES"
    
    # Create helper script
    cat > "dev-$ENV_NAME.sh" << EOF
#!/bin/bash
# Connect to $ENV_NAME development environment

case \$1 in
    shell)
        podman exec -it "dev-$ENV_NAME" bash
        ;;
    stop)
        podman stop "dev-$ENV_NAME"
        ;;
    start)
        podman start "dev-$ENV_NAME"
        ;;
    logs)
        podman logs -f "dev-$ENV_NAME"
        ;;
    destroy)
        podman rm -f "dev-$ENV_NAME"
        podman volume rm "${ENV_NAME}-code"
        rm "dev-$ENV_NAME.sh"
        ;;
    *)
        echo "Usage: ./dev-$ENV_NAME.sh {shell|stop|start|logs|destroy}"
        ;;
esac
EOF
    
    chmod +x "dev-$ENV_NAME.sh"
    
    echo "โœ… Development environment ready!"
    echo "๐Ÿ“ Use ./dev-$ENV_NAME.sh to manage"
    echo "๐Ÿš€ Access shell: ./dev-$ENV_NAME.sh shell"
}

# Create multiple environments
create_dev_env "webapp" "python"
create_dev_env "api" "node"
create_dev_env "microservice" "go"

Example 4: Container Health Monitor ๐Ÿฅ

#!/bin/bash
# Monitor and auto-heal containers

monitor_containers() {
    LOG_FILE="/var/log/podman-monitor.log"
    
    echo "๐Ÿฅ Container Health Monitor Started - $(date)" | tee -a "$LOG_FILE"
    
    while true; do
        # Check all containers
        for container in $(podman ps -q); do
            name=$(podman inspect $container --format '{{.Name}}')
            state=$(podman inspect $container --format '{{.State.Status}}')
            health=$(podman inspect $container --format '{{.State.Health.Status}}' 2>/dev/null || echo "none")
            
            # Check if container is healthy
            if [ "$health" = "unhealthy" ]; then
                echo "โš ๏ธ Container $name is unhealthy!" | tee -a "$LOG_FILE"
                
                # Try to heal
                echo "๐Ÿ”ง Attempting to heal $name..." | tee -a "$LOG_FILE"
                podman restart $container
                
                sleep 30
                
                # Check again
                new_health=$(podman inspect $container --format '{{.State.Health.Status}}' 2>/dev/null)
                if [ "$new_health" = "healthy" ]; then
                    echo "โœ… Container $name healed!" | tee -a "$LOG_FILE"
                else
                    echo "โŒ Container $name still unhealthy, may need manual intervention" | tee -a "$LOG_FILE"
                    # Send alert
                    echo "Container $name is unhealthy on $(hostname)" | \
                        mail -s "Container Health Alert" [email protected]
                fi
            fi
            
            # Check resource usage
            stats=$(podman stats --no-stream --format json $container)
            cpu=$(echo $stats | jq -r '.[0].cpu_percent' | sed 's/%//')
            mem=$(echo $stats | jq -r '.[0].mem_percent' | sed 's/%//')
            
            if (( $(echo "$cpu > 90" | bc -l) )); then
                echo "โš ๏ธ High CPU usage for $name: ${cpu}%" | tee -a "$LOG_FILE"
            fi
            
            if (( $(echo "$mem > 90" | bc -l) )); then
                echo "โš ๏ธ High memory usage for $name: ${mem}%" | tee -a "$LOG_FILE"
            fi
        done
        
        # Check for stopped containers that should be running
        for container in $(podman ps -a --filter "status=exited" -q); do
            name=$(podman inspect $container --format '{{.Name}}')
            restart_policy=$(podman inspect $container --format '{{.HostConfig.RestartPolicy.Name}}')
            
            if [ "$restart_policy" = "always" ] || [ "$restart_policy" = "unless-stopped" ]; then
                echo "๐Ÿ”„ Restarting stopped container $name" | tee -a "$LOG_FILE"
                podman start $container
            fi
        done
        
        sleep 60
    done
}

# Run monitor
monitor_containers

๐Ÿšจ Fix Common Problems

Problem 1: Rootless Containers Not Working โŒ

Permission denied errors?

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

# If missing, add them
sudo usermod --add-subuids 100000-165535 $USER
sudo usermod --add-subgids 100000-165535 $USER

# Enable user namespaces
sudo sysctl user.max_user_namespaces=15000

# Logout and login again
exit
# Log back in

# Reset storage
podman system reset

Problem 2: Cannot Pull Images โŒ

Registry access issues?

# Check registries
podman info | grep -A5 registries

# Login to registry
podman login docker.io

# Use full image path
podman pull docker.io/library/nginx:latest

# Behind proxy?
export HTTP_PROXY=http://proxy:8080
export HTTPS_PROXY=http://proxy:8080

Problem 3: SELinux Blocking Volumes โŒ

Permission denied on mounted volumes?

# Use :Z flag for private label
podman run -v /host/path:/container/path:Z image

# Or :z for shared label
podman run -v /host/path:/container/path:z image

# Check SELinux context
ls -laZ /host/path

# Temporarily disable SELinux (not recommended)
sudo setenforce 0

Problem 4: Containers Canโ€™t Communicate โŒ

Network isolation issues?

# Create shared network
podman network create shared

# Run containers on same network
podman run -d --network shared --name app1 nginx
podman run -d --network shared --name app2 alpine

# Test connectivity
podman exec app2 ping app1

# Check firewall
sudo firewall-cmd --list-all

๐Ÿ“‹ Simple Commands Summary

TaskCommand
๐Ÿƒ Run containerpodman run image
๐Ÿ“‹ List containerspodman ps
๐Ÿ›‘ Stop containerpodman stop name
๐Ÿ—‘๏ธ Remove containerpodman rm name
๐Ÿ–ผ๏ธ List imagespodman images
๐Ÿ”จ Build imagepodman build -t tag .
๐ŸŒ Create networkpodman network create name
๐Ÿ“ฆ Create podpodman pod create name
๐Ÿ“Š View statspodman stats

๐Ÿ’ก Tips for Success

  1. Go Rootless ๐Ÿ”’ - Safer than Dockerโ€™s root requirement
  2. Use Pods ๐ŸŽฏ - Group related containers
  3. Systemd Integration ๐Ÿค– - Auto-start containers at boot
  4. Alias Docker ๐Ÿ”„ - Smooth transition from Docker
  5. Volume Labels ๐Ÿท๏ธ - Always use :Z for SELinux
  6. Regular Cleanup ๐Ÿงน - Prune unused images/containers

Pro tip: I replaced our entire Docker setup with Podman in production. Zero downtime, better security, and our devs didnโ€™t even notice - their docker commands just worked! ๐Ÿ˜Ž

๐Ÿ† What You Learned

Youโ€™re now a container ninja! You can:

  • โœ… Install and configure Podman
  • โœ… Run rootless containers safely
  • โœ… Build custom container images
  • โœ… Manage pods like Kubernetes
  • โœ… Integrate with systemd
  • โœ… Create container networks
  • โœ… Migrate from Docker seamlessly

๐ŸŽฏ Why This Matters

Podman gives you:

  • ๐Ÿ”’ Better security (rootless!)
  • ๐Ÿ’พ No daemon overhead
  • ๐ŸŽฏ Kubernetes compatibility
  • ๐Ÿ”„ Easy Docker migration
  • ๐Ÿ›ก๏ธ SELinux integration
  • ๐Ÿ’ช Production-ready containers

Last week, a clientโ€™s Docker daemon crashed and took down their entire container infrastructure. We migrated them to Podman - now each container runs independently. One crashes? Others keep running. They havenโ€™t had downtime since! ๐Ÿš€

Remember: Containers are the future, and Podman is leading the charge. Rootless, daemonless, and secure by default. The way containers should be! ๐Ÿณ

Happy containerizing! May your pods be healthy and your images be slim! ๐ŸŽ‰โœจ