Docker Volumes
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.
Tipuri de montare (mount types)
Docker oferă trei metode distincte prin care un container poate accesa date din afara sistemului său de fișiere intern:
Named Volumes
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
Bind Mounts
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.
tmpfs Mounts
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 |
Named Volumes
Crearea unui volum
# 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
Listarea și inspecția volumelor
# 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"
}
]
Ștergerea volumelor
# Ș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.
Folosirea volumelor în containere
Sintaxa --mount (recomandată)
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 -v (scurtă)
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
Volume-uri cu mai multe containere
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 Mounts în detaliu
Cazuri de utilizare
Bind mount-urile sunt ideale pentru:
- Development activ - modificările de cod din editor sunt vizibile imediat în container fără rebuild
- Fișiere de configurare - montezi
/etc/myapp/config.yamlde pe host în container - Certificate TLS/SSL - montezi certificatele generate (ex. via Certbot) în containerul web
- Socket-ul Docker - expui
/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
Opțiuni avansate bind mount
# 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
Volume Drivers (Plugins)
Docker suportă drivere de volum terțe care permit stocarea datelor pe sisteme externe, nu doar local.
Drivere populare
| 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 |
Exemplu: volum NFS
# 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
Exemplu: plugin SSHFS
# 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
Volumes în Docker Compose
Docker Compose oferă o sintaxă elegantă pentru declararea și gestionarea volumelor la nivelul stack-ului.
Declarare de bază
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:
Volume cu opțiuni avansate
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"
Partajarea volumelor între servicii
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:
Backup și Restore
Backup unui volum
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 unui volum
# 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
Copiere volum → volum nou
# 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/"
Backup baze de date (PostgreSQL)
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
Inspecție și Debugging
Explorarea conținutului unui volum
# 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
Verificarea volumelor unui container
# 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": ""
}
]
Identificarea volumelor dangling
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
Permisiuni și Securitate
Problema permisiunilor cu bind mounts
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
Volume read-only
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
Evitarea montării /var/run/docker.sock
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.
Bune practici
- Folosește named volumes pentru date de producție - nu bind mounts; sunt portabile, ușor de backup și nu depind de structura de directoare a host-ului
- Separă volumele per funcție - un volum pentru date aplicație, altul pentru logs, altul pentru upload-uri; nu pune totul într-un singur volum
- Adaugă labels volumelor - facilitează identificarea și curățarea ulterioară (
docker volume ls –filter label=env=productie) - Include backup în rutina de deployment - automatizează backup-urile înainte de update-uri majore
- Preferă
–mountfață de-v- sintaxa explicită reduce ambiguitatea și erorile - Nu stoca secrete în volume - folosește Docker Secrets sau variabile de mediu gestionate (ex. Vault, sops); volumele nu sunt criptate implicit
- Monitorizează spațiul pe disk - volumele pot crește nelimitat; adaugă alerte pe
/var/lib/docker/volumes - Fă
docker volume pruneperiodic - în medii de development se acumulează rapid volume orfane