#!/bin/bash
set -e
DB_CONTAINER="my_prod_postgres"
BACKUP_FILE="/backups/db_backup_$(date +%F).sql.gz"
# 1. Backup corect folosind pg_dump în interiorul containerului
docker exec -t $DB_CONTAINER pg_dumpall -U postgres | gzip > "$BACKUP_FILE"
# 2. Testăm restore-ul automat pe un container temporar
echo "Se inițiază testul de restore..."
TEST_CONTAINER="pg_test_restore"
docker run --name $TEST_CONTAINER -e POSTGRES_PASSWORD=test_pwd -d postgres:15-alpine
sleep 5 # așteptăm ca Postgres să fie gata să accepte conexiuni
# Decomprimăm și injectăm backup-ul în containerul de test
gunzip -c "$BACKUP_FILE" | docker exec -i $TEST_CONTAINER psql -U postgres -d postgres
# Rulăm un query de verificare pentru a ne asigura că avem date reale
USER_COUNT=$(docker exec -i $TEST_CONTAINER psql -U postgres -d postgres -t -c "SELECT COUNT(*) FROM users;")
# Curățăm containerul de test
docker rm -f $TEST_CONTAINER
if [ "$USER_COUNT" -gt 0 ]; then
echo "Backup validat cu succes! Total useri restaurați: $USER_COUNT"
else
echo "EROARE: Backup-ul pare gol sau corupt!"
exit 1
fiSalutare! Hai să vorbim direct despre o greșeală pe care o văd și la developeri cu câțiva ani buni în spate: folosirea bind mount-urilor pentru bazele de date în producție. Am avut acum doi ani un proiect mărișor, cu vreo 15k utilizatori activi, unde băieții se mirau de ce le crapă performanța la scriere și de ce aveau probleme constante cu permisiunile fișierelor pe Linux.
Diferența care contează: Named vs Bind
Pe scurt, un bind mount (-v /opt/app/data:/var/lib/postgresql/data) leagă un director specific de pe mașina gazdă de un director din container. E genial pentru development. Vrei hot-reload la codul de Node sau PHP? Dai bind mount la folderul de proiect în container și aia a fost.
Dar pentru baze de date în producție, e o idee proastă.
În primul rând, ai problema permisiunilor. Docker rulează procesele din container cu utilizatori interni specifici (de exemplu, userul postgres cu UID 999). Dacă folderul de pe gazdă este deținut de root sau de userul tău de sistem, te lovești instant de erori de tipul "Permission denied".
În al doilea rând, performanța I/O scade drastic. Pe Linux este acceptabil, dar pe macOS sau Windows (unde Docker rulează într-o mașină virtuală), bind mount-urile trec printr-un strat de traducere a sistemului de fișiere care distruge efectiv viteza de scriere. Am măsurat personal o scădere de până la 40% a vitezei de scriere la un import masiv de date când am folosit bind mount în loc de named volume.
Named volumes (-v pg_data:/var/lib/postgresql/data) sunt gestionate complet de Docker. Ele trăiesc într-o zonă dedicată din sistem (de obicei în /var/lib/docker/volumes/ pe Linux). Docker se ocupă singur de permisiuni, folosește driverul nativ de stocare și rulează la viteză maximă.
Trade-off-ul sincer? E mai greu să te uiți "cu ochiul liber" în fișierele bazei de date direct de pe gazdă. Dar, să fim serioși, în producție oricum nu ai ce căuta să modifici fișierele bazei de date cu mâna.
Mitul „fac backup la folderul de volume”
Am auzit des scuza asta: „Dacă folosesc named volumes, cum le fac backup? Nu e mai simplu cu bind mount că dau un zip la folder direct în cron?”
Nu face asta. Dacă copiezi fișierele brute ale bazei de date (cum ar fi folderul de date din Postgres sau MySQL) în timp ce motorul de bază de date rulează, backup-ul tău va fi corupt în 9 cazuri din 10. Bazele de date scriu în memorie și pe disc asincron, folosesc WAL (Write-Ahead Logging) și fișiere temporare. Fișierele copiate „la cald” vor fi într-o stare inconsistentă.
Soluția corectă este să rulezi utilitarul nativ al bazei de date (pg_dump sau mysqldump) din interiorul containerului și să trimiți output-ul direct pe gazdă sau într-un storage extern.
Strategia de restore testat: Ce nu testezi, nu există
Am pățit-o pe pielea mea la un startup. Scriptul de backup rula zilnic, lăsa un fișier .sql.gz frumos în S3. Când a picat serverul și am avut nevoie de el, am descoperit că dump-ul era gol (0 bytes). O schimbare de schemă făcea ca utilitarul să dea o eroare silențioasă pe care scriptul meu de bash o ignora.
De atunci, regula mea este clară: un backup nu este valid până când nu rulează un script de restore automatizat pe o bază de date temporară, urmat de un query de verificare.
În scriptul de mai jos aveți o metodă simplă prin care fac asta automat într-un pipeline sau într-un cron job. Facem backup, pornim un container temporar, restaurăm datele și verificăm dacă tabela de utilizatori conține date. Dacă totul e ok, ștergem containerul de test și salvăm backup-ul.
Voi cum gestionați backup-urile pentru containerele din producție? Mergeți pe scripturi clasice pe gazdă sau folosiți soluții gata integrate gen litestream sau barman?