Skip to content

Podman : Docker sans Daemon

Pourquoi Podman sur RHEL ?

Podman (Pod Manager) est le remplaçant officiel de Docker sur RHEL 8+ et Fedora. Red Hat a choisi Podman pour des raisons de sécurité et d'architecture.

Architecture : Docker vs Podman

graph TD
    subgraph "Docker (Architecture Daemon)"
        A[docker CLI] -->|Socket Unix| B[dockerd<br/>Daemon Root]
        B -->|Fork| C1[Container 1<br/>PID namespace]
        B -->|Fork| C2[Container 2<br/>PID namespace]
        B -->|Single Point<br/>of Failure| D[☠️ Si dockerd crash<br/>tous les conteneurs meurent]
    end

    subgraph "Podman (Architecture Fork/Exec)"
        E[podman CLI] -->|Direct Fork/Exec| F1[Container 1<br/>Processus Utilisateur]
        E -->|Direct Fork/Exec| F2[Container 2<br/>Processus Utilisateur]
        E -->|Rootless| G[✅ Pas de daemon root<br/>Isolation totale]
    end

    style B fill:#f44336,stroke:#b00016,color:#fff
    style D fill:#f44336,stroke:#b00016,color:#fff
    style E fill:#4CAF50,stroke:#0b5a0d,color:#fff
    style G fill:#4CAF50,stroke:#0b5a0d,color:#fff

Avantages de Podman

Critère Docker Podman
Daemon Oui (root) Non (fork/exec direct)
Rootless Expérimental Natif et stable
Systemd Non intégré Génération d'unités native
Pods Non (Swarm différent) Oui (compatible Kubernetes)
API Docker Oui Compatible via socket
SELinux Complexe Intégré (RHEL)
Image Build Intégré Buildah (séparé)

Installation

# Sur RHEL 8/9, Rocky, AlmaLinux
dnf install podman -y

# Vérifier la version
podman --version
# podman version 4.x.x

# Installer les outils complémentaires
dnf install podman-compose buildah skopeo -y

Transition Docker → Podman

Alias Transparent

# Ajouter dans ~/.bashrc ou /etc/bashrc
alias docker=podman
alias docker-compose=podman-compose

# Recharger
source ~/.bashrc

# Maintenant, toutes les commandes docker fonctionnent !
docker run hello-world
docker ps
docker images

Différences Clés à Connaître

Commande Docker Équivalent Podman Notes
docker run -d nginx podman run -d nginx Identique
docker ps podman ps Identique
docker-compose up podman-compose up Nécessite podman-compose
docker build -t img . podman build -t img . Ou buildah bud
docker network create podman network create Identique
docker volume create podman volume create Identique
systemctl restart docker ⚠️ N'existe pas Pas de daemon

Pas de Daemon = Pas de Systemctl

Podman n'a pas de daemon global. Chaque conteneur est un processus indépendant. Pour démarrer au boot, utiliser podman generate systemd (voir plus bas).

Rootless Containers : Le Game Changer

Concept

Un utilisateur non-root peut lancer des conteneurs sans sudo, avec isolation complète via user namespaces.

# En tant qu'utilisateur normal (pas de sudo !)
podman run -d --name web -p 8080:80 nginx

# Vérifier
podman ps
# CONTAINER ID  IMAGE   COMMAND  PORTS                 NAMES
# abc123def456  nginx   ...      0.0.0.0:8080->80/tcp  web

# Tester
curl http://localhost:8080
# Welcome to nginx!

Configuration Rootless

1. User Namespaces (subuid/subgid)

# Vérifier les mappings utilisateur
cat /etc/subuid
# user1:100000:65536

cat /etc/subgid
# user1:100000:65536

# Si absent, ajouter manuellement
sudo usermod --add-subuids 100000-165535 user1
sudo usermod --add-subgids 100000-165535 user1

2. Limites de Ports (<1024)

Par défaut, les utilisateurs non-root ne peuvent pas binder sur les ports < 1024. Solution :

# Option 1 : Utiliser des ports > 1024 et un reverse proxy
podman run -d -p 8080:80 nginx  # OK

# Option 2 : Autoriser les low ports (RHEL 8+)
sudo sysctl net.ipv4.ip_unprivileged_port_start=80
# Persistant :
echo "net.ipv4.ip_unprivileged_port_start=80" | sudo tee /etc/sysctl.d/podman-ports.conf
sudo sysctl -p /etc/sysctl.d/podman-ports.conf

# Option 3 : Utiliser CAP_NET_BIND_SERVICE (rootful)
sudo setcap cap_net_bind_service=+ep /usr/bin/podman

3. Stockage Rootless

# Les images/conteneurs rootless sont stockés dans le home
ls ~/.local/share/containers/storage/

# Lister les images (rootless)
podman images

# Comparer avec les images root
sudo podman images
# ⚠️ Différent ! Root et rootless ont des storages séparés

Sécurité : Rootless vs Rootful

# Rootless : Le conteneur tourne sous l'UID de l'utilisateur
podman run --rm alpine id
# uid=0(root) gid=0(root)  # ⚠️ root DANS le conteneur

# Mais sur l'hôte, c'est mappé à l'UID user
ps aux | grep alpine
# user1  12345  ... /usr/bin/conmon --api-version 2 ...

# Rootful : Le conteneur est réellement root
sudo podman run --rm alpine id
# uid=0(root) gid=0(root)  # Root aussi sur l'hôte

SecNumCloud : Privilégier Rootless

Les conteneurs rootless offrent une isolation supplémentaire. Si un attaquant échappe du conteneur, il est user1 sur l'hôte, pas root.

Pods : Le Concept Kubernetes en Local

Un Pod est un groupe de conteneurs partageant le même namespace réseau (comme dans Kubernetes).

Créer un Pod Multi-Conteneurs

# Créer un pod (crée automatiquement un conteneur "infra" pause)
podman pod create --name webapp -p 8080:80

# Ajouter un conteneur nginx dans le pod
podman run -d --pod webapp --name web nginx

# Ajouter un conteneur PHP-FPM dans le même pod
podman run -d --pod webapp --name php php:fpm

# Les 2 conteneurs partagent localhost !
# Nginx peut atteindre PHP via localhost:9000

# Lister les pods
podman pod ps
# POD ID     NAME    STATUS   CREATED   # OF CONTAINERS
# abc123...  webapp  Running  5m ago    3

# Voir les conteneurs du pod
podman ps --pod
# CONTAINER ID  POD ID    IMAGE        NAMES
# def456...     abc123... nginx        web
# ghi789...     abc123... php:fpm      php
# jkl012...     abc123... pause:3.5    abc123-infra

Exporter un Pod en YAML Kubernetes

# Générer le YAML
podman generate kube webapp > webapp-pod.yaml

# Contenu (compatible Kubernetes)
cat webapp-pod.yaml
# apiVersion: v1
# kind: Pod
# metadata:
#   name: webapp
# spec:
#   containers:
#   - name: web
#     image: nginx
#   - name: php
#     image: php:fpm

# Recréer le pod depuis le YAML
podman play kube webapp-pod.yaml

Systemd Integration : Auto-Start au Boot

Podman peut générer des unités systemd pour démarrer les conteneurs automatiquement.

Générer une Unité Systemd

# Lancer un conteneur
podman run -d --name nginx-prod -p 8080:80 nginx

# Générer l'unité systemd (rootless)
podman generate systemd --name nginx-prod --files --new
# Crée : container-nginx-prod.service

# Copier dans le répertoire utilisateur
mkdir -p ~/.config/systemd/user/
mv container-nginx-prod.service ~/.config/systemd/user/

# Recharger systemd
systemctl --user daemon-reload

# Activer au boot (nécessite lingering)
loginctl enable-linger $USER

# Activer le service
systemctl --user enable container-nginx-prod.service
systemctl --user start container-nginx-prod.service

# Vérifier
systemctl --user status container-nginx-prod.service

Systemd Rootful (Admin Système)

# Lancer un conteneur root
sudo podman run -d --name nginx-prod -p 80:80 nginx

# Générer l'unité
sudo podman generate systemd --name nginx-prod --files --new

# Copier dans systemd système
sudo mv container-nginx-prod.service /etc/systemd/system/

# Activer
sudo systemctl daemon-reload
sudo systemctl enable container-nginx-prod.service
sudo systemctl start container-nginx-prod.service

Gérer un Pod avec Systemd

# Créer un pod
podman pod create --name webapp -p 8080:80
podman run -d --pod webapp --name web nginx
podman run -d --pod webapp --name php php:fpm

# Générer les unités pour TOUT le pod
podman generate systemd --name webapp --files --new
# Crée : pod-webapp.service
#        container-webapp-web.service
#        container-webapp-php.service

# Copier
mkdir -p ~/.config/systemd/user/
mv pod-webapp.service container-*.service ~/.config/systemd/user/

# Activer le pod (active automatiquement les conteneurs)
systemctl --user enable pod-webapp.service
systemctl --user start pod-webapp.service

Build d'Images : Podman vs Buildah

Avec Podman (Compatible Dockerfile)

# Créer un Dockerfile
cat > Dockerfile <<'EOF'
FROM nginx:alpine
COPY index.html /usr/share/nginx/html/
EXPOSE 80
EOF

# Build
podman build -t my-nginx:v1 .

# Run
podman run -d -p 8080:80 my-nginx:v1

Avec Buildah (Approche Scriptée)

# Créer un conteneur de travail
ctr=$(buildah from alpine)

# Installer des paquets
buildah run $ctr apk add nginx

# Copier des fichiers
buildah copy $ctr index.html /usr/share/nginx/html/

# Configurer
buildah config --entrypoint '["nginx", "-g", "daemon off;"]' $ctr
buildah config --port 80 $ctr

# Commit l'image
buildah commit $ctr my-nginx:buildah

# Lister
buildah images
podman images  # Même registry !

Networking

# Lister les réseaux
podman network ls
# podman (default bridge)

# Créer un réseau custom
podman network create mynet

# Lancer des conteneurs sur le réseau
podman run -d --name web --network mynet nginx
podman run -d --name db --network mynet postgres

# Les conteneurs peuvent se pinguer par nom !
podman exec web ping db

Registries & Skopeo

# Chercher une image
podman search nginx

# Pull depuis un registry
podman pull docker.io/library/nginx

# Push vers un registry privé
podman tag nginx localhost:5000/my-nginx
podman push localhost:5000/my-nginx

# Skopeo : Inspecter/Copier sans pull
skopeo inspect docker://docker.io/nginx
skopeo copy docker://nginx:latest docker://localhost:5000/nginx:latest

Dépannage

# Logs d'un conteneur
podman logs -f container_name

# Inspecter
podman inspect container_name

# Entrer dans un conteneur
podman exec -it container_name /bin/bash

# Stats ressources
podman stats

# Voir les events
podman events

# Vérifier les permissions rootless
podman unshare cat /proc/self/uid_map

Checklist Production

# 1. Podman installé
podman --version

# 2. Rootless configuré (subuid/subgid)
grep $USER /etc/subuid

# 3. Lingering activé pour auto-start
loginctl show-user $USER | grep Linger
# Linger=yes

# 4. Systemd units générées
systemctl --user list-unit-files | grep container

# 5. Images locales listées
podman images

# 6. Conteneurs en run
podman ps

# 7. Pods actifs
podman pod ps

Liens Utiles