Aller au contenu
Conteneurs & Orchestration medium

Volumes Podman : persistance et partage de données

14 min de lecture

logo podman

Les conteneurs sont éphémères : supprimer un conteneur supprime ses données internes. Le stockage se gère donc avec 3 mécanismes : volume nommé, bind mount, tmpfs. Ce cours vous apprend à les utiliser dans des contextes réels — dev, prod, temporaire — et à résoudre les problèmes de permissions qui bloquent 80% des débutants.

Avant de foncer sur les commandes, posez-vous la question : quel est mon contexte ?

ContexteType recommandéPourquoi
Dev : je modifie du code sur l’hôte, je veux voir le résultat immédiatementBind mountLien direct hôte ↔ conteneur
Prod : je veux persister des données (DB, uploads, logs)Volume nomméGéré par Podman, portable, sauvegardable
Temporaire : cache, sessions, fichiers de buildtmpfsRapide (RAM), disparaît à l’arrêt

Monter un répertoire de votre machine dans le conteneur. Vous éditez les fichiers sur l’hôte, le conteneur les voit instantanément.

  1. Créez un répertoire de travail

    Fenêtre de terminal
    mkdir -p ~/dev-projet
    echo "<h1>Hello depuis l'hôte</h1>" > ~/dev-projet/index.html
  2. Lancez nginx avec un bind mount

    Fenêtre de terminal
    podman run -d --name dev-nginx -p 8080:80 \
    -v ~/dev-projet:/usr/share/nginx/html:Z \
    docker.io/library/nginx:alpine
  3. Vérifiez dans le navigateur

    Ouvrez http://localhost:8080 — vous voyez “Hello depuis l’hôte”.

  4. Modifiez le fichier sur l’hôte

    Fenêtre de terminal
    echo "<h1>Modification en direct !</h1>" > ~/dev-projet/index.html
  5. Rafraîchissez le navigateur

    Le changement est visible immédiatement — pas de rebuild, pas de redémarrage.

Le conteneur peut aussi écrire sur l’hôte :

Fenêtre de terminal
podman exec dev-nginx sh -c "echo 'Log du conteneur' > /usr/share/nginx/html/log.txt"
cat ~/dev-projet/log.txt
Résultat attendu
Log du conteneur
Fenêtre de terminal
podman rm -f dev-nginx

Recette 2 — Production : volume nommé + base de données

Section intitulée « Recette 2 — Production : volume nommé + base de données »

Persister les données d’une base PostgreSQL indépendamment du conteneur. Supprimer et recréer le conteneur ne perd pas les données.

  1. Créez le volume

    Fenêtre de terminal
    podman volume create postgres-data
  2. Lancez PostgreSQL avec ce volume

    Fenêtre de terminal
    podman run -d --name postgres-prod \
    -e POSTGRES_PASSWORD=secret \
    -v postgres-data:/var/lib/postgresql/data \
    docker.io/library/postgres:16-alpine
  3. Créez une table de test

    Fenêtre de terminal
    sleep 5 # Attendre le démarrage
    podman exec -it postgres-prod psql -U postgres -c \
    "CREATE TABLE test (id serial, message text); INSERT INTO test (message) VALUES ('Données persistantes');"
  4. Supprimez le conteneur

    Fenêtre de terminal
    podman rm -f postgres-prod
  5. Recréez un conteneur avec le même volume

    Fenêtre de terminal
    podman run -d --name postgres-prod \
    -e POSTGRES_PASSWORD=secret \
    -v postgres-data:/var/lib/postgresql/data \
    docker.io/library/postgres:16-alpine
  6. Vérifiez que les données sont toujours là

    Fenêtre de terminal
    sleep 3
    podman exec -it postgres-prod psql -U postgres -c "SELECT * FROM test;"
    Résultat attendu
    id | message
    ----+---------------------
    1 | Données persistantes

Ne mémorisez pas un chemin fixe — demandez-le à Podman :

Fenêtre de terminal
podman volume inspect postgres-data --format '{{.Mountpoint}}'

Le chemin dépend du mode (rootless vs rootful) et de la configuration storage.

Fenêtre de terminal
podman rm -f postgres-prod
# Le volume existe toujours — supprimez-le seulement si vous voulez perdre les données :
# podman volume rm postgres-data

Stocker des données temporaires en RAM. Rapide, volatile, parfait pour les caches ou les sessions.

Fenêtre de terminal
podman run --rm --mount type=tmpfs,destination=/cache,tmpfs-size=64M \
docker.io/library/alpine:3.20 sh -c "
echo 'Données temporaires' > /cache/session.txt
df -h /cache
cat /cache/session.txt
"
Résultat
Filesystem Size Used Available Use% Mounted on
tmpfs 64.0M 0 64.0M 0% /cache
Données temporaires

Quand le conteneur s’arrête, tout disparaît.

Cas d’usage typique : conteneur read-only avec tmpfs

Section intitulée « Cas d’usage typique : conteneur read-only avec tmpfs »

Pour durcir un conteneur, montez le système de fichiers en lecture seule mais autorisez /tmp en tmpfs :

Fenêtre de terminal
podman run --rm --read-only \
--mount type=tmpfs,destination=/tmp \
docker.io/library/alpine:3.20 sh -c "echo test > /tmp/ok.txt && cat /tmp/ok.txt"

Deux conteneurs accèdent au même volume — un écrivain, un lecteur.

  1. Créez le volume partagé

    Fenêtre de terminal
    podman volume create shared-logs
  2. Lancez le conteneur écrivain

    Fenêtre de terminal
    podman run -d --name writer -v shared-logs:/logs docker.io/library/alpine:3.20 \
    sh -c "while true; do date >> /logs/events.log; sleep 2; done"
  3. Lisez depuis un autre conteneur

    Fenêtre de terminal
    sleep 5
    podman run --rm -v shared-logs:/logs:ro docker.io/library/alpine:3.20 \
    tail -5 /logs/events.log
    Résultat
    Thu Feb 13 10:15:02 UTC 2026
    Thu Feb 13 10:15:04 UTC 2026
    Thu Feb 13 10:15:06 UTC 2026
Fenêtre de terminal
podman rm -f writer
podman volume rm shared-logs

En Podman, 80% des problèmes de volumes viennent de deux sources : permissions rootless et SELinux. Voici comment les résoudre.

Problème 1 : “Permission denied” sur un bind mount

Section intitulée « Problème 1 : “Permission denied” sur un bind mount »

Symptôme :

/bin/sh: can't create /app/file.txt: Permission denied

Causes possibles :

CauseSolution
SELinux bloque l’accèsAjoutez :Z ou :z au montage
UID mismatch rootlessUtilisez --userns=keep-id + :U
Permissions UNIX du dossierchmod 777 ~/mon-dossier (test) ou ajustez les ACL

Diagnostic rapide :

Fenêtre de terminal
# Vérifiez si SELinux est actif
getenforce
# Vérifiez les permissions du dossier
ls -laZ ~/mon-dossier

Solution SELinux :

Fenêtre de terminal
# :Z = privé (un seul conteneur)
podman run -v ~/mon-dossier:/app:Z ...
# :z = partagé (plusieurs conteneurs)
podman run -v ~/mon-dossier:/app:z ...

Symptôme : les fichiers créés par le conteneur appartiennent à root sur l’hôte, vous ne pouvez pas les modifier.

Cause : en rootless, l’UID dans le conteneur est mappé différemment.

Solution : --userns=keep-id conserve votre UID, et :U ajuste le volume.

Fenêtre de terminal
podman run --rm --userns=keep-id -v ~/mon-dossier:/app:U \
docker.io/library/alpine:3.20 touch /app/mon-fichier.txt
ls -la ~/mon-dossier/mon-fichier.txt
Résultat
-rw-r--r-- 1 bob bob 0 Feb 13 10:30 mon-fichier.txt

Le fichier vous appartient.

Problème 3 : “volume in use” lors de la suppression

Section intitulée « Problème 3 : “volume in use” lors de la suppression »

Symptôme :

Error: volume "mon-volume" is being used by the following container(s): abc123

Solution : supprimez d’abord le conteneur (même arrêté) :

Fenêtre de terminal
podman rm abc123
podman volume rm mon-volume

Problème 4 : données perdues après podman machine reset

Section intitulée « Problème 4 : données perdues après podman machine reset »

Symptôme (macOS/Windows) : après un podman machine rm, tous les volumes ont disparu.

Cause : les volumes sont stockés dans la VM. Supprimer la VM = supprimer les volumes.

Solution : sauvegardez vos volumes avant de toucher à la machine :

Fenêtre de terminal
# Backup
podman run --rm -v mon-volume:/source:ro -v ~/backups:/backup \
alpine tar cvf /backup/mon-volume.tar -C /source .
Fenêtre de terminal
podman run --rm \
-v postgres-data:/source:ro \
-v ~/backups:/backup \
docker.io/library/alpine:3.20 \
tar cvf /backup/postgres-data-$(date +%Y%m%d).tar -C /source .
Fenêtre de terminal
podman volume create postgres-data-restored
podman run --rm \
-v postgres-data-restored:/dest \
-v ~/backups:/backup \
docker.io/library/alpine:3.20 \
tar xvf /backup/postgres-data-20260213.tar -C /dest

Toujours vérifier avant de remettre en prod :

Fenêtre de terminal
podman run --rm -v postgres-data-restored:/data docker.io/library/alpine:3.20 \
ls -la /data
Fenêtre de terminal
podman volume create --label env=dev --label app=web dev-web-data
podman volume create --label env=prod --label app=db prod-db-data
# Filtrer
podman volume ls --filter label=env=prod
Fenêtre de terminal
# Voir les volumes non utilisés
podman volume ls -f dangling=true
# Supprimer (avec confirmation)
podman volume prune

Mettez en pratique ce que vous avez appris :

  1. Créez un volume pour une app

    Fenêtre de terminal
    podman volume create --label app=exercice exercice-data
  2. Lancez un conteneur qui écrit dedans

    Fenêtre de terminal
    podman run --rm -v exercice-data:/data docker.io/library/alpine:3.20 \
    sh -c "echo 'Test exercice' > /data/test.txt"
  3. Sauvegardez le volume

    Fenêtre de terminal
    mkdir -p ~/backups
    podman run --rm -v exercice-data:/source:ro -v ~/backups:/backup \
    docker.io/library/alpine:3.20 tar cvf /backup/exercice.tar -C /source .
  4. Supprimez le volume

    Fenêtre de terminal
    podman volume rm exercice-data
  5. Restaurez et vérifiez

    Fenêtre de terminal
    podman volume create exercice-data-restored
    podman run --rm -v exercice-data-restored:/dest -v ~/backups:/backup \
    docker.io/library/alpine:3.20 tar xvf /backup/exercice.tar -C /dest
    podman run --rm -v exercice-data-restored:/data docker.io/library/alpine:3.20 \
    cat /data/test.txt

    Vous devez voir : Test exercice

Types de stockage

  • Bind mount : dev, hot-reload, accès direct aux fichiers hôte
  • Volume nommé : prod, persistance, portable
  • tmpfs : cache, sessions, données volatiles

Résoudre les permissions

  • SELinux : ajoutez :Z (privé) ou :z (partagé)
  • Rootless : utilisez --userns=keep-id + :U
  • Fichiers root:root : combinez keep-id et :U
OptionDescriptionExemple
-v nom:/cheminVolume nommé-v app-data:/var/lib/app
-v /hôte:/cheminBind mount-v ~/code:/app
:roLecture seule-v config:/etc/app:ro
:ZSELinux privé-v ~/data:/data:Z
:zSELinux partagé-v ~/shared:/shared:z
:UAjuster UID (rootless)-v vol:/data:U
--mount type=tmpfsRAM temporaire--mount type=tmpfs,dst=/cache

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.