eduardweb.
Docker & ContainersIntermediar#docker#devops#sysadmin#databases

Docker volumes: De ce folosești greșit bind mounts pentru baze de date și cum faci un backup corect

De Florin Manea, 20 iul. 2026 · 13 vizualizări · 3 like-uri

Postat 20 iul. 2026
bash
#!/bin/bash
# Backup securizat din containerul de Postgres și testare restore
CONTAINER_NAME="my_prod_db"
BACKUP_DIR="/opt/backups"
DATE=$(date +%Y%m%d_%H%M%S)
BACKUP_FILE="${BACKUP_DIR}/db_backup_${DATE}.sql.gz"

# 1. Backup consistent utilizând pg_dump în interiorul containerului
docker exec -t ${CONTAINER_NAME} pg_dumpall -U postgres | gzip > "${BACKUP_FILE}"

# 2. Pornim un container temporar de Postgres pentru a testa restore-ul
TEST_CONTAINER="pg_test_restore"
docker run --name ${TEST_CONTAINER} -d -e POSTGRES_PASSWORD=test_pwd postgres:15-alpine

# Așteptăm câteva secunde să pornească instanța de test
sleep 5

# 3. Restaurăm datele în containerul de test
gunzip -c "${BACKUP_FILE}" | docker exec -i ${TEST_CONTAINER} psql -U postgres

# 4. Verificăm dacă structura de date este validă
TABLE_EXISTS=$(docker exec -i ${TEST_CONTAINER} psql -U postgres -t -c "SELECT EXISTS (SELECT FROM pg_tables WHERE tablename = 'users');")

# Curățăm containerul de test
docker rm -f ${TEST_CONTAINER}

if [ "${TABLE_EXISTS//[[:space:]]/}" == "t" ]; then
    echo "Backup-ul ${BACKUP_FILE} este valid și a fost testat cu succes."
else
    echo "ALERTĂ: Restore-ul a eșuat sau tabela 'users' nu există!"
    exit 1
fi

Salutare. Am văzut destule baze de date pierdute prin producție pentru că lumea încă mai confundă bind mount-urile cu volumele managed sau, mai rău, face backup direct pe fișierele brute din /var/lib/docker/volumes. Am trecut și eu prin asta la începuturi și am pierdut date din cauza unui backup corupt. Azi vreau să lămurim cum stă treaba și cum facem un workflow de backup și restore pe care chiar te poți baza când crapă serverul.

Named Volumes vs Bind Mounts: Unde greșește majoritatea

Am avut acum doi ani un proiect cu vreo 8k useri activi unde rula un Postgres ca bază de date principală. Din comoditate, echipa pusese un bind mount grosolan: -v /opt/db_data:/var/lib/postgresql/data. Toate bune în local, dar în producție am început să avem probleme uriașe de I/O și blocaje de permisiuni când am încercat să facem un update de OS pe host.

Trade-off-ul e destul de simplu:

  • Bind mount-urile (-v /calea/mea:/container/path) sunt excelente pentru development. Vrei să vezi modificările din cod instant pe host? Dai bind mount la folderul de proiect. Dar în producție, pe baze de date, sunt o idee proastă. Depinzi direct de structura de directoare a hostului, de utilizatorul de pe host și de modul în care sistemul de operare face sync pe disc.
  • Named volumes (-v db_data:/container/path) sunt gestionate complet de Docker. Docker știe exact ce permisiuni să pună, driverele de stocare sunt optimizate nativ și nu riști să strici baza de date pentru că ai rulat din greșeală un chown greșit pe host. Singurul dezavantaj e că nu poți naviga la fel de ușor prin fișiere direct din terminalul hostului, dar pentru asta avem utilitarele bazei de date, nu ne băgăm degetele direct în fișierele motorului de stocare.

Capcana backup-ului direct pe foldere

La începutul carierei mele, am scris un script care oprea parțial serviciile și dădea un tar pe folderul de date al MySQL-ului. Toate bune, până când am avut nevoie de restore. O tranzacție lungă era încă în memorie (dirty pages) în momentul în care am copiat fișierele. Rezultatul? Un backup inutilizabil de 40GB care la restore dădea crash instant din cauza tabelelor corupte. Am pierdut atunci cam 4 ore de date.

Pentru baze de date, backup-ul se face întotdeauna prin utilitarul dedicat al bazei de date rulat în interiorul containerului (pg_dump pentru Postgres sau mysqldump pentru MySQL/MariaDB). În felul ăsta, motorul bazei de date garantează consistența datelor salvate, chiar dacă există tranzacții active în acel moment. În plus, am economisit cam 30% la spațiul de stocare pe serverul de backup doar trecând de la tar-uri brute la dump-uri comprimate cu gzip.

Regula de aur: Restore-ul testat

Un backup pe care nu l-ai restaurat niciodată nu este backup. Este doar o speranță. Cel mai bun workflow pe care l-am implementat și pe care îl folosesc și acum rulează dintr-un cron job săptămânal:

  1. Face dump-ul bazei de date.
  2. Pornește un container temporar, izolat.
  3. Aplică restore-ul pe containerul de test.
  4. Rulează o interogare simplă (un SELECT COUNT pe o tabelă critică) ca să valideze că datele sunt acolo și structura e intactă.
  5. Șterge containerul de test și trimite un raport pe Slack.

În secțiunea de cod am lăsat un script Bash simplificat care face exact asta pentru un Postgres cu volum numit. Îl puteți adapta ușor pentru orice altă bază de date.

Voi cum gestionați backup-urile pentru containere în producție? Mergeți pe scripturi custom în cron sau folosiți soluții dedicate de orchestrare?

Răspunsuri 0

Se încarcă răspunsurile…

Loghează-te pentru a răspunde

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