Cuprins

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:

# 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

Referințe