
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
Droit au but
Section intitulée « Droit au but »Pourquoi utiliser un pod ?
Section intitulée « Pourquoi utiliser un pod ? »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 :
| Pattern | Conteneur principal | Sidecar |
|---|---|---|
| Reverse proxy | Application | nginx/envoy |
| Logging | Application | Fluentd/Vector |
| Monitoring | Application | Prometheus exporter |
| PHP-FPM | nginx | php-fpm |
La solution : le pod
Section intitulée « La solution : le pod »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
Premier pod en 5 minutes
Section intitulée « Premier pod en 5 minutes »-
Créer le pod
Fenêtre de terminal podman pod create --name web-stack -p 8080:80Important : le port est exposé au niveau du pod, pas des conteneurs.
-
Ajouter nginx
Fenêtre de terminal podman run -d --pod web-stack --name nginx nginx:alpine -
Vérifier
Fenêtre de terminal podman pod psRésultat POD ID NAME STATUS CREATED INFRA ID # OF CONTAINERSabc123def456 web-stack Running 1 minute ago def456ghi789 2 -
Tester
Fenêtre de terminal curl http://localhost:8080Vous voyez la page d’accueil nginx.
-
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).
Ce qui est partagé
Section intitulée « Ce qui est partagé »Le namespace réseau
Section intitulée « Le namespace réseau »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 :
# Créer un pod avec deux conteneurspodman 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 localhostpodman exec client wget -qO- http://localhost:9000<!DOCTYPE HTML><html>...Sans pod, il faudrait un réseau dédié et utiliser le nom du conteneur.
Le conteneur infra (pause)
Section intitulée « Le conteneur infra (pause) »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 :
| Fonction | Explication |
|---|---|
| Maintenir les namespaces | Même si tous les conteneurs s’arrêtent, le namespace réseau persiste |
| Anchorer l’IP | L’IP du pod ne change pas quand un conteneur redémarre |
| Léger | Utilise ~1 MB de mémoire |
# Voir le conteneur infrapodman ps --pod | grep infradef456ghi789 k8s.gcr.io/pause:3.5 3 minutes ago Up web-stack-infra web-stackCe qui N’est PAS partagé
Section intitulée « Ce qui N’est PAS partagé »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.
| Ressource | Partagée ? | Explication |
|---|---|---|
| Réseau | ✅ | Même interface, même localhost |
| IPC | ✅ | Communication inter-processus |
| Volumes | ⚠️ | Seulement si montés explicitement |
| PID namespace | ❌ | Chaque conteneur a ses propres PIDs |
| Filesystem | ❌ | Chaque conteneur a son propre rootfs |
| Mémoire/CPU | ❌ | Limites par conteneur |
Partager des volumes
Section intitulée « Partager des volumes »Pour partager des fichiers entre conteneurs, montez le même volume :
# Créer un pod avec volume partagépodman pod create --name shared-data
# Conteneur qui écritpodman 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 litpodman run -d --pod shared-data \ -v data:/shared:Z,ro \ --name reader \ alpine:3.21 tail -f /shared/log.txtLifecycle : pod vs conteneurs
Section intitulée « Lifecycle : pod vs conteneurs »Commandes de pod
Section intitulée « Commandes de pod »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é.
| Commande | Effet |
|---|---|
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 |
Démonstration du lifecycle
Section intitulée « Démonstration du lifecycle »# Créer un pod avec 2 conteneurspodman pod create --name lifecycle-demopodman run -d --pod lifecycle-demo --name c1 alpine:3.21 sleep infinitypodman run -d --pod lifecycle-demo --name c2 alpine:3.21 sleep infinity
# Vérifier l'étatpodman pod pspodman ps --pod
# Arrêter le pod (arrête c1 et c2)podman pod stop lifecycle-demo
# Vérifierpodman ps -a --pod | grep lifecycleabc123 alpine:3.21 Exited c1 lifecycle-demodef456 alpine:3.21 Exited c2 lifecycle-demoComportement au redémarrage
Section intitulée « Comportement au redémarrage »Quand un conteneur dans un pod s’arrête inopinément :
| Situation | Comportement |
|---|---|
| Un conteneur crash | Les autres continuent |
| Tous les conteneurs crashent | Le pod reste “Running” (infra actif) |
| Le conteneur infra crash | Le pod est détruit |
Important : contrairement à Kubernetes, Podman ne redémarre pas automatiquement les conteneurs crashés. Utilisez Quadlet ou systemd pour ça.
Exposition réseau : ports et limites
Section intitulée « Exposition réseau : ports et limites »Règle fondamentale
Section intitulée « Règle fondamentale »Les ports sont exposés au niveau du pod, pas des conteneurs individuels.
# ✅ Correct : port sur le podpodman pod create --name web -p 8080:80podman 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é !Exposer plusieurs ports
Section intitulée « Exposer plusieurs ports »podman pod create --name multi-port \ -p 8080:80 \ -p 9000:9000 \ -p 3000:3000Limites du réseau pod
Section intitulée « Limites du réseau pod »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 balancing | ❌ | Traefik, nginx reverse proxy |
Recette : nginx + php-fpm
Section intitulée « Recette : nginx + php-fpm »Le cas d’usage classique : nginx sert les fichiers statiques et fait proxy vers php-fpm pour le PHP.
Architecture
Section intitulée « Architecture »Implémentation
Section intitulée « Implémentation »-
Créer le contenu PHP
Fenêtre de terminal mkdir -p ~/lab-pod/html~/lab-pod/html/index.php <?phpecho "<h1>PHP dans un pod Podman</h1>";echo "<p>Hostname: " . gethostname() . "</p>";echo "<p>Date: " . date('Y-m-d H:i:s') . "</p>";phpinfo();?> -
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;}} -
Créer le pod avec le port
Fenêtre de terminal podman pod create --name web-php -p 8080:80 -
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 -
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 -
Vérifier
Fenêtre de terminal # État du podpodman pod ps# Conteneurspodman ps --pod# Testercurl http://localhost:8080/index.php
Vérifications
Section intitulée « Vérifications »# Vérifier que les conteneurs sont dans le même podpodman pod inspect web-php --format '{{range .Containers}}{{.Name}} {{end}}'# php-fpm nginx abc123-infra
# Vérifier que localhost:9000 fonctionne depuis nginxpodman exec nginx sh -c 'echo "test" | nc -z 127.0.0.1 9000 && echo "OK"'# OK
# Logspodman logs nginxpodman logs php-fpmPods vs Compose : règle de décision
Section intitulée « Pods vs Compose : règle de décision »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.
Tableau de décision
Section intitulée « Tableau de décision »| Critère | Pod | Compose |
|---|---|---|
| Conteneurs sur localhost | ✅ Idéal | ⚠️ Possible mais pas natif |
| Services indépendants | ❌ | ✅ Idéal |
| Stack multi-services (db + api + front) | ⚠️ | ✅ |
| Pattern sidecar | ✅ Idéal | ⚠️ |
| Compatibilité Kubernetes YAML | ✅ | ❌ |
| Service discovery (DNS) | ❌ | ✅ |
| Déjà un docker-compose.yml | ❌ | ✅ |
Règle simple
Section intitulée « Règle simple »- Pod : conteneurs couplés qui doivent partager localhost
- Compose : services découplés qui communiquent via le réseau
Exemples
Section intitulée « Exemples »| Situation | Meilleur choix |
|---|---|
| nginx + php-fpm | Pod (localhost:9000) |
| App + redis + postgres | Compose (services séparés) |
| App + envoy sidecar | Pod (proxy localhost) |
| Microservices | Compose (service discovery) |
| Test d’un YAML Kubernetes | Pod (kube play) |
Différences avec les pods Kubernetes
Section intitulée « Différences avec les pods Kubernetes »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 :
| Aspect | Podman pods | Kubernetes 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 |
Ce qui pique quand on passe à Kubernetes
Section intitulée « Ce qui pique quand on passe à Kubernetes »- Pas de restart auto : en production, utilisez Quadlet/systemd
- Pas de DNS : utilisez
localhost, pas des noms de service - Ports au pod : pas de
-psurpodman run --pod
Dépannage
Section intitulée « Dépannage »Erreurs courantes
Section intitulée « Erreurs courantes »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.
| Erreur | Cause | Solution |
|---|---|---|
port already in use | Port exposé sur un pod existant | podman pod rm <pod> |
-p ignoré avec --pod | Ports = responsabilité du pod | Créer le pod avec -p |
| Conteneur ne voit pas l’autre | Mauvais port ou conteneur pas dans le pod | Vérifier avec podman pod inspect |
| Connection refused localhost | Le service n’écoute pas sur toutes les interfaces | Vérifier que le service écoute sur 0.0.0.0 |
Commandes de diagnostic
Section intitulée « Commandes de diagnostic »# Lister les podspodman pod ps
# Voir les conteneurs d'un podpodman ps --pod --filter pod=<pod-name>
# Inspecter un podpodman pod inspect <pod-name>
# Voir les ports d'un podpodman pod inspect <pod-name> --format '{{.InfraConfig.PortBindings}}'
# Logs de tous les conteneurs du podpodman pod logs <pod-name>
# Tester localhost depuis un conteneurpodman exec <container> wget -qO- http://localhost:<port>
# Nettoyerpodman pod rm -f <pod-name>Le conteneur ne démarre pas dans le pod
Section intitulée « Le conteneur ne démarre pas dans le pod »# Vérifier les logspodman logs <container-name>
# Vérifier que le pod est Runningpodman pod ps
# Recréer le podpodman pod rm -f <pod-name>podman pod create --name <pod-name> -p <ports>Bonnes pratiques
Section intitulée « Bonnes pratiques »# ✅ Noms explicitespodman pod create --name api-stackpodman run --pod api-stack --name api-server ...podman run --pod api-stack --name api-cache ...
# ❌ Noms génériquespodman pod create --name pod1podman run --pod pod1 --name container1 ...Organisation
Section intitulée « Organisation »- Un pod = un groupe fonctionnel (app + sidecars)
- Pas de pod monolithique avec 10 services indépendants
- Volumes partagés seulement si nécessaire
Production
Section intitulée « Production »Pour la production, ne lancez pas les pods manuellement. Utilisez :
- Quadlet : fichiers déclaratifs → systemd (voir le guide)
- kube play : fichiers YAML Kubernetes (voir le guide)
À retenir
Section intitulée « À retenir »- Pod = groupe de conteneurs partageant le réseau (même localhost)
- Conteneur infra : maintient les namespaces, ne pas supprimer
- Ports exposés au pod :
-psurpodman pod create, pas surrun - Pas de restart auto : utilisez Quadlet/systemd en production
- Pas de DNS : communication via
localhost:<port> - Pod vs Compose : pod pour couplage fort, Compose pour services séparés