eduardweb.
Docker & ContainersIntermediar#docker#devops#postgresql#backup

Docker volumes pentru baze de date: named vs bind mounts și backup verificat

De Cosmin Rotaru, 6 sept. 2026 · 21 vizualizări · 2 like-uri

Postat 6 sept. 2026
bash
#!/usr/bin/env bash
set -euo pipefail

BACKUP_FILE="/tmp/db_backup_$(date +%Y%m%d_%H%M%S).dump"
CONTAINER_PROD="my_prod_postgres"
DB_NAME="app_production"
DB_USER="postgres"

# 1. Generam dump-ul direct din container prin stream
docker exec -t "$CONTAINER_PROD" pg_dump -U "$DB_USER" -Fc "$DB_NAME" > "$BACKUP_FILE"

# 2. Testam restore-ul intr-un container de unica folosinta
echo "Verificam integritatea dump-ului pe un container temporar..."
docker run --rm -d --name pg_test_restore \
  -e POSTGRES_PASSWORD=testpass \
  postgres:16-alpine

sleep 4 # asteptam initializarea

# 3. Restauram baza de test
docker exec pg_test_restore createdb -U postgres test_db
docker exec -i pg_test_restore pg_restore -U postgres -d test_db < "$BACKUP_FILE"

# 4. Verificam ca datele chiar exista
COUNT=$(docker exec -i pg_test_restore psql -U postgres -d test_db -t -c "SELECT count(*) FROM users;")
echo "Restore validat cu succes. Total useri in backup: $(echo $COUNT | xargs)"

# 5. Cleanup container de test
docker stop pg_test_restore

# Aici urmeaza upload-ul spre S3/B2 si stergerea fisierului local
# aws s3 cp "$BACKUP_FILE" s3://my-backups/ && rm -f "$BACKUP_FILE"

Dacă arunci o bază de date de producție pe un bind mount și faci backup dând tar pe folderul de pe host în timp ce baza rulează, e o chestiune de timp până pierzi date. Am pățit-o acum vreo 6 ani la un proiect cu vreo 15k useri zilnici: am încercat un restore de urgență după un crash de disc și Postgres a refuzat să pornească din cauza unui checksum mismatch pe fișierele de WAL.

Nu vrei să înveți lecția asta într-o vineri seară cu clientul la telefon.

Named volumes vs Bind mounts: unde greșește lumea

Mulți începători pun în docker-compose.yml ceva de genul ./pgdata:/var/lib/postgresql/data pentru că vor să vadă fișierele direct în proiect. E comod pe local când vrei să dai un rm -rf pgdata să resetezi totul de la zero, dar pentru baze de date în orice alt mediu e o idee proastă.

Bind mount-urile leagă un director precis de pe host în container. Pe Linux te lovești instant de permisiuni: procesul din Postgres rulează de regulă ca utilizatorul intern postgres (UID 999). Dacă directorul de pe host a fost creat de root sau de userul tău de sistem (UID 1000), baza crapă instant cu Permission denied. Pe macOS sau Windows prin Docker Desktop, bind mount-urile trec printr-un layer de sincronizare de fișiere care distruge complet performanța de I/O — am măsurat diferențe de 4x până la 8x la write-uri grele.

Named volume-urile (db_data:/var/lib/postgresql/data) sunt administrate complet de Docker în /var/lib/docker/volumes/. Docker se ocupă singur de permisiuni la inițializare, folosește direct sistemul de fișiere nativ al gazdei fără layers intermediare și nu ai bătăi de cap cu UID-urile.

Trade-off-ul sincer? Named volume-ul e mai opac. Nu poți deschide un fișier rapid din VS Code și, dacă vrei să inspectezi fișierele brute, trebuie să pornești un container temporar sau să umbli ca root prin directorul intern Docker.

De ce cp sau tar pe volum nu e backup

O bază relațională ține tranzacții în memorie, scrie în WAL (Write-Ahead Log) și face flush asincron pe disc. Dacă tu copiezi fișierele brute din /var/lib/docker/volumes/... în timp ce Postgres sau MySQL răspunde la request-uri, copiezi o stare parțială. La restore, motorul va detecta fișiere scrise pe jumătate și cel mai probabil nu va porni.

Singurul backup corect pentru baze de date mici și medii (sub 100GB) este un dump logic generat de utilitarul nativ (pg_dump sau mysqldump). Pentru o bază de 20GB, un pg_dump -Fc prin stream comprimat durează sub 3 minute și garantează consistență tranzacțională completă, fără să oprești containerul.

Dacă n-ai testat restore-ul, nu ai backup

Regula de fier: ai un backup valid abia în momentul în care ai automatizat restore-ul într-un mediu izolat și ai verificat datele. Backup-ul care stă netestat pe un S3 e doar o speranță.

Soluția mea simplă într-un cronjob de noapte: trag dump-ul, pornesc un container temporar de Postgres cu volum aruncat pe loc (--rm), fac restore, rulez un SELECT count(*) pe un tabel critic și abia apoi împing fișierul către stocarea externă.

Răspunsuri 0

Se încarcă răspunsurile…

Loghează-te pentru a răspunde

Doar membrii comunității pot lăsa comentarii.