Aller au contenu
Conteneurs & Orchestration medium

Maîtriser Podman : conteneurs rootless, systemd et pods

17 min de lecture

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.

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:alpine) 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.

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:alpine
# Vérifier qu'il tourne
curl http://localhost:8080
# Voir les logs
podman logs web
# Tester un volume (SELinux : :Z)
podman run -d --name web2 -v ~/html:/usr/share/nginx/html:Z -p 8081:80 docker.io/library/nginx:alpine
# Nettoyer
podman rm -f web web2

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

Comparaison architecture Docker vs Podman

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 : un fichier créé dans le conteneur par l'UID 0 apparaît sur l'hôte avec l'UID de base de votre plage subuid, souvent 100000, donc illisible par votre propre 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é

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.

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
podman run -d --network app-network --name db docker.io/library/postgres:16-alpine
podman run --rm --network app-network docker.io/library/alpine ping -c 1 db

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. Sur une machine que vous exploitez réellement, remplacez le tag alpine par un digest @sha256:... : c'est le seul moyen de garantir qu'un redémarrage du service ne change pas l'image sous vos pieds.

[Container]
Image=docker.io/library/nginx:alpine
PublishPort=8080:80
Volume=/data/nginx:/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
# placer nginx.container dans ce dossier
systemctl --user daemon-reload
systemctl --user start nginx
systemctl --user enable nginx
journalctl --user -u nginx -f

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 et dans la sortie de podman inspect. Pour un usage durable, préférez podman secret create et --secret.

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

podman kube play : exécuter un manifest sans cluster

Section intitulée « podman kube play : exécuter un manifest sans cluster »
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.

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.

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

Choisissez votre point d'entrée, puis avancez module par module. Les quatre premières lignes forment le socle et se lisent dans l'ordre ; les suivantes sont indépendantes et se prennent au besoin. Une seule contrainte d'enchaînement compte : Quadlet suppose acquis le contenu de Réseaux et de Volumes, puisqu'une unité systemd déclare les deux sans possibilité de tâtonner en ligne de commande.

ModuleObjectif
Installationêtre opérationnel (Linux/macOS/Windows)
Conceptsrootless, daemonless, pods, architecture
Commandes de baserun, ps, exec, logs, images, nettoyage
Run avancérootless, namespaces, sécurité, options
Volumespersistance et permissions
RéseauxDNS, ports, isolation, multi-tier
BuildContainerfile, multi-stage, optimisation
Podspods, infra container, mapping Kubernetes
kube playdéployer des manifests sans cluster
Quadletconteneurs comme services systemd
Manifests multi-archimages multi-architecture

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 : 5.8.5, publiée le 8 juillet 2026). La 6.0.0 est sortie le 24 juin 2026, suivie de la 6.0.2 le 22 juillet ; 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.0 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.0
Amont (dernières)5.8.5 (5.x) / 6.0.2
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.

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.

  • Cgroups : Les limites de CPU, de mémoire et d'entrées/sorties que Podman applique à chaque conteneur.
  • Namespaces : Les espaces de noms utilisateur dont dépend directement le mode rootless.
  • Capabilities : Les privilèges unitaires qu'un conteneur conserve ou perd, la base de --cap-drop.

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 site vous est utile ?

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

Je maintiens +700 guides gratuits, sans pub ni tracking. Un soutien, même symbolique, m'aide à couvrir l'hébergement et à garder ces ressources gratuites. Merci pour votre appui.

Le formulaire ne s'affiche pas ? Ouvrir Ko-fi dans un onglet.

Abonnez-vous et suivez mon actualité DevSecOps sur LinkedIn