Aller au contenu
Conteneurs & Orchestration medium

Pods Podman : regrouper des conteneurs comme une unité

18 min de lecture

logo podman

Un pod Podman regroupe plusieurs conteneurs qui partagent le même espace réseau. Ils communiquent via localhost, démarrent et s’arrêtent ensemble. C’est idéal pour les patterns sidecar (app + reverse proxy, app + agent de logs).

À la fin de ce guide, vous saurez :

  • Créer un pod avec plusieurs conteneurs
  • Comprendre ce qui est partagé et ce qui ne l’est pas
  • Exposer correctement les ports
  • Éviter les pièges classiques

Le problème : conteneurs qui doivent communiquer étroitement

Section intitulée « Le problème : conteneurs qui doivent communiquer étroitement »

Certaines applications nécessitent plusieurs processus qui doivent :

  • Communiquer sur localhost (pas via le réseau)
  • Partager des volumes pour échanger des fichiers
  • Être démarrés/arrêtés ensemble

Exemples :

PatternConteneur principalSidecar
Reverse proxyApplicationnginx/envoy
LoggingApplicationFluentd/Vector
MonitoringApplicationPrometheus exporter
PHP-FPMnginxphp-fpm

Un pod est un groupe de conteneurs qui partagent :

  • Le namespace réseau (même interface, même localhost)
  • Le namespace IPC (communication inter-processus)
  • Optionnellement des volumes

Structure d'un pod Podman : nginx + php-fpm + infra partageant localhost

  1. Créer le pod

    Fenêtre de terminal
    podman pod create --name web-stack -p 8080:80

    Important : le port est exposé au niveau du pod, pas des conteneurs.

  2. Ajouter nginx

    Fenêtre de terminal
    podman run -d --pod web-stack --name nginx nginx:alpine
  3. Vérifier

    Fenêtre de terminal
    podman pod ps
    Résultat
    POD ID NAME STATUS CREATED INFRA ID # OF CONTAINERS
    abc123def456 web-stack Running 1 minute ago def456ghi789 2
  4. Tester

    Fenêtre de terminal
    curl http://localhost:8080

    Vous voyez la page d’accueil nginx.

  5. Voir les conteneurs du pod

    Fenêtre de terminal
    podman pod inspect web-stack --format '{{range .Containers}}{{.Name}} {{end}}'
    Résultat
    abc123def456-infra nginx

Notez qu’il y a 2 conteneurs : nginx + le conteneur “infra” (on y revient).

Tous les conteneurs d’un pod partagent la même interface réseau. Concrètement :

  • Ils ont la même IP
  • Ils peuvent communiquer via localhost
  • Un conteneur peut accéder aux ports des autres sans configuration

Démonstration :

Fenêtre de terminal
# Créer un pod avec deux conteneurs
podman pod create --name demo-net
podman run -d --pod demo-net --name server \
python:3.12-alpine python -m http.server 9000
podman run -d --pod demo-net --name client \
alpine:3.21 sleep infinity
# Le client peut accéder au serveur via localhost
podman exec client wget -qO- http://localhost:9000
Résultat
<!DOCTYPE HTML>
<html>...

Sans pod, il faudrait un réseau dédié et utiliser le nom du conteneur.

Quand vous créez un pod, Podman démarre automatiquement un conteneur spécial appelé infra (ou “pause”). Ce conteneur ne fait rien d’utile en apparence — il dort. Mais c’est lui qui détient les namespaces réseau et IPC que tous les autres conteneurs du pod partagent.

Son rôle :

FonctionExplication
Maintenir les namespacesMême si tous les conteneurs s’arrêtent, le namespace réseau persiste
Anchorer l’IPL’IP du pod ne change pas quand un conteneur redémarre
LégerUtilise ~1 MB de mémoire
Fenêtre de terminal
# Voir le conteneur infra
podman ps --pod | grep infra
Résultat
def456ghi789 k8s.gcr.io/pause:3.5 3 minutes ago Up web-stack-infra web-stack

Le partage se limite au réseau et aux IPC. Chaque conteneur conserve son propre système de fichiers, sa propre vision des processus, et ses propres limites de ressources. C’est une différence importante avec les VM où tout est partagé par défaut.

RessourcePartagée ?Explication
RéseauMême interface, même localhost
IPCCommunication inter-processus
Volumes⚠️Seulement si montés explicitement
PID namespaceChaque conteneur a ses propres PIDs
FilesystemChaque conteneur a son propre rootfs
Mémoire/CPULimites par conteneur

Pour partager des fichiers entre conteneurs, montez le même volume :

Fenêtre de terminal
# Créer un pod avec volume partagé
podman pod create --name shared-data
# Conteneur qui écrit
podman run -d --pod shared-data \
-v data:/shared:Z \
--name writer \
alpine:3.21 sh -c 'while true; do date >> /shared/log.txt; sleep 5; done'
# Conteneur qui lit
podman run -d --pod shared-data \
-v data:/shared:Z,ro \
--name reader \
alpine:3.21 tail -f /shared/log.txt

Les commandes podman pod agissent sur tous les conteneurs du pod en une seule opération. C’est l’intérêt principal : gérer un groupe comme une unité.

CommandeEffet
podman pod start <pod>Démarre tous les conteneurs
podman pod stop <pod>Arrête tous les conteneurs
podman pod restart <pod>Redémarre tous les conteneurs
podman pod rm <pod>Supprime le pod ET tous ses conteneurs
podman pod pause <pod>Met en pause tous les conteneurs
podman pod unpause <pod>Reprend tous les conteneurs
Fenêtre de terminal
# Créer un pod avec 2 conteneurs
podman pod create --name lifecycle-demo
podman run -d --pod lifecycle-demo --name c1 alpine:3.21 sleep infinity
podman run -d --pod lifecycle-demo --name c2 alpine:3.21 sleep infinity
# Vérifier l'état
podman pod ps
podman ps --pod
# Arrêter le pod (arrête c1 et c2)
podman pod stop lifecycle-demo
# Vérifier
podman ps -a --pod | grep lifecycle
Résultat
abc123 alpine:3.21 Exited c1 lifecycle-demo
def456 alpine:3.21 Exited c2 lifecycle-demo

Quand un conteneur dans un pod s’arrête inopinément :

SituationComportement
Un conteneur crashLes autres continuent
Tous les conteneurs crashentLe pod reste “Running” (infra actif)
Le conteneur infra crashLe pod est détruit

Important : contrairement à Kubernetes, Podman ne redémarre pas automatiquement les conteneurs crashés. Utilisez Quadlet ou systemd pour ça.

Les ports sont exposés au niveau du pod, pas des conteneurs individuels.

Fenêtre de terminal
# ✅ Correct : port sur le pod
podman pod create --name web -p 8080:80
podman run -d --pod web --name nginx nginx:alpine
# ❌ Incorrect : -p ignoré quand --pod est utilisé
podman run -d --pod web -p 9090:80 --name nginx nginx:alpine
# Warning: Le -p est ignoré !
Fenêtre de terminal
podman pod create --name multi-port \
-p 8080:80 \
-p 9000:9000 \
-p 3000:3000

Le modèle réseau d’un pod est volontairement simple : tout passe par localhost. C’est parfait pour des conteneurs couplés (nginx → php-fpm), mais insuffisant pour des architectures distribuées.

FonctionnalitéDisponible ?Alternative
localhost entre conteneurs
Ports exposés à l’hôte
Service discovery (DNS)Utiliser podman-compose ou des réseaux bridge
Load balancingTraefik, nginx reverse proxy

Le cas d’usage classique : nginx sert les fichiers statiques et fait proxy vers php-fpm pour le PHP.

nginx + php-fpm dans un pod : proxy vers FastCGI avec volume partagé

  1. Créer le contenu PHP

    Fenêtre de terminal
    mkdir -p ~/lab-pod/html
    ~/lab-pod/html/index.php
    <?php
    echo "<h1>PHP dans un pod Podman</h1>";
    echo "<p>Hostname: " . gethostname() . "</p>";
    echo "<p>Date: " . date('Y-m-d H:i:s') . "</p>";
    phpinfo();
    ?>
  2. Configuration nginx

    ~/lab-pod/nginx.conf
    server {
    listen 80;
    server_name localhost;
    root /var/www/html;
    index index.php index.html;
    location ~ \.php$ {
    # php-fpm sur localhost:9000 (même pod)
    fastcgi_pass 127.0.0.1:9000;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    include fastcgi_params;
    }
    location / {
    try_files $uri $uri/ =404;
    }
    }
  3. Créer le pod avec le port

    Fenêtre de terminal
    podman pod create --name web-php -p 8080:80
  4. Lancer php-fpm

    Fenêtre de terminal
    podman run -d --pod web-php \
    --name php-fpm \
    -v ~/lab-pod/html:/var/www/html:Z \
    php:8.3-fpm-alpine
  5. Lancer nginx

    Fenêtre de terminal
    podman run -d --pod web-php \
    --name nginx \
    -v ~/lab-pod/html:/var/www/html:Z,ro \
    -v ~/lab-pod/nginx.conf:/etc/nginx/conf.d/default.conf:Z,ro \
    nginx:alpine
  6. Vérifier

    Fenêtre de terminal
    # État du pod
    podman pod ps
    # Conteneurs
    podman ps --pod
    # Tester
    curl http://localhost:8080/index.php
Fenêtre de terminal
# Vérifier que les conteneurs sont dans le même pod
podman pod inspect web-php --format '{{range .Containers}}{{.Name}} {{end}}'
# php-fpm nginx abc123-infra
# Vérifier que localhost:9000 fonctionne depuis nginx
podman exec nginx sh -c 'echo "test" | nc -z 127.0.0.1 9000 && echo "OK"'
# OK
# Logs
podman logs nginx
podman logs php-fpm

Podman supporte les deux : pods natifs et Compose. La question revient souvent : “Pourquoi utiliser un pod plutôt que Compose ?”

La réponse tient en une phrase : les pods sont pour les conteneurs qui doivent partager localhost, Compose pour les services qui communiquent via le réseau.

CritèrePodCompose
Conteneurs sur localhostIdéal⚠️ Possible mais pas natif
Services indépendantsIdéal
Stack multi-services (db + api + front)⚠️
Pattern sidecarIdéal⚠️
Compatibilité Kubernetes YAML
Service discovery (DNS)
Déjà un docker-compose.yml
  • Pod : conteneurs couplés qui doivent partager localhost
  • Compose : services découplés qui communiquent via le réseau
SituationMeilleur choix
nginx + php-fpmPod (localhost:9000)
App + redis + postgresCompose (services séparés)
App + envoy sidecarPod (proxy localhost)
MicroservicesCompose (service discovery)
Test d’un YAML KubernetesPod (kube play)

Les pods Podman s’inspirent de Kubernetes, mais ne sont pas identiques. Podman est un outil local sans orchestrateur — les fonctionnalités qui dépendent d’un cluster (scheduling, service discovery, restart automatique) sont absentes.

Si vous connaissez Kubernetes, attention aux différences :

AspectPodman podsKubernetes pods
Restart automatique❌ Non✅ Oui (restartPolicy)
Service discovery DNS❌ Non✅ Oui
Load balancing❌ Non✅ Oui (Services)
Scheduling❌ Local uniquement✅ Multi-nodes
Health checks⚠️ Manuels✅ livenessProbe, readinessProbe
Resource limits⚠️ Par conteneur✅ Pod-level + container-level
  1. Pas de restart auto : en production, utilisez Quadlet/systemd
  2. Pas de DNS : utilisez localhost, pas des noms de service
  3. Ports au pod : pas de -p sur podman run --pod

La plupart des problèmes avec les pods viennent de deux sources : les ports mal configurés, et les conteneurs qui ne sont pas dans le bon pod. Le tableau ci-dessous couvre 90% des cas.

ErreurCauseSolution
port already in usePort exposé sur un pod existantpodman pod rm <pod>
-p ignoré avec --podPorts = responsabilité du podCréer le pod avec -p
Conteneur ne voit pas l’autreMauvais port ou conteneur pas dans le podVérifier avec podman pod inspect
Connection refused localhostLe service n’écoute pas sur toutes les interfacesVérifier que le service écoute sur 0.0.0.0
Fenêtre de terminal
# Lister les pods
podman pod ps
# Voir les conteneurs d'un pod
podman ps --pod --filter pod=<pod-name>
# Inspecter un pod
podman pod inspect <pod-name>
# Voir les ports d'un pod
podman pod inspect <pod-name> --format '{{.InfraConfig.PortBindings}}'
# Logs de tous les conteneurs du pod
podman pod logs <pod-name>
# Tester localhost depuis un conteneur
podman exec <container> wget -qO- http://localhost:<port>
# Nettoyer
podman pod rm -f <pod-name>
Fenêtre de terminal
# Vérifier les logs
podman logs <container-name>
# Vérifier que le pod est Running
podman pod ps
# Recréer le pod
podman pod rm -f <pod-name>
podman pod create --name <pod-name> -p <ports>
Fenêtre de terminal
# ✅ Noms explicites
podman pod create --name api-stack
podman run --pod api-stack --name api-server ...
podman run --pod api-stack --name api-cache ...
# ❌ Noms génériques
podman pod create --name pod1
podman run --pod pod1 --name container1 ...
  • Un pod = un groupe fonctionnel (app + sidecars)
  • Pas de pod monolithique avec 10 services indépendants
  • Volumes partagés seulement si nécessaire

Pour la production, ne lancez pas les pods manuellement. Utilisez :

  1. Pod = groupe de conteneurs partageant le réseau (même localhost)
  2. Conteneur infra : maintient les namespaces, ne pas supprimer
  3. Ports exposés au pod : -p sur podman pod create, pas sur run
  4. Pas de restart auto : utilisez Quadlet/systemd en production
  5. Pas de DNS : communication via localhost:<port>
  6. Pod vs Compose : pod pour couplage fort, Compose pour services séparés

Ce site vous est utile ?

Sachez que moins de 1% des lecteurs soutiennent ce site.

Je maintiens +700 guides gratuits, sans pub ni tracing. Aujourd'hui, ce site ne couvre même pas mes frais d'hébergement, d'électricité, de matériel, de logiciels, mais surtout de cafés.

Un soutien régulier, même symbolique, m'aide à garder ces ressources gratuites et à continuer de produire des guides de qualité. Merci pour votre appui.