Skip to main content

Docker Volumes


Chapter objectives​

  • Understand data persistence in Docker
  • Master the different volume types
  • Manage volumes effectively
  • Share data between containers

1 - Why volumes?​

The ephemerality problem​

By default, a container's data is lost when it is deleted:

# CrΓ©er un fichier dans un conteneur
docker run -it --name test ubuntu bash
echo "Hello" > /data.txt
exit

# RedΓ©marrer le conteneur - fichier prΓ©sent
docker start -i test
cat /data.txt # Hello

# Supprimer le conteneur - fichier perdu !
docker rm test
docker run -it ubuntu cat /data.txt # Erreur !

The solutions​

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Options de stockage β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ β”‚
β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
β”‚ β”‚ Volumes β”‚ β”‚ Bind Mounts β”‚ β”‚ tmpfs β”‚ β”‚
β”‚ β”‚ (GΓ©rΓ© par β”‚ β”‚ (Dossier β”‚ β”‚ (MΓ©moire RAM) β”‚ β”‚
β”‚ β”‚ Docker) β”‚ β”‚ hΓ΄te) β”‚ β”‚ β”‚ β”‚
β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
β”‚ β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

2 - Storage types​

Comparison​

TypeLocationManagementUsage
Volume/var/lib/docker/volumes/DockerProduction, persistent data
Bind mountAnywhere on the hostUserDevelopment, configs
tmpfsRAM memoryDockerSensitive temporary data

Diagram​

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Conteneur β”‚
β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
β”‚ β”‚ /app/data β”‚ β”‚
β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β”‚
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ β”‚ β”‚
β–Ό β–Ό β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Volume β”‚ β”‚ Bind Mount β”‚ β”‚ tmpfs β”‚
β”‚ /var/lib/ β”‚ β”‚ /home/user/ β”‚ β”‚ (RAM) β”‚
β”‚ docker/vol/ β”‚ β”‚ project/data β”‚ β”‚ β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

3 - Docker Volumes​

Create a volume​

# CrΓ©er un volume
docker volume create mon-volume

# CrΓ©er avec options
docker volume create --driver local \
--opt type=none \
--opt device=/path/to/data \
--opt o=bind \
mon-volume

List the volumes​

# Lister tous les volumes
docker volume ls

# Filtrer
docker volume ls --filter "dangling=true"
docker volume ls --filter "driver=local"

# Format personnalisΓ©
docker volume ls --format "{{.Name}}: {{.Driver}}"

Inspect a volume​

# DΓ©tails d'un volume
docker volume inspect mon-volume

# Sortie JSON
{
"Name": "mon-volume",
"Driver": "local",
"Mountpoint": "/var/lib/docker/volumes/mon-volume/_data",
"Labels": {},
"Scope": "local"
}

Delete volumes​

# Supprimer un volume
docker volume rm mon-volume

# Supprimer plusieurs volumes
docker volume rm vol1 vol2 vol3

# Supprimer les volumes non utilisΓ©s
docker volume prune

# Forcer la suppression
docker volume prune -f

4 - Use volumes​

Syntax with -v​

# Volume nommΓ©
docker run -v mon-volume:/app/data nginx

# Volume anonyme
docker run -v /app/data nginx

# Mode lecture seule
docker run -v mon-volume:/app/data:ro nginx
# Volume nommΓ©
docker run --mount source=mon-volume,target=/app/data nginx

# Avec options
docker run --mount type=volume,source=mon-volume,target=/app/data,readonly nginx

# Volume anonyme
docker run --mount type=volume,target=/app/data nginx

Practical examples​

# Base de donnΓ©es PostgreSQL avec volume
docker run -d \
--name postgres \
-e POSTGRES_PASSWORD=secret \
--mount source=pg-data,target=/var/lib/postgresql/data \
postgres:15

# Les donnΓ©es survivent Γ  la suppression du conteneur
docker rm -f postgres
docker run -d \
--name postgres-new \
-e POSTGRES_PASSWORD=secret \
--mount source=pg-data,target=/var/lib/postgresql/data \
postgres:15
# Les donnΓ©es sont prΓ©servΓ©es !

5 - Bind Mounts​

Syntax​

# Avec -v
docker run -v /chemin/hote:/chemin/conteneur nginx
docker run -v $(pwd)/html:/usr/share/nginx/html nginx

# Avec --mount
docker run --mount type=bind,source=/chemin/hote,target=/chemin/conteneur nginx

# Lecture seule
docker run --mount type=bind,source=$(pwd)/config,target=/etc/nginx,readonly nginx

Use case: development​

# Monter le code source pour le hot-reload
docker run -d \
--name dev-app \
-p 3000:3000 \
-v $(pwd)/src:/app/src \
-v $(pwd)/package.json:/app/package.json \
node:18 npm run dev

# Les modifications du code sont reflΓ©tΓ©es immΓ©diatement

Differences with volumes​

AspectVolumeBind Mount
LocationManaged by DockerSpecified by the user
PortabilityExcellentDepends on the host path
PerformanceOptimizedVariable
BackupVia DockerManual
SecurityBetter isolationAccess to the host system

6 - tmpfs Mounts​

Usage​

tmpfs stores data in RAM memory:

# CrΓ©er un tmpfs mount
docker run --mount type=tmpfs,target=/app/temp nginx

# Avec options
docker run --mount type=tmpfs,target=/app/temp,tmpfs-size=100m,tmpfs-mode=1777 nginx

Use cases​

  • Sensitive data (secrets, tokens)
  • Temporary cache
  • Session files
  • Data that should not persist
# Stocker des secrets temporairement
docker run -d \
--name secure-app \
--mount type=tmpfs,target=/run/secrets \
mon-app

7 - Share data between containers​

Shared volumes​

# Conteneur 1 : Γ©crit des donnΓ©es
docker run -d \
--name writer \
--mount source=shared-data,target=/data \
alpine sh -c "while true; do date >> /data/log.txt; sleep 1; done"

# Conteneur 2 : lit les donnΓ©es
docker run -it \
--name reader \
--mount source=shared-data,target=/data,readonly \
alpine tail -f /data/log.txt

Volumes-from (legacy)​

# CrΓ©er un conteneur avec des volumes
docker run -d --name data-container -v /data alpine sleep infinity

# Utiliser les volumes d'un autre conteneur
docker run --volumes-from data-container alpine ls /data

8 - Backup and restore​

Back up a volume​

# MΓ©thode 1 : tar dans un conteneur temporaire
docker run --rm \
-v mon-volume:/source:ro \
-v $(pwd):/backup \
alpine tar cvf /backup/mon-volume-backup.tar -C /source .

# MΓ©thode 2 : docker cp (depuis un conteneur)
docker cp mon-conteneur:/app/data ./backup/

Restore a volume​

# CrΓ©er le volume
docker volume create mon-volume-restored

# Restaurer depuis le backup
docker run --rm \
-v mon-volume-restored:/target \
-v $(pwd):/backup \
alpine tar xvf /backup/mon-volume-backup.tar -C /target

Automated backup script​

#!/bin/bash
# backup-volumes.sh

BACKUP_DIR="/backups/docker"
DATE=$(date +%Y%m%d_%H%M%S)

for volume in $(docker volume ls -q); do
echo "Backing up $volume..."
docker run --rm \
-v $volume:/source:ro \
-v $BACKUP_DIR:/backup \
alpine tar cvf /backup/${volume}_${DATE}.tar -C /source .
done

# Nettoyer les backups de plus de 7 jours
find $BACKUP_DIR -name "*.tar" -mtime +7 -delete

9 - Volumes in a Dockerfile​

The VOLUME instruction​

FROM node:18

WORKDIR /app

# DΓ©clarer un volume
VOLUME /app/data
VOLUME ["/app/logs", "/app/uploads"]

COPY . .

CMD ["node", "server.js"]

Behavior​

# Un volume anonyme est créé automatiquement
docker run mon-app

# Lister les volumes anonymes
docker volume ls
# DRIVER VOLUME NAME
# local abc123def456...
Warning

VOLUME instructions in the Dockerfile create anonymous volumes that are hard to manage. Prefer named volumes at runtime.


10 - Best practices​

Naming​

# βœ… Bon : noms descriptifs
docker volume create postgres-data
docker volume create app-uploads
docker volume create nginx-logs

# ❌ Mauvais : noms génériques
docker volume create data
docker volume create vol1

Security​

# Lecture seule quand possible
docker run --mount source=config,target=/etc/app,readonly mon-app

# Utilisateur non-root
docker run -u 1000:1000 --mount source=data,target=/app/data mon-app

Performance​

# Utiliser des volumes pour les donnΓ©es frΓ©quemment accΓ©dΓ©es
# (meilleure performance que bind mounts sur macOS/Windows)

# Pour le dΓ©veloppement sur macOS
docker run -v mycode:/app:cached node:18 npm run dev

Regular cleanup​

# Identifier les volumes orphelins
docker volume ls -f dangling=true

# Nettoyer
docker volume prune

# VΓ©rifier l'espace utilisΓ©
docker system df -v | grep VOLUME -A 100

Summary​

CommandDescription
docker volume createCreate a volume
docker volume lsList the volumes
docker volume inspectVolume details
docker volume rmDelete a volume
docker volume pruneClean up unused volumes
-v or --mountMount a volume
TypeRecommended usage
VolumeProduction data
Bind mountDevelopment
tmpfsTemporary/sensitive data
Key points
  • Volumes persist after containers are deleted
  • Use --mount for a clear syntax
  • Name your volumes descriptively
  • Regularly back up your critical volumes

Hands-on exercises​

  1. Create a volume and use it with a MySQL container
  2. Mount a local folder for developing a Node.js app
  3. Share a volume between two containers
  4. Perform a backup and restore of a volume

← Dockerfile | Docker Networks β†’