Containerele Docker sunt prin natura lor efemere - când un container este șters, toate datele scrise în sistemul său de fișiere dispar odată cu el. Docker Volumes rezolvă această problemă oferind un mecanism de stocare persistentă, complet decuplat de ciclul de viață al containerului.
Volumele sunt mecanismul recomandat de Docker pentru persistența datelor - preferate altor metode datorită portabilității, performanței și integrării native cu Docker Engine.
Docker oferă trei metode distincte prin care un container poate accesa date din afara sistemului său de fișiere intern:
Stocate în directorul gestionat de Docker (implicit /var/lib/docker/volumes/), volumele denumite sunt complet gestionate de Docker Engine. Sunt opțiunea recomandată pentru persistența datelor de producție.
/var/lib/docker/volumes/
└── nume_volum/
└── _data/ ← datele efective
Mapează un director sau fișier de pe host direct în container. Calea trebuie să existe pe sistemul gazdă și trebuie specificată cu calea absolută. Utile în development, când vrei ca modificările locale să fie reflectate imediat în container.
Stocate exclusiv în memoria RAM a gazdei, fără a scrie nimic pe disk. Datele dispar la oprirea containerului. Utile pentru informații sensibile (tokeni, parole temporare) sau date de caching cu latență minimă.
| Caracteristică | Named Volume | Bind Mount | tmpfs |
|---|---|---|---|
| Stocare | Docker managed | Filesystem gazdă | Memorie RAM |
| Persistență | ✓ Da | ✓ Da (pe host) | ✗ Nu |
| Portabilitate | ✓ Ridicată | ✗ Depinde de cale | - |
| Performanță Linux | ✓ Optimă | ✓ Bună | ✓ Maximă |
| Partajare containere | ✓ Facilă | ✓ Posibilă | ✗ Nu |
| Recomandat pentru | Date producție, DB | Development, config | Secrete, cache |
# Creare simplă docker volume create date_aplicatie # Creare cu opțiuni (driver explicit, labels) docker volume create \ --driver local \ --label env=productie \ --label app=myapp \ date_aplicatie
# Listare toate volumele docker volume ls # Filtrare după driver docker volume ls --filter driver=local # Filtrare după label docker volume ls --filter label=env=productie # Inspecție detaliată (JSON) docker volume inspect date_aplicatie
Exemplu output docker volume inspect:
[
{
"CreatedAt": "2024-11-15T10:23:45Z",
"Driver": "local",
"Labels": {
"env": "productie",
"app": "myapp"
},
"Mountpoint": "/var/lib/docker/volumes/date_aplicatie/_data",
"Name": "date_aplicatie",
"Options": {},
"Scope": "local"
}
]
# Ștergere volum specific (trebuie să nu fie folosit) docker volume rm date_aplicatie # Ștergere toate volumele nefolosite (dangling) docker volume prune # Ștergere cu confirmare automată (atenție în producție!) docker volume prune --force
⚠️ Atenție:docker volume pruneșterge definitiv toate volumele care nu sunt atașate la niciun container (inclusiv oprite). Nu există undo.
Opțiunea --mount este explicită și mai ușor de citit - recomandată în scripturi și documentație:
# Named volume docker run -d \ --mount type=volume,source=date_postgres,target=/var/lib/postgresql/data \ postgres:16 # Bind mount docker run -d \ --mount type=bind,source=/home/user/config,target=/etc/myapp,readonly \ myapp:latest # tmpfs mount docker run -d \ --mount type=tmpfs,target=/tmp/cache,tmpfs-size=256m \ myapp:latest
Sintaxa prescurtată cu -v este mai concisă, dar mai ambiguă (Docker determină tipul automat):
# Named volume: -v nume_volum:cale_container docker run -d -v date_postgres:/var/lib/postgresql/data postgres:16 # Bind mount: -v /cale/absoluta/host:cale_container docker run -d -v /home/user/app:/var/www/html nginx:alpine # Read-only: adaugă :ro la final docker run -d -v /home/user/config:/etc/myapp:ro myapp:latest # tmpfs: --tmpfs cale_container:optiuni docker run -d --tmpfs /tmp:size=256m,mode=1777 myapp:latest
Același volum poate fi montat simultan în mai multe containere - util pentru partajarea datelor între servicii:
# Containerul principal scrie date docker run -d \ --name producator \ --mount type=volume,source=date_partajate,target=/date/out \ app-producator:latest # Containerul secundar citește aceleași date docker run -d \ --name consumator \ --mount type=volume,source=date_partajate,target=/date/in,readonly \ app-consumator:latest
⚠️ Accesul concurent la același volum din mai multe containere poate cauza corupție de date dacă aplicațiile nu gestionează locking-ul. Asigură-te că aplicațiile tale sunt proiectate pentru acces concurent sau că doar un singur container scrie.
Bind mount-urile sunt ideale pentru:
/etc/myapp/config.yaml de pe host în container/var/run/docker.sock în containere de tip CI/CD sau management# Exemplu development: codul local montat în container Node.js docker run -d \ --name dev-server \ --mount type=bind,source=$(pwd)/src,target=/app/src \ -p 3000:3000 \ node:20-alpine npm run dev # Montare socket Docker (ex. pentru Portainer) docker run -d \ --name portainer \ --mount type=bind,source=/var/run/docker.sock,target=/var/run/docker.sock \ -p 9000:9000 \ portainer/portainer-ce:latest
# Read-only - containerul nu poate modifica fișierele docker run --mount type=bind,source=/etc/ssl/certs,target=/certs,readonly nginx # Propagation - cum sunt propagate sub-mount-urile (avansat, Linux) # Valori: shared, slave, private, rshared, rslave, rprivate docker run --mount type=bind,source=/data,target=/data,bind-propagation=shared myapp
Docker suportă drivere de volum terțe care permit stocarea datelor pe sisteme externe, nu doar local.
| Driver | Stocare backend | Caz de utilizare |
|---|---|---|
local | Disk local | Default, single-node |
nfs | NFS share | Partajare între noduri |
vieux/sshfs | SFTP/SSH | Stocare remotă via SSH |
rexray/s3fs | Amazon S3 | Stocare obiect cloud |
convoy | EBS, NFS, VFS | Backup & restore integrate |
# Creare volum pe un share NFS docker volume create \ --driver local \ --opt type=nfs \ --opt o=addr=192.168.1.100,rw,nfsvers=4 \ --opt device=:/export/date \ volum_nfs # Folosire în container docker run -d \ --mount source=volum_nfs,target=/date \ myapp:latest
# Instalare plugin docker plugin install vieux/sshfs # Creare volum via SSH docker volume create \ --driver vieux/sshfs \ --opt sshcmd=user@server:/cale/date \ --opt password=secret \ volum_ssh
Docker Compose oferă o sintaxă elegantă pentru declararea și gestionarea volumelor la nivelul stack-ului.
services: db: image: postgres:16 volumes: - date_db:/var/lib/postgresql/data environment: POSTGRES_PASSWORD: secret app: image: myapp:latest volumes: # Named volume (read-write) - date_uploads:/var/www/uploads # Bind mount (development) - ./config/app.yaml:/etc/myapp/config.yaml:ro # tmpfs - type: tmpfs target: /tmp/cache tmpfs: size: 134217728 # 128 MB în bytes volumes: date_db: date_uploads:
volumes: # Volum extern (creat în afara Compose, ex. manual sau alt stack) date_externa: external: true # Volum cu driver NFS date_nfs: driver: local driver_opts: type: nfs o: addr=192.168.1.100,rw device: ":/export/date" # Volum cu labels date_app: labels: - "com.example.project=myapp" - "com.example.env=productie"
services: generator: image: app-generator:latest volumes: - date_partajate:/output processor: image: app-processor:latest volumes: - date_partajate:/input:ro depends_on: - generator volumes: date_partajate:
Strategia clasică: pornești un container temporar cu volumul montat, arhivezi conținutul, copiezi arhiva pe host.
# Backup volum → arhivă tar.gz pe host docker run --rm \ --mount source=date_aplicatie,target=/date,readonly \ --mount type=bind,source=$(pwd)/backup,target=/backup \ alpine \ tar czf /backup/backup_$(date +%Y%m%d_%H%M%S).tar.gz -C /date . # Verificare arhivă ls -lh backup/
# Restore dintr-o arhivă tar.gz într-un volum (existent sau nou) docker run --rm \ --mount source=date_aplicatie,target=/date \ --mount type=bind,source=$(pwd)/backup,target=/backup,readonly \ alpine \ tar xzf /backup/backup_20241115_102345.tar.gz -C /date # Verificare restaurare docker run --rm \ --mount source=date_aplicatie,target=/date,readonly \ alpine ls -la /date
# Migrare date dintr-un volum vechi în unul nou docker run --rm \ --mount source=volum_vechi,target=/sursa,readonly \ --mount source=volum_nou,target=/destinatie \ alpine \ sh -c "cp -av /sursa/. /destinatie/"
La baze de date, e recomandat să folosești utilitarele native în loc de un simplu tar - garantezi astfel consistența datelor, indiferent dacă baza e activă în momentul backup-ului:
# Dump PostgreSQL direct în fișier pe host docker exec postgres_container \ pg_dumpall -U postgres | gzip > backup_postgres_$(date +%Y%m%d).sql.gz # Restore PostgreSQL gunzip -c backup_postgres_20241115.sql.gz | \ docker exec -i postgres_container psql -U postgres
# Metoda 1: container temporar Alpine docker run --rm \ --mount source=date_aplicatie,target=/date,readonly \ alpine ls -laR /date # Metoda 2: shell interactiv docker run -it --rm \ --mount source=date_aplicatie,target=/date \ alpine sh # Metoda 3: accesare directă pe host (necesită root) sudo ls -la /var/lib/docker/volumes/date_aplicatie/_data
# Listare mount-uri ale unui container docker inspect --format='{{json .Mounts}}' nume_container | jq # Sau mai detaliat docker inspect nume_container | jq '.[0].Mounts'
Exemplu output:
[
{
"Type": "volume",
"Name": "date_aplicatie",
"Source": "/var/lib/docker/volumes/date_aplicatie/_data",
"Destination": "/date",
"Driver": "local",
"Mode": "",
"RW": true,
"Propagation": ""
}
]
Volumele dangling sunt cele care nu mai sunt atașate la niciun container - ocupă spațiu inutil:
# Listare volume nefolosite docker volume ls --filter dangling=true # Afișare spațiu folosit de volume docker system df -v # Curățare volume dangling docker volume prune
Când folosești bind mounts, UID-ul/GID-ul procesului din container trebuie să corespundă cu proprietarul fișierelor de pe host:
# Verificare UID proces în container docker run --rm nginx:alpine id # uid=101(nginx) gid=101(nginx) # Ajustare permisiuni pe host sudo chown -R 101:101 /home/user/nginx-data # Sau specificare user la rulare docker run -d --user 1000:1000 myapp:latest
Montarea volumelor ca read-only limitează suprafața de atac - containerul nu poate modifica date critice:
# CLI docker run --mount source=config_date,target=/config,readonly myapp # Docker Compose services: app: volumes: - config_date:/config:ro
Montarea socket-ului Docker oferă containerului control deplin asupra host-ului - echivalent cu privilegii root. Folosește-l doar când este absolut necesar (ex. Portainer, CI runners) și niciodată în aplicații expuse publicului.
docker volume ls –filter label=env=productie)–mount față de -v - sintaxa explicită reduce ambiguitatea și erorile/var/lib/docker/volumesdocker volume prune periodic - în medii de development se acumulează rapid volume orfane