Aller au contenu
Conteneurs & Orchestration medium

Concepts fondamentaux de Podman

17 min de lecture

logo podman

Podman est un moteur de conteneurs sans daemon central qui exécute les conteneurs en mode rootless par défaut. Ce guide vous explique les concepts fondamentaux qui différencient Podman de Docker et comment ils améliorent la sécurité.

ConceptCe que ça signifie
DaemonlessPas de daemon central requis — chaque conteneur est un processus indépendant supervisé par conmon
RootlessLes conteneurs tournent sans privilèges root grâce aux user namespaces (/etc/subuid, /etc/subgid)
Pods natifsGroupe de conteneurs partageant le même réseau via un infra container (concept Kubernetes)
CompatibilitéCLI compatible Docker, images OCI, registries standard — avec quelques différences sur Compose et le réseau

Docker utilise une architecture client-serveur : le CLI docker communique avec un daemon (dockerd) qui gère les conteneurs.

Architecture Docker avec daemon centralisé

Ce modèle a des implications :

AspectConséquence
Daemon permanentUn processus tourne en permanence, même sans conteneurs actifs
Accès au socketL’accès au socket Docker (groupe docker) équivaut à des privilèges root sur la machine — documenté par Docker
Point unique de défaillanceSi dockerd crash, tous les conteneurs sont affectés

Podman n’a pas de daemon central requis pour exécuter des conteneurs. Chaque commande podman run lance directement le runtime (crun/runc) :

Architecture Podman daemonless avec conmon

Vérifiez qu’aucun daemon Podman ne tourne par défaut :

Fenêtre de terminal
pgrep -a podman
# Aucun résultat = pas de daemon permanent

Chaque conteneur est supervisé par conmon (container monitor), un processus minimal qui :

  • Maintient le TTY et les flux stdin/stdout/stderr
  • Capture le code de sortie du conteneur
  • Permet de détacher/rattacher (podman attach)
Fenêtre de terminal
podman run -d --name demo docker.io/library/alpine:3.21 sleep 300
ps aux | grep conmon | grep -v grep
bob 3857458 /usr/bin/conmon --api-version 1 -c d070dd3e... -n demo ...

“Daemonless” ne signifie pas “aucun service possible”. Pour les outils nécessitant l’API Docker, Podman peut exposer un socket compatible :

Fenêtre de terminal
# Activer le service API (rootless, à la demande)
systemctl --user enable --now podman.socket
# Vérifier le socket
ls -la /run/user/$(id -u)/podman/podman.sock

Ce service s’active à la demande (socket activation) et ne tourne pas en permanence. Documentation : podman-system-service

AspectDocker (daemon)Podman (daemonless)
Process permanentdockerd toujours actifAucun (ou socket à la demande)
Crash du daemonConteneurs affectésAucun impact
Mise à jour CLIRedémarrer dockerdTransparent
Multi-utilisateursDaemon global partagéStores séparés par utilisateur
Ressources au reposDaemon en mémoireRien

En mode rootless, Podman exécute les conteneurs sans aucun privilège root. Le processus du conteneur appartient à votre utilisateur :

Fenêtre de terminal
podman run -d --name test docker.io/library/alpine:3.20 sleep 100
ps aux | grep "sleep 100" | grep -v grep
bob 3857490 sleep 100

Le processus appartient à bob, pas à root.

Comment le conteneur peut-il être “root” à l’intérieur tout en étant un utilisateur normal à l’extérieur ? Grâce aux user namespaces.

Podman mappe l’UID 0 (root) du conteneur vers un UID non privilégié sur l’hôte. Cette configuration est définie dans /etc/subuid et /etc/subgid :

Fenêtre de terminal
grep $USER /etc/subuid /etc/subgid
/etc/subuid:bob:100000:65536
/etc/subgid:bob:100000:65536

Cela signifie :

  • L’utilisateur bob peut utiliser les UIDs 100000 à 165535 (65536 UIDs)
  • L’UID 0 dans le conteneur = UID 100000 sur l’hôte
  • L’UID 1000 dans le conteneur = UID 101000 sur l’hôte
Mapping des UIDs entre conteneur et hôte via user namespaces

Documentation : rootless tutorial

Podman propose plusieurs modes de mapping qui influencent les permissions sur les volumes :

ModeComportementCas d’usage
Par défautUID 0 conteneur → UID 100000+ hôteIsolation maximale
--userns=keep-idVotre UID réel = même UID dans le conteneurVolumes partagés avec l’hôte
--userns=autoAllocation automatique d’UIDs uniquesMulti-conteneurs isolés

L’option --userns=keep-id est particulièrement utile pour éviter les problèmes de permissions sur les volumes montés depuis l’hôte.

En savoir plus : modes user namespace

En mode rootless, les images et conteneurs sont stockés dans votre home :

Fenêtre de terminal
podman info --format "{{.Store.GraphRoot}}"
/home/bob/.local/share/containers/storage

Structure du répertoire :

ÉlémentContenu
overlay/Layers des images (système de fichiers)
overlay-images/Métadonnées des images
overlay-containers/Données des conteneurs
volumes/Volumes nommés
db.sql ou bolt_state.dbBase de données (SQLite ou BoltDB selon version)
LimitationCauseSolution
Ports < 1024Réservés à rootsysctl net.ipv4.ip_unprivileged_port_start=80
PingNécessite capabilitysysctl net.ipv4.ping_group_range="0 65536"
OverlayfsKernel < 5.11fuse-overlayfs (automatique)
Performances réseauStack userspaceUtiliser rootful si critique

Certains cas nécessitent sudo podman :

  • Ports privilégiés (80, 443) sans sysctl
  • Montage de certains systèmes de fichiers
  • Accès direct aux périphériques (/dev/…)
  • Performances réseau maximales

Le réseau est la principale source de problèmes en mode rootless. Comprendre les différences évite beaucoup de frustration.

En rootful, Podman utilise netavark (ou CNI) pour créer des ponts réseau et configurer iptables. En rootless, ces opérations nécessitent des privilèges — Podman utilise donc une stack réseau userspace.

StackModeCaractéristiques
pastaRootless (défaut Podman 5+)Performant, remplace slirp4netns
slirp4netnsRootless (legacy)Plus lent, compatible ancien
netavarkRootfulPerformances natives, iptables
SymptômeCauseSolution
Pas de connectivité DNSRésolveur mal configuréVérifier /etc/resolv.conf dans le conteneur
Port non accessible depuis l’hôteMapping port incorrectUtiliser -p 8080:80 explicitement
Lenteur réseauslirp4netnsMettre à jour vers Podman 5+ (pasta)

Pour une configuration avancée, voir le guide Réseau Podman.

Discussion : architecture réseau rootless

Un Pod est un groupe de conteneurs qui partagent les mêmes namespaces (réseau, IPC). Ce concept vient de Kubernetes où il représente l’unité de déploiement de base.

Podman implémente nativement les pods — une fonctionnalité absente de Docker.

Quand vous créez un pod, Podman lance automatiquement un conteneur spécial appelé infra (ou pause). Son rôle : maintenir les namespaces actifs même si tous les autres conteneurs s’arrêtent.

Documentation : podman-pod-create

Fenêtre de terminal
podman pod create --name mon-pod
podman pod ps
POD ID NAME STATUS CREATED INFRA ID # OF CONTAINERS
363aa4fe9e83 mon-pod Created 1 second ago 1ed785cc2461 1

Le conteneur infra a un seul rôle : maintenir les namespaces actifs même si tous les autres conteneurs s’arrêtent.

Ajoutez des conteneurs au pod :

Fenêtre de terminal
podman run -d --pod mon-pod --name nginx docker.io/library/nginx:alpine
podman run -d --pod mon-pod --name sidecar docker.io/library/alpine:3.20 sleep 600

Listez les conteneurs du pod :

Fenêtre de terminal
podman ps --filter "pod=mon-pod" --format "table {{.Names}}\t{{.Image}}"
NAMES IMAGE
363aa4fe9e83-infra localhost/podman-pause:4.9.3-0
nginx docker.io/library/nginx:alpine
sidecar docker.io/library/alpine:3.20

Les conteneurs partagent le même namespace réseau. Le sidecar peut accéder à nginx via localhost :

Fenêtre de terminal
podman exec sidecar wget -qO- localhost:80 | head -3
<!DOCTYPE html>
<html>
<head>

Les deux conteneurs utilisent exactement le même namespace réseau :

Fenêtre de terminal
podman inspect nginx --format '{{.NetworkSettings.SandboxKey}}'
podman inspect sidecar --format '{{.NetworkSettings.SandboxKey}}'
/run/user/1000/netns/netns-a54048f2-209e-ec00-2125-8c76d38cd7e2
/run/user/1000/netns/netns-a54048f2-209e-ec00-2125-8c76d38cd7e2

Même chemin = même namespace réseau.

PatternDescriptionExemple
SidecarConteneur auxiliaire qui complète l’app principaleCollecteur de logs, proxy
AmbassadorProxy vers des services externesEnvoy, connexion DB
AdapterTransforme les sorties de l’appConvertisseur de métriques
Init containerPrépare l’environnement avant l’appMigration DB, téléchargement config

La commande podman generate systemd est dépréciée. Red Hat recommande désormais Quadlet pour intégrer les conteneurs avec systemd.

Documentation : podman-generate-systemd (déprécié)

Quadlet permet de définir des conteneurs comme des unités systemd via des fichiers .container :

~/.config/containers/systemd/webapp.container
[Container]
Image=docker.io/library/nginx:alpine
PublishPort=8080:80
[Service]
Restart=always
[Install]
WantedBy=default.target
Fenêtre de terminal
# Recharger systemd et démarrer
systemctl --user daemon-reload
systemctl --user start webapp

Le conteneur démarre au boot, redémarre en cas d’échec, et s’intègre parfaitement avec journalctl.

Voir le guide Quadlet pour une configuration complète.

Podman est conçu comme un drop-in replacement de Docker. La plupart des commandes fonctionnent à l’identique :

Fenêtre de terminal
# Ces commandes fonctionnent avec podman ET docker
podman pull nginx
podman run -d -p 8080:80 nginx
podman ps
podman logs <container>
podman stop <container>

Vous pouvez même créer un alias :

Fenêtre de terminal
alias docker=podman
docker --version
podman version 4.9.3

Podman utilise Buildah en interne et comprend les Dockerfiles standard :

FROM alpine:3.21
RUN apk add --no-cache curl
CMD ["curl", "--version"]
Fenêtre de terminal
podman build -t mon-image .

Podman fonctionne avec tous les registries OCI :

  • Docker Hub (docker.io)
  • Quay.io (quay.io)
  • GitHub Container Registry (ghcr.io)
  • Registries privés

Pour les outils qui nécessitent l’API Docker, Podman peut exposer un socket compatible :

Fenêtre de terminal
# Activer le service API (rootless)
systemctl --user enable --now podman.socket
# Vérifier le socket
ls -la /run/user/$(id -u)/podman/podman.sock

Cela permet d’utiliser des outils comme docker-compose avec Podman.

  1. Daemonless : pas de daemon central requis, mais un service API optionnel (podman.socket) existe pour la compatibilité

  2. Rootless par défaut : user namespaces + subuid/subgid — option --userns=keep-id pour les volumes partagés

  3. Réseau rootless : stack userspace (pasta/slirp4netns) — comportement différent du rootful

  4. Pods natifs : infra container maintient les namespaces — pattern sidecar/ambassador possible

  5. Compatibilité Docker : migration souvent simple, mais différences sur Compose et réseau rootless

  6. Quadlet : intégration systemd recommandée (remplace generate systemd)

Podman fait partie d’un écosystème cohérent :

Écosystème containers/ : Podman, Buildah, Skopeo partageant containers/image et containers/storage
OutilUtilitéCommande exemple
PodmanRun, create, exec, logs…podman run nginx
BuildahBuild sans daemonbuildah build -t app .
SkopeoCopier entre registriesskopeo copy docker://a oci://b
CRI-ORuntime pour KubernetesUtilisé par OpenShift, K3s
AspectDockerPodman
ArchitectureClient-daemonDaemonless (+ socket optionnel)
Sécurité par défautDaemon root (rootless disponible)Rootless par défaut
Pods natifsNonOui (infra container)
Intégration systemddocker-composeQuadlet natif
Socket/APIToujours actifÀ la demande (socket activation)
CLIdockerpodman (compatible)
ImagesOCIOCI (compatible)

Oui, Docker propose un mode rootless depuis la version 20.10. Cependant, ce mode n’est pas activé par défaut et nécessite une installation séparée. L’architecture daemon reste, avec un daemon et un socket utilisateur.

Pourquoi podman.socket existe si Podman est daemonless ?

Section intitulée « Pourquoi podman.socket existe si Podman est daemonless ? »

“Daemonless” signifie qu’aucun daemon n’est requis pour exécuter des conteneurs via la CLI. Le socket podman.socket est un service optionnel qui expose l’API Docker pour les outils tiers (docker-compose, Portainer, etc.). Il s’active à la demande (socket activation) et ne tourne pas en permanence.

Pourquoi mes volumes ont des “permission denied” ?

Section intitulée « Pourquoi mes volumes ont des “permission denied” ? »

En rootless, l’UID 0 du conteneur correspond à un UID non privilégié sur l’hôte (100000+). Vos fichiers appartiennent à votre UID réel (ex: 1000), pas à 100000. Solutions :

  • --userns=keep-id : aligne votre UID réel avec l’UID du conteneur
  • Suffixe :U sur le volume : Podman ajuste les permissions (avec précaution)

L’infra container (ou pause container) maintient les namespaces actifs même si tous les autres conteneurs du pod s’arrêtent. Sans lui, le namespace réseau serait détruit dès l’arrêt du premier conteneur. C’est le même principe que dans Kubernetes.

Ce sont deux stacks réseau userspace pour le mode rootless :

  • slirp4netns : legacy, plus lent, compatibilité large
  • pasta : défaut depuis Podman 5, plus performant, remplace slirp4netns

Vérifiez avec podman info --format '{{.Host.NetworkBackend}}'.

Non. La compatibilité est élevée sur les usages CLI courants, mais des différences existent :

  • Compose : utilisez podman-compose ou le mode intégré
  • Réseau rootless : comportement différent (pas d’iptables)
  • Certaines options docker build non supportées
  • API : compatible via socket, mais pas identique à 100%

Pourquoi Quadlet plutôt que podman generate systemd ?

Section intitulée « Pourquoi Quadlet plutôt que podman generate systemd ? »

podman generate systemd créait des fichiers statiques qui devenaient obsolètes. Quadlet utilise des fichiers .container déclaratifs que systemd interprète dynamiquement. C’est plus maintenable et recommandé par Red Hat.

Comment savoir si je suis en rootless ou rootful ?

Section intitulée « Comment savoir si je suis en rootless ou rootful ? »
Fenêtre de terminal
podman info --format '{{.Host.Security.Rootless}}'
# true = rootless, false = rootful
# Vérifier aussi le chemin de stockage
podman info --format '{{.Store.GraphRoot}}'
# ~/.local/share/containers/storage = rootless
# /var/lib/containers/storage = rootful

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.