# 1. Backup securizat (fără oprirea containerului)
docker exec -t my_postgres_db pg_dumpall -U postgres | gzip > ./backups/db_backup_$(date +%F).sql.gz
# 2. Restore testat într-un container nou, curat
# Pornim un container temporar pentru test
docker run --name temp_restore_test -e POSTGRES_PASSWORD=mytestpwd -d postgres:15
# Așteptăm 5 secunde să se inițializeze
sleep 5
# Restaurăm datele din dump
gunzip -c ./backups/db_backup_2024-05-20.sql.gz | docker exec -i temp_restore_test psql -U postgres
# Verificăm dacă datele sunt acolo
docker exec -it temp_restore_test psql -U postgres -c "SELECT COUNT(*) FROM users;"Am văzut prea des oameni care își pierd datele fiindcă fac "backup" la folderele de Docker prin simplă copiere. Am pățit-o și eu acum vreo opt ani cu un Postgres de producție și de atunci suflu și-n iaurt. Dacă doar copiezi fișierele din volum în timp ce baza de date rulează, ai șanse mari să te alegi cu un backup corupt.
Hai să lămurim cum stă treaba cu named volumes, bind mounts și cum structurăm un proces de backup care chiar funcționează când ia foc serverul.
Named Volumes vs Bind Mounts: Unde punem datele?
Aici e o confuzie mare în rândul celor care trec de la mediul de dev la producție. Ambele pun date pe host, dar o fac diferit.
Named volumes (-v db_data:/var/lib/postgresql/data) sunt gestionate complet de Docker. Docker decide unde le pune pe disk (de regulă în /var/lib/docker/volumes/ pe Linux).
- Avantaj: Performanță maximă de I/O și izolare completă.
- Dezavantaj: Sunt greu de accesat direct de pe host, mai ales dacă rulezi Docker Desktop pe macOS sau Windows unde totul e izolat într-o mașină virtuală.
Bind mounts (-v /opt/my-app/db:/var/lib/postgresql/data) sunt mapări directe ale unui folder specificat de tine de pe host.
- Avantaj: Acces direct la fișiere. Poți să intri cu file manager-ul și să vezi ce e acolo.
- Dezavantaj: Pe macOS și Windows, performanța scade dramatic (până la 30-40% la scriere) din cauza stratului de virtualizare. În plus, te lovești rapid de probleme de permisiuni, deoarece ID-ul userului din container (de exemplu,
postgrescu UID 999) s-ar putea să nu aibă drept de scriere în folderul tău din host.
Regula mea de aur: Pentru baze de date în producție, folosesc exclusiv named volumes. Pentru fișiere de configurare în dev sau cod sursă pe care îl vreau sincronizat instant, folosesc bind mounts.
Greșeala clasică: Backup direct pe fișierele din volum
Să zicem că ai baza de date într-un named volume. Te gândești că e suficient să faci un tar archive la folderul /var/lib/docker/volumes/db_data/_data.
Greșit. Dacă baza de date scrie în acel moment, fișierele copiate vor fi într-o stare inconsistentă. Când vei încerca să pornești un container nou cu acele date, motorul bazei de date va raporta erori de checksum sau corupere de pagini.
Pentru un backup corect, trebuie să folosești utilitarul nativ al bazei de date, rulat din interiorul containerului, dar salvat pe host.
Restore testat (Singurul backup care contează)
La un proiect cu o bază de date PostgreSQL de 120GB, am implementat un script simplu care face dump și apoi testează automat restore-ul.
Ideea e simplă: degeaba ai un fișier .sql.gz de backup dacă atunci când ai nevoie de el descoperi că are o sintaxă parțială sau e incomplet. În codul de mai jos aveți varianta curată de backup și restore pe care o folosesc în producție.
După ce rulați restore-ul pe o bază de date de test (de preferat într-un container temporar pornit special pentru asta), rulați un query simplu, de tipul SELECT COUNT(*) FROM users;. Dacă query-ul returnează un număr valid și nu dă eroare, abia atunci poți dormi liniștit.
Voi cum testați backup-urile? Le lăsați acolo în S3 și vă rugați să meargă când crapă serverul, sau aveți un flow automatizat?