Aller au contenu
English
Compte : non connecté, synchronisation possible Mon apprentissage
Selectionner le thème
English

Maîtriser Podman : conteneurs rootless, systemd et pods

Par mis à jour le

Améliorer cette page

Logo Podman

Podman est un moteur de conteneurs sans démon obligatoire (daemonless), pensé pour une utilisation Linux native : rootless par défaut, intégration propre à systemd via Quadlet, et support des pods façon Kubernetes. Sur macOS et Windows, il s'appuie sur Podman Machine (une VM Linux). Ce guide couvre la version stable 5.8 et signale les changements de Podman 6.

Cette page présente la formation en trois temps : un modèle mental de l'outil, un démarrage rapide de cinq minutes, puis un aperçu des trois piliers (rootless, réseau, systemd) qui renvoie vers la leçon qui détaille chacun. Le plan des modules et l'état des versions par distribution viennent ensuite.

Trois décisions d'architecture expliquent l'essentiel des différences que vous constaterez avec Docker, et donc l'essentiel des surprises. Elles ne sont pas indépendantes : c'est parce que Podman n'a pas de démon qu'un conteneur peut appartenir à votre session utilisateur, et c'est parce qu'il appartient à votre session que systemd peut en prendre la charge comme de n'importe quel autre processus. Gardez cet enchaînement en tête, il rend prévisible le comportement de l'outil.

  1. Rootless : les conteneurs tournent avec les droits de votre utilisateur, via les user namespaces.
  2. Daemonless : pas de service central permanent pour gérer vos conteneurs au quotidien.
  3. Systemd-first : avec Quadlet, un conteneur devient un service propre (restart, logs, dépendances).
  4. Bonus, pods et kube play : regrouper des conteneurs façon Kubernetes et lancer des manifests sans cluster.

Pour le « pourquoi » et les détails d'architecture, voir les concepts Podman.

Objectif : valider que Podman tourne, savoir exposer un port, lire des logs, monter un volume, puis nettoyer.

Deux détails de cette séquence n'ont pas d'équivalent sous Docker. Le nom d'image est complet (docker.io/library/nginx) parce que Podman ne préfixe pas silencieusement les noms courts : il vous demandera de choisir un registre si vous écrivez seulement nginx. Et le suffixe :Z sur le volume demande à Podman de réétiqueter le répertoire pour SELinux ; sans lui, sur Fedora ou RHEL, le conteneur lira un permission denied alors que les droits Unix sont corrects.

La référence d'image porte aussi un tag et un digest : nginx:1.31.6-alpine@sha256:…. Le tag dit quelle version vous lisez, le digest garantit que vous tirez exactement l'image que ce guide a testée, même si l'éditeur republie un jour le même tag avec un autre contenu. Ce digest se relit au registre avec skopeo inspect, présenté dans le guide Skopeo.

Fenêtre de terminal
# Vérifier la version
podman version
# Lancer un conteneur nginx
podman run -d --name web -p 8080:80 \
docker.io/library/nginx:1.31.6-alpine@sha256:df221db836e1754089190208cee7eeda94f233197056426eda74a43ab1abeac2
# Vérifier qu'il tourne
curl http://localhost:8080
# Voir les logs
podman logs web
# Tester un volume (SELinux : :Z) : le dossier doit exister
mkdir -p ~/html && echo ok > ~/html/index.html
podman run -d --name web2 -v ~/html:/usr/share/nginx/html:Z -p 8081:80 \
docker.io/library/nginx:1.31.6-alpine@sha256:df221db836e1754089190208cee7eeda94f233197056426eda74a43ab1abeac2
# Vérifier le volume : la page servie est votre fichier
curl http://localhost:8081
# Nettoyer
podman rm -f web web2

Si Podman n'est pas encore installé, commencez par l'installation ; pour comprendre ce qui vient de se passer, les concepts expliquent rootless, daemonless et pods, et les commandes de base donnent les gestes indispensables.

L'objectif n'est pas une comparaison exhaustive, mais de vous aider à décider vite, puis de vous envoyer vers les guides.

Le schéma résume la différence d'architecture qui fonde tout le reste : chez Docker, la commande passe par le daemon dockerd, qui tourne en root ; chez Podman, chaque conteneur est suivi par un petit processus conmon lancé avec les droits de l'utilisateur.

Comparaison d'architecture : côté Docker, la commande docker passe par le daemon dockerd, exécuté en root, qui lance les conteneurs ; côté Podman, la commande podman lance les conteneurs via conmon, exécuté avec les droits de l'utilisateur.Architecture Dockerdocker CLIdockerddaemon rootconteneursArchitecture Podmanpodman CLIconmonutilisateurconteneurs
Source · SVG
Échap pour fermer, + et − pour zoomer, défilement pour se déplacer. 100 %

Ces quatre situations ont un point commun : elles portent sur l'exploitation de la machine, pas sur le développement de l'application. Podman se distingue quand vous devez rendre des comptes sur qui exécute quoi, sur un serveur que vous administrez.

  • Vous voulez rootless par défaut (multi-utilisateurs, postes partagés, moindre risque).
  • Vous voulez des services systemd propres (serveur, self-hosting, edge).
  • Vous voulez rester proche de Kubernetes (pods, kube play, kube generate).
  • Vous voulez éviter un daemon central obligatoire sur la machine.

À l'inverse, deux contextes rendent la migration plus coûteuse que le bénéfice attendu. Dans les deux cas, l'obstacle n'est pas technique mais lié à l'outillage autour : podman compose délègue à docker-compose ou à podman-compose selon ce qui est installé, et les comportements divergent sur les fichiers Compose élaborés.

  • Votre quotidien dépend d'un Docker Compose complexe et d'intégrations « Docker-only ».
  • Vous êtes dans un contexte où l'écosystème Docker Desktop est imposé.

Le mode rootless est le gros avantage de Podman, mais il a des implications concrètes.

Podman utilise les user namespaces pour mapper les identités du conteneur vers des UID/GID non privilégiés sur l'hôte :

Hôte Conteneur
─────────────────────────────────────────────
UID 1000 (vous) UID 0 (root)
UID 100000-165535 (subuid) UID 1-65535

Ces trois frictions découlent toutes du même fait : votre conteneur croit être root, l'hôte sait qu'il ne l'est pas. Lisez la colonne Symptôme en premier, c'est le message d'erreur exact que vous verrez. La plus fréquente en pratique est celle des volumes. Le root du conteneur correspond à votre propre compte, ses fichiers vous appartiennent donc ; mais une image applicative tourne souvent sous un utilisateur non root, par exemple l'UID 1000, et ses fichiers apparaissent sur l'hôte avec un UID de votre plage subuid (100999 avec le mappage ci-dessus), illisibles par votre compte tant que vous n'avez pas ajouté --userns=keep-id.

FrictionSymptômeRéflexe
Ports basbind: permission denied sur 80/443utiliser ≥1024 ou sysctl net.ipv4.ip_unprivileged_port_start
Volumesfichiers root:root ou permission denied--userns=keep-id ou options de volume
RéseauDNS ou perf surprenantsréseau dédié + backend adapté

Deux leçons traitent ces frictions à fond. Le run avancé explique les user namespaces, l'option --userns=keep-id et le durcissement d'un conteneur (capacités, options de sécurité), et la leçon volumes traite la persistance des données et les permissions des fichiers partagés avec l'hôte.

En rootless, c'est souvent le réseau qui surprend. L'objectif : un réseau où les conteneurs se résolvent par nom avec une perf correcte. Depuis Podman 5, le backend par défaut est Netavark (avec Aardvark pour le DNS) et la pile réseau rootless par défaut est Pasta.

L'exemple ci-dessous crée un réseau nommé, y lance une base PostgreSQL appelée db, puis un client Alpine qui la joint par son nom. Le ping doit répondre 1 packets received : c'est Aardvark qui a résolu db en adresse IP. Sur le réseau par défaut, cette résolution par nom n'existe pas, d'où le réseau dédié. Le mot de passe de la base est lu depuis une variable du shell, pour ne pas l'écrire dans l'historique.

Fenêtre de terminal
# Créer un réseau applicatif (résolution DNS par nom)
podman network create app-network
# Un conteneur "db" et un client qui le joint par son nom
export PGPASS="$(openssl rand -base64 24)"
podman run -d --network app-network --name db -e POSTGRES_PASSWORD="$PGPASS" \
docker.io/library/postgres:16.15-alpine@sha256:721873c34ceb9f8d8fc265984940dc982404c105f19ad51be9fdc5970a6080ea
podman run --rm --network app-network \
docker.io/library/alpine:3.24@sha256:294b683cb724975bec92580e1e685676bd4b50bda910ddb8c51d4cabeaec77e6 \
ping -c 1 db
# Nettoyer avant la suite (le pod réutilise le nom db)
podman rm -f db && podman network rm app-network

La leçon réseaux Podman détaille le reste : le DNS interne, la publication des ports en rootless, l'isolation entre réseaux et une architecture multi-tier complète.

Pour du « prod-like » sur un serveur Linux, Quadlet est le point d'inflexion : un conteneur devient un service (journalctl, restart, dépendances). C'est la voie recommandée par l'écosystème Podman ; l'ancien podman generate systemd est déprécié (toujours utilisable, mais ce n'est plus la direction).

Un fichier .container est une unité systemd enrichie : systemd le lit, génère à la volée le service correspondant, et vous manipulez ensuite ce service avec les commandes habituelles. La section [Container] remplace les arguments de podman run, la section [Service] reste du systemd standard. L'image y est épinglée par digest @sha256:... : c'est le seul moyen de garantir qu'un redémarrage du service ne change pas l'image sous vos pieds. Pour monter de version, vous changez tag et digest ensemble, puis relancez le service.

[Container]
Image=docker.io/library/nginx:1.31.6-alpine@sha256:df221db836e1754089190208cee7eeda94f233197056426eda74a43ab1abeac2
PublishPort=8080:80
Volume=%h/nginx-html:/usr/share/nginx/html:ro,Z
[Service]
Restart=always
[Install]
WantedBy=default.target

Activation en rootless :

Fenêtre de terminal
mkdir -p ~/.config/containers/systemd ~/nginx-html
# placer nginx.container dans ce dossier
systemctl --user daemon-reload
systemctl --user start nginx
journalctl --user -u nginx -f

Il n'y a pas de systemctl --user enable : sur une unité générée par Quadlet, la commande échoue (Unit … is transient or generated). Le démarrage automatique est déjà déclaré par la section [Install] du fichier, WantedBy=default.target, que daemon-reload prend en compte. %h désigne votre répertoire personnel : en rootless, un chemin comme /data appartient à root et n'est pas accessible. Enfin, un service rootless s'arrête quand vous fermez votre session et ne démarre pas au boot, sauf si vous activez le maintien de session avec loginctl enable-linger. La leçon Quadlet et systemd couvre ce point et tout ce qu'un vrai service demande : dépendances entre unités, secrets, healthchecks, et les fichiers .pod et .volume.

Bonus, pods et intégration Kubernetes (sans cluster)

Section intitulée « Bonus, pods et intégration Kubernetes (sans cluster) »

Quand vous avez besoin d'un modèle mental « mini-Kubernetes » sans déployer de cluster, les pods Podman sont parfaits.

Le point à comprendre est la publication des ports. Elle se déclare une seule fois, sur le pod, jamais sur les conteneurs qui le rejoignent : ces derniers partagent la même pile réseau et se joignent entre eux par localhost. C'est exactement le comportement d'un Pod Kubernetes, et c'est ce qui explique pourquoi la chaîne de connexion de l'application pointe sur localhost:5432 alors que la base tourne dans un autre conteneur.

Le mot de passe est lu depuis une variable du shell plutôt qu'écrit dans la commande : sans cette précaution, il finit dans l'historique du shell. La valeur reste toutefois lisible dans la sortie de podman inspect, puisqu'elle devient une variable d'environnement du conteneur : pour un usage durable, préférez podman secret create et --secret.

L'image localhost/mon-app:1.0.0 représente votre application, construite au préalable avec podman build -t mon-app:1.0.0 . comme l'enseigne la leçon build. Podman range une image construite localement sous le préfixe localhost/, et lui donner une version explicite plutôt que latest vous dit toujours quel code tourne dans le pod.

Fenêtre de terminal
export PGPASS="$(openssl rand -base64 24)"
podman pod create --name webapp -p 8082:80
podman run -d --pod webapp --name db \
-e POSTGRES_PASSWORD="$PGPASS" \
docker.io/library/postgres:16.15-alpine@sha256:721873c34ceb9f8d8fc265984940dc982404c105f19ad51be9fdc5970a6080ea
podman run -d --pod webapp --name app \
-e DATABASE_URL="postgres://postgres:$PGPASS@localhost:5432" \
localhost/mon-app:1.0.0

podman kube play : exécuter un manifest sans cluster

Section intitulée « podman kube play : exécuter un manifest sans cluster »

La commande podman kube play lit un manifest Kubernetes (Pod, Deployment, ConfigMap, Secret) et crée les pods et conteneurs correspondants sur votre machine, sans cluster. L'inverse existe : podman kube generate exporte un pod que vous avez construit à la main en manifest réutilisable, ce qui fait de Podman un bon banc d'essai avant Kubernetes.

Fenêtre de terminal
# Lancer un manifest Kubernetes localement
podman kube play deployment.yaml
# Arrêter et supprimer
podman kube play deployment.yaml --down
# Exporter un pod existant vers un manifest Kubernetes
podman kube generate webapp > webapp.yaml

Les commandes historiques podman play kube et podman generate kube restent des alias, mais la forme moderne est podman kube play / podman kube generate. Toutes les ressources Kubernetes ne sont pas prises en charge : la leçon pods précise le rôle du conteneur d'infrastructure et les limites du modèle, et la leçon kube play liste ce que la commande accepte réellement d'un manifest.

Sur macOS et Windows, les conteneurs Linux nécessitent une VM, car ils dépendent du kernel Linux. Podman Machine la gère pour vous : podman machine init crée la VM, podman machine start la démarre, et la commande podman de votre poste parle ensuite à cette VM de façon transparente. podman machine ssh ouvre un shell dans la VM quand vous devez y diagnostiquer quelque chose.

Fenêtre de terminal
podman machine init
podman machine start
podman run -d -p 8080:80 \
docker.io/library/nginx:1.31.6-alpine@sha256:df221db836e1754089190208cee7eeda94f233197056426eda74a43ab1abeac2
podman machine ssh

Les prérequis propres à chaque système (WSL 2 ou Hyper-V sous Windows, installation par Homebrew sous macOS) sont détaillés pas à pas dans la leçon installation.

La formation suit l'ordre dans lequel on s'approprie l'outil : comprendre ses principes, exécuter des conteneurs, construire des images, les regrouper en pods, puis les industrialiser avec systemd. Chaque module s'appuie sur le précédent, et votre avancement leçon par leçon se suit sur la page Mon parcours.

Le premier module explique ce qui distingue Podman de Docker. Les concepts posent le rootless, l'absence de démon, les pods et l'architecture, l'installation vous rend opérationnel sur Linux, macOS ou Windows, et les commandes de base (run, ps, exec, logs, images, nettoyage) font le quotidien.

Le deuxième module va au-delà du simple lancement. Le run avancé détaille les namespaces, la sécurité et les options d'exécution, les volumes traitent la persistance et les permissions, et les réseaux couvrent le DNS, les ports, l'isolation et les architectures multi-tier.

Le troisième module produit les images. Le guide build enseigne le Containerfile, le multi-stage et l'optimisation, puis les manifests multi-arch publient une même image pour plusieurs architectures.

Le pod est natif chez Podman, comme dans Kubernetes. Les pods expliquent le conteneur d'infrastructure et la correspondance avec Kubernetes, et kube play déploie des manifests sans cluster, ce qui prépare le passage à l'orchestrateur.

Le dernier module transforme un conteneur en service. Quadlet apporte le démarrage automatique, le redémarrage et la journalisation de systemd. Il arrive en dernier parce qu'il suppose acquis le contenu des réseaux et des volumes : une unité systemd déclare les deux d'avance, sans possibilité de tâtonner en ligne de commande.

Podman évolue vite et chaque distribution embarque une version différente. La branche stable de référence pour ce guide est la 5.8 (dernière 5.x au 13 octobre 2026 : 5.8.9, publiée le 12 octobre 2026). La 6.0.0 est sortie le 24 juin 2026 ; la branche courante est la 6.1 (dernière version : 6.1.4, publiée le 12 octobre 2026). Elle arrive d'abord sur les distributions rolling et via Homebrew.

Ce tableau sert à répondre à une seule question avant de suivre un guide : la commande que vous lisez existe-t-elle dans votre version ? L'écart est considérable, plus de trois ans séparent la 4.3 de Debian 12 de la 6.1 d'Arch, et des pans entiers de la documentation amont ne s'appliquent pas aux versions 4.x, à commencer par Quadlet, absent avant la 4.4.

BaseVersion Podman
Arch Linux, Homebrew (macOS)6.1
Amont (dernières, 13 octobre 2026)5.8.9 (5.x) / 6.1.4
Fedora 43 (à jour)5.8
Debian 13, Ubuntu 25.105.4
Fedora 425.4
Ubuntu 24.04 LTS4.9
Debian 124.3

Pour un environnement critique, épinglez la version et testez les comportements par défaut, qui changent d'une majeure à l'autre (réseau, volumes, cgroups).

Sortie le 24 juin 2026, Podman 6 finalise plusieurs suppressions entamées en 5.x. Elle exige des composants compagnons alignés : Buildah 1.44, Skopeo 1.23, Netavark/Aardvark 2.0. Le dépôt a par ailleurs rejoint l'organisation CNCF podman-container-tools.

La CVE-2026-57231 est souvent citée comme argument de migration, à tort. Cette fuite de variables d'environnement de l'hôte vers le conteneur, déclenchée par une image contenant une variable sans valeur, touche toutes les versions de la 1.8.1 à la 5.8.3 incluse et pèse 7.5 sur l'échelle CVSS v3.1. Elle est corrigée à la fois dans la 5.8.4 et dans la 6.0.0 : rester sur la branche 5.x à jour suffit à s'en protéger, la montée en 6 se décide sur d'autres critères.

Ces suppressions ne sont pas des surprises : chacune concerne un composant déjà remplacé par défaut depuis Podman 4 ou 5, et déjà signalé comme déprécié. Le risque porte donc sur les machines qui ont été configurées explicitement pour l'ancien composant, typiquement un /etc/containers/containers.conf qui force network_backend = "cni". Vérifiez ce fichier avant toute montée de version, ainsi que vos scripts : la dernière ligne de la liste, sur le changement de logique des filtres, casse silencieusement un podman ps --filter qui en cumulait plusieurs.

  • CNI supprimé au profit de Netavark (le backend réseau par défaut depuis Podman 5).
  • slirp4netns supprimé au profit de Pasta pour le réseau rootless.
  • cgroups v1 et iptables supprimés (passez à cgroups v2 et nftables).
  • BoltDB supprimé : migration automatique vers SQLite au premier démarrage.
  • Intel Mac et Windows 10 ne sont plus supportés.
  • podman volume prune ne supprime plus que les volumes anonymes par défaut ; utilisez --all pour l'ancien comportement.
  • Quadlet range désormais chaque unité et ses fichiers dans un sous-répertoire au lieu du fichier .app.
  • Filtres multiples : ils se combinent maintenant en ET et non plus en OU, ce qui restreint les résultats d'un --filter cumulé.

Ces ajouts répondent tous à des frustrations connues de la 5.x. Les deux premiers rendent le nettoyage prévisible, ce qui manquait cruellement : jusqu'ici, podman volume prune supprimait sans prévisualisation possible. Le troisième donne enfin une vue directe des unités Quadlet, qu'il fallait auparavant reconstituer en listant les fichiers et les services systemd séparément.

  • podman volume prune --dry-run et --all pour un nettoyage maîtrisé.
  • podman quadlet ls (nouvel alias) avec une colonne Pod.
  • podman info expose les répertoires CDI et les périphériques découverts.
  • --gpus compatible AMD, adresses IP statiques multiples, routes blackhole/unreachable.
  • podman machine os update et gestion multi-provider des VM.

Podman ne construit pas d'images et ne parle pas aux registres tout seul : ces fonctions vivent dans des binaires distincts, qui partagent la même bibliothèque de stockage et les mêmes fichiers de configuration. Vous pouvez donc construire une image avec Buildah, la copier avec Skopeo et l'exécuter avec Podman sans jamais la pousser sur un registre intermédiaire.

Trois pages prolongent Podman sur ce point : Buildah (construire des images sans daemon, workflows avancés), Skopeo (copier et inspecter des images entre registries) et Conteneurisation (fondamentaux des conteneurs Linux et de l'écosystème OCI).

Avant de dérouler le parcours, validez le geste de base : ce lab vous fait lancer un conteneur en mode détaché avec Podman, contrôler son état et consulter ses logs sur une VM, sans rien installer sur votre poste.

Les questions rassemblées ici sont celles que pose une équipe qui vient de Docker : équivalences de commandes, sort de Compose, et comportement du mode rootless sur les ports privilégiés. Chaque réponse tient en quelques lignes et renvoie vers le guide détaillé quand le sujet le mérite.

Ce projet vous est utile ?

Je prends le temps de rédiger ces guides, de tester les commandes et de vérifier les labs pour que vous puissiez apprendre gratuitement. Si ce travail vous aide, offrez-moi un café. C'est une façon simple de contribuer à la suite du projet.

Offrir un café (nouvel onglet) Soutenir chaque mois (nouvel onglet) En savoir plus

Suivez aussi le projet sur LinkedIn