Jak wykonać kopię zapasową i aktualizację Docker Compose
Dowiedz się, jak poprawnie zabezpieczyć stos Docker Compose przed aktualizacją. Poradnik omawia procedurę zrzutu bazy danych, kopiowania wolumenów oraz weryfikacji przywracania.
Co musi zawierać kopia zapasowa stosu Docker Compose
Kopia zapasowa stosu Docker Compose musi obejmować cztery odrębne elementy, a utrata któregokolwiek z nich uniemożliwia przywrócenie aplikacji: plik compose, plik .env znajdujący się obok niego, zawartość każdego wolumenu oraz zrzut bazy danych wykonany przez natywnego klienta bazy danych. Kopiowanie plików bazy danych w trakcie działania kontenera nie jest kopią zapasową. Aktualizacje wymagają tej samej listy oraz jednej zasady: wykonaj kopię zapasową przed pobraniem nowych obrazów, ponieważ migracje schematu są projektowane do działania w jednym kierunku, a większość projektów nie oferuje ścieżki powrotnej.
Wszystkie poniższe instrukcje zakładają, że stos jest już wdrożony, a polecenie docker compose ps potwierdza jego działanie. Przykłady wykorzystują katalog projektu /srv/myapp z usługami o nazwach app oraz db. Należy podstawić własne nazwy. Polecenia celowo pozostawiono w formie ogólnej, ponieważ kluczowe elementy, takie jak wolumeny i baza danych, działają w ten sam sposób niezależnie od aplikacji.
Ustalenie, co faktycznie przechowuje stos
cd /srv/myapp
docker compose ps
docker compose config --volumes
docker volume ls --filter label=com.docker.compose.project=myappdocker compose config --volumes wyświetla krótkie nazwy wolumenów nazwanych zadeklarowanych w pliku. docker volume ls wyświetla nazwy, które te wolumeny faktycznie posiadają na dysku. Listy te różnią się, ponieważ Compose dodaje nazwę projektu przed nazwą wolumenu: wolumen zapisany jako db_data w pliku istnieje jako myapp_db_data. Nazwa projektu domyślnie odpowiada nazwie katalogu, więc zmiana nazwy katalogu powoduje, że stos wskazuje na nowy zestaw pustych wolumenów, pozostawiając stare z danymi na dysku. Każde poniższe polecenie wymaga użycia rzeczywistej nazwy z docker volume ls.
Montowania typu bind mounts nie pojawiają się na żadnej z tych list. W pliku compose są to wpisy ze ścieżką hosta po lewej stronie dwukropka, ./config:/app/config. Są to zwykłe katalogi na hoście, więc standardowe narzędzia mają do nich dostęp. Wolumeny nazwane znajdują się w /var/lib/docker/volumes/, a docker volume inspect --format '{{.Mountpoint}}' myapp_db_data wyświetla dokładną ścieżkę wybranego wolumenu. Rodzaj używanego rozwiązania wpływa na sposób kopiowania danych, a porównanie bind mounts i wolumenów nazwanych szczegółowo omawia różnice między nimi.
Teraz należy podzielić znalezione elementy na dwie grupy. Niektóre wolumeny przechowują stan, którego nie da się odtworzyć: przesłane pliki, wygenerowane klucze, samą bazę danych oraz wszystko, co użytkownik wprowadził do aplikacji. Inne przechowują dane pochodne, takie jak miniatury czy indeksy wyszukiwania, które aplikacja może samodzielnie odbudować. Tworzenie kopii zapasowych drugiej grupy zajmuje miejsce na dysku i wydłuża czas przywracania, nie przynosząc żadnych korzyści. Wolumen pamięci podręcznej Redis jest najbardziej wyrazistym przykładem: jego utrata skutkuje jedynie jednym wolniejszym pierwszym żądaniem.
Tworzenie kopii zapasowej pliku compose oraz pliku .env
Oba pliki znajdują się na hoście obok siebie i żaden z nich nie jest częścią wolumenu. Plik .env przechowuje hasło do bazy danych, sekret aplikacji oraz wszelkie tokeny API, dlatego to właśnie ten plik pozwala przywrócić zestaw wolumenów do stanu działającej aplikacji. Zazwyczaj jest on również uwzględniony w .gitignore, co oznacza, że strategia „moja konfiguracja jest w git” pomija najważniejszy plik. Przechowywanie sekretów w pliku env jest właściwym wzorcem, który nakłada na użytkownika obowiązek uwzględnienia tego pliku w kopii zapasowej.
sudo install -d -m 700 -o "$USER" -g "$(id -gn)" /srv/backups/myapp
cp -a compose.yaml .env /srv/backups/myapp/
chmod 600 /srv/backups/myapp/.envSkopiuj każdy plik compose używany przez stos, a nie tylko pierwszy z nich. Stos uruchomiony za pomocą -f compose.yaml -f compose.prod.yaml wymaga obu plików, aby przywrócenie przebiegło w ten sam sposób, a sposób łączenia wielu plików compose decyduje o tym, które wartości faktycznie trafią do kontenera.
Jedno ostrzeżenie wiąże .env z wolumenami. Oficjalny obraz Postgres odczytuje POSTGRES_PASSWORD tylko podczas inicjalizacji pustego katalogu danych. Zmiana tej wartości w późniejszym czasie nie zmienia hasła wewnątrz bazy danych. Przywrócenie wolumenu sprzed miesiąca obok dzisiejszego .env spowoduje błąd połączenia aplikacji z komunikatem FATAL: password authentication failed for user "appuser", mimo że oba pliki wyglądają na poprawne podczas inspekcji. Przechowuj .env oraz wolumeny pochodzące z tego samego momentu razem w tej samej kopii zapasowej.
Zrzut bazy danych za pomocą dedykowanego klienta
Serwer bazy danych nieustannie zapisuje dane do swoich plików. tar typu /var/lib/postgresql/data, wykonana w trakcie pracy serwera, kopiuje niektóre strony zapisu przed operacją, a inne po niej, przez co archiwum zawiera niespójny stan, którego nie można odtworzyć. Narzędzie do zrzutu odczytuje dane w ramach pojedynczej transakcji, dzięki czemu plik reprezentuje jeden spójny moment w czasie. Ta różnica odróżnia kopię zapasową od zwykłego skopiowania plików.
docker compose exec -T db sh -c \
'pg_dump -U "$POSTGRES_USER" -d "$POSTGRES_DB" -Fc' \
> /srv/backups/myapp/db-$(date +%F).dumpNależy zachować flagę -T. Wyłącza ona przydzielanie TTY, a przy dołączonym TTY Docker przekształca strumień wyjściowy w drodze do powłoki, co powoduje uszkodzenie binarnego zrzutu. O tym problemie dowiesz się dopiero w momencie nieudanego przywracania danych. Pojedyncze cudzysłowy są również istotne: zapobiegają one rozwijaniu zmiennej $POSTGRES_USER przez powłokę hosta, dzięki czemu rozwija ją powłoka wewnątrz kontenera, używając wartości zdefiniowanych w pliku Compose. Flaga -Fc zapisuje dane w formacie niestandardowym, który kompresuje zawartość w locie i pozwala narzędziu pg_restore na późniejsze wyodrębnianie poszczególnych obiektów.
Role oraz ich hasła znajdują się poza pojedynczą bazą danych, dlatego należy je również wyeksportować:
docker compose exec -T db sh -c 'pg_dumpall -U "$POSTGRES_USER" --globals-only' \
> /srv/backups/myapp/globals.sqlNastępnie należy sprawdzić, czy plik jest poprawnym zrzutem, a nie komunikatem o błędzie:
ls -lh /srv/backups/myapp/
head -c 5 /srv/backups/myapp/db-$(date +%F).dumpZrzut w formacie niestandardowym rozpoczyna się od pięciu bajtów PGDMP. Plik o zerowej długości lub rozpoczynający się od pg_dump: oznacza, że polecenie zakończyło się niepowodzeniem. Powłoka tworzy plik wyjściowy przed uruchomieniem polecenia, więc nieudany zrzut pozostawia po sobie plik o wiarygodnej nazwie i znaczniku czasu. Jest to najczęstsza przyczyna cichego niepowodzenia kopii zapasowych.
W przypadku MariaDB lub MySQL klient ulega zmianie, ale zasada pozostaje ta sama:
docker compose exec -T db sh -c \
'mariadb-dump -u root -p"$MARIADB_ROOT_PASSWORD" --single-transaction --databases "$MARIADB_DATABASE"' \
> /srv/backups/myapp/db-$(date +%F).sqlFlaga --single-transaction zapewnia spójny zrzut tabel InnoDB bez blokowania operacji zapisu. W obrazie MySQL polecenie to mysqldump, a zmienne to MYSQL_ROOT_PASSWORD oraz MYSQL_DATABASE. W aktualnych obrazach MariaDB polecenie mysqldump nadal działa jako nazwa kompatybilności dla mariadb-dump. Należy pamiętać, że hasło podane w wierszu poleceń jest widoczne na liście procesów kontenera przez cały czas trwania zrzutu.
SQLite wymaga szczególnej uwagi. Baza danych to jeden plik, ale ostatnie transakcje mogą nadal znajdować się w oddzielnym pliku -wal obok niej, więc skopiowanie tylko .db spowoduje utratę najnowszych zapisów. Jeśli obraz zawiera klienta, polecenie sqlite3 /data/app.db ".backup '/data/app-backup.db'" zapisze spójną kopię podczas pracy aplikacji. Jeśli go nie zawiera, należy zatrzymać kontener i skopiować plik .db wraz z jego towarzyszącymi plikami -wal oraz -shm.
Jeśli baza danych działa na hoście, a nie wewnątrz stosu, mają zastosowanie te same polecenia bez przedrostka docker compose exec, a lektura uruchamianie bazy danych w Dockerze lub na hoście jest zalecana przed kolejną przebudową środowiska.
Przechwytywanie wolumenów
Nazwany wolumen nie posiada ścieżki w systemie hosta, którą można edytować ręcznie, dlatego należy zamontować go w tymczasowym kontenerze i stamtąd zarchiwizować.
docker run --rm \
-v myapp_uploads:/data:ro \
-v /srv/backups/myapp:/backup \
alpine:3 tar czf /backup/uploads.tar.gz -C /data .Kontener pomocniczy montuje wolumen w trybie tylko do odczytu w /data, a katalog kopii zapasowej w /backup, po czym zapisuje archiwum po stronie hosta. --rm usuwa kontener pomocniczy natychmiast po zakończeniu tar. Parametr :ro jest istotny, ponieważ w przypadku błędnego wpisania polecenia tar, źródło pozostaje bezpieczne. -C /data . zapewnia poprawne odtworzenie danych: przechowuje każdą ścieżkę w odniesieniu do katalogu głównego wolumenu. Użycie tar czf /backup/uploads.tar.gz /data spowodowałoby dodanie wiodącego data/ do każdej ścieżki, przez co przywracanie utworzyłoby /data/data wewnątrz wolumenu, a aplikacja widziałaby pusty katalog. Archiwum należy do użytkownika root, ponieważ tar został uruchomiony z uprawnieniami roota wewnątrz kontenera. Uruchom sudo chown "$USER" /srv/backups/myapp/uploads.tar.gz, jeśli stanowi to problem, i przeczytaj jak PUID i PGID decydują o własności plików, jeśli przywrócone pliki są nieczytelne dla aplikacji.
Wykonaj to polecenie dla każdego nazwanego wolumenu z osobna. W przypadku bind mounts kontener nie jest potrzebny: tar czf /srv/backups/myapp/config.tar.gz -C /srv/myapp/config . wykonuje to samo zadanie bezpośrednio na hoście.
Dla każdego wolumenu zdecyduj, czy aplikacja musi zostać zatrzymana. Archiwizacja na żywo wolumenu, w którym aplikacja nadpisuje pliki, może spowodować przechwycenie pliku w trakcie zapisu. W przypadku katalogu z przesłanymi plikami, gdzie dane są zapisywane raz, a następnie tylko odczytywane, ryzyko jest niewielkie. W każdym innym przypadku zatrzymaj usługę na czas kopiowania za pomocą docker compose stop app, a następnie docker compose start app. stop pozostawia kontenery i wolumeny w systemie, co jest pożądanym zachowaniem w tym scenariuszu; warto upewnić się, że różnica między down a stop jest zrozumiała przed wydaniem któregokolwiek z tych poleceń.
Nie traktuj archiwum tar wolumenu bazy danych jako pełnej kopii zapasowej bazy. Kopia zapasowa to zrzut bazy (dump). Archiwum wolumenu zatrzymanej bazy danych jest jedynie użytecznym sposobem na szybkie odtworzenie stanu, niczym więcej.
Kolejność operacji
- Skopiuj pliki compose oraz
.envdo katalogu kopii zapasowej. - Wykonaj zrzut bazy danych, gdy jest ona jeszcze uruchomiona.
- Zatrzymaj kontener aplikacji, jeśli jego wolumeny ulegają zmianie w miejscu.
- Zarchiwizuj każdy nazwany wolumen oraz każdy katalog montowany przez bind-mount.
- Uruchom wszystko, co zostało zatrzymane, a następnie potwierdź działanie za pomocą
docker compose ps. - Zapisz tagi obrazów oraz sumy kontrolne digest, na których działa stos.
- Skopiuj cały katalog kopii zapasowej poza ten serwer.
Krok 7 jest tym, który często odkłada się na później.
Przeniesienie kopii zapasowej poza serwer
Kopia zapasowa przechowywana na tym samym dysku co dane produkcyjne chroni jedynie przed błędami użytkownika. Awaria wolumenu, usunięcie serwera lub utrata dostępu do konta powoduje jednoczesną utratę obu kopii. Należy przesyłać katalog z danymi do zewnętrznej pamięci masowej zgodnie z harmonogramem i polityką retencji. Artykuł kopie zapasowe restic z VPS opisuje konfigurację repozytorium, flagi retencji oraz polecenie weryfikacji, dlatego te informacje nie będą tutaj powtarzane.
Narzędzie restic potrafi również odczytać zrzut bezpośrednio ze strumienia, co pozwala uniknąć zapisu niezaszyfrowanej bazy danych na dysku:
docker compose exec -T db sh -c 'pg_dump -U "$POSTGRES_USER" -d "$POSTGRES_DB" -Fc' \
| restic backup --stdin --stdin-filename db.dumpNiezależnie od wybranego narzędzia, należy umieścić harmonogram w timerze systemd lub zadaniu cron, a także skonfigurować powiadamianie o błędach. Skrypt kopii zapasowej, którego wyjście nie jest monitorowane, może przestać działać na wiele miesięcy bez wiedzy administratora.
Weryfikacja kopii zapasowej poprzez próbne przywracanie
Kopia zapasowa, która nie została przywrócona, jest jedynie hipotezą. Poniższa procedura przywraca dane do drugiego stosu działającego obok pierwszego, dzięki czemu środowisko produkcyjne pozostaje aktywne, a wprowadzane polecenia nie mają na nie wpływu.
Mechanizm opiera się na nazwie projektu. Docker Compose pobiera ją z nazwy katalogu i przypisuje do każdego tworzonego kontenera oraz wolumenu. Skopiowanie kopii zapasowej do nowego katalogu sprawia, że przywrócony stos automatycznie otrzymuje własne wolumeny.
sudo install -d -m 700 -o "$USER" -g "$(id -gn)" /srv/myapp-restore
cd /srv/myapp-restore
cp /srv/backups/myapp/compose.yaml /srv/backups/myapp/.env .Edytuj skopiowany plik compose, aby opublikowany port hosta nie kolidował z działającym stosem; użyj 18080:8080 zamiast 8080:8080 lub zmień zmienną, która ustawia go w skopiowanym .env. Następnie utwórz kontenery i ich puste wolumeny bez uruchamiania czegokolwiek:
docker compose create
docker volume ls --filter label=com.docker.compose.project=myapp-restoreDrugie polecenie powinno wyświetlić te same nazwy wolumenów co na produkcji, z prefiksem myapp-restore_. Wypełnij je, uruchom samodzielnie bazę danych i załaduj zrzut:
docker run --rm -v myapp-restore_uploads:/data -v /srv/backups/myapp:/backup \
alpine:3 tar xzf /backup/uploads.tar.gz -C /data
docker compose up -d db
docker compose exec -T db sh -c \
'pg_restore -U "$POSTGRES_USER" -d "$POSTGRES_DB" --clean --if-exists' \
< /srv/backups/myapp/db-2026-08-16.dump--clean --if-exists usuwa każdy obiekt przed jego ponownym utworzeniem, co sprawia, że przywracanie jest powtarzalne. Bez tego parametru drugie uruchomienie w bazie danych, która już zawiera te tabele, zakończy się błędem pg_restore: error: could not execute query: ERROR: relation "users" already exists.
Następnie uruchom resztę usług i sprawdź je tak, jak zrobiłby to użytkownik:
docker compose up -d --wait
docker compose exec -T db sh -c 'psql -U "$POSTGRES_USER" -d "$POSTGRES_DB" -c "\dt"'
docker compose logs --tail=50docker compose up -d --wait blokuje działanie do momentu, aż każda usługa zgłosi stan uruchomienia lub gotowości (healthy), a w przypadku niepowodzenia zwraca kod błędu, co pozwala na automatyzację tego kroku. Jeśli usługa nigdy nie osiągnie stanu gotowości, docker compose ps pokaże jej stan, a Compose healthchecks wyjaśnia, co oznacza ta kolumna. Następnie otwórz aplikację na alternatywnym porcie i zaloguj się na rzeczywiste konto. Zapisz jeden rekord i otwórz jeden plik znajdujący się w wolumenie. Ta para stanowi dowód: zrzut został przywrócony, wolumen został przywrócony, a oba elementy są ze sobą spójne. Próba, która potwierdza jedynie wyświetlenie strony logowania, nie stanowi dowodu na poprawność danych.
Po zakończeniu testu usuń środowisko testowe:
docker compose down -vTo jedyne miejsce, w którym -v jest właściwą flagą. W katalogu produkcyjnym to samo polecenie usunie wolumeny, które mają zostać zachowane.
Jak zaktualizować stos Compose
Należy zapoznać się z informacjami o wydaniu dla każdej wersji pomiędzy aktualnie używaną a docelową, wyszukując frazy breaking oraz migration. Projekty, które nie wspierają przeskakiwania kilku głównych wersji, informują o tym w dokumentacji, a nieudana migracja zgłasza błąd dopiero po częściowej zmianie schematu danych.
Przed wprowadzeniem jakichkolwiek zmian należy zarejestrować aktualny stan:
docker compose images
docker image inspect --format '{{index .RepoDigests 0}}' postgres:16.4docker compose images wyświetla obraz oraz tag używany obecnie przez każdą usługę. Wartość digest jest jedynym parametrem jednoznacznie identyfikującym obraz, ponieważ tag może w dowolnym momencie zostać przeniesiony na inną wersję.
Należy wykonać kopię zapasową zgodnie z instrukcjami z poprzednich sekcji i przenieść ją poza serwer. Dotyczy to również aktualizacji typu patch. Najbardziej kosztowne w skutkach są aktualizacje, do których użytkownicy przestają się przygotowywać.
Następnie należy przypiąć wersję w pliku compose, ponieważ latest nie jest wersją:
services:
db:
image: postgres:16.4W przypadku image: postgres:latest, docker compose pull pobiera obraz, na który aktualnie wskazuje dany tag, co uniemożliwia precyzyjne określenie, co było uruchomione wcześniej. Przypięty tag sprawia, że aktualizacja staje się jednowierszową zmianą, którą można zweryfikować w git diff i cofnąć poprzez ponowną edycję. W ten sam sposób należy przypiąć obraz aplikacji, pobierając dokładną wersję ze strony wydania projektu.
Pobierz i odtwórz kontenery:
docker compose pull
docker compose up -d --waitdocker compose up -d porównuje plik z uruchomionymi kontenerami i odtwarza tylko te usługi, których obraz lub konfiguracja uległy zmianie. Operacja ta nie wpływa na nazwane wolumeny, dzięki czemu nowy kontener uruchamia się na istniejących danych. Jest to cel operacji, a zarazem ryzyko, ponieważ podczas pierwszego uruchomienia nowej wersji zazwyczaj wykonywana jest migracja schematu.
Monitoruj proces:
docker compose ps
docker compose logs -f --tail=100 appKontener, który uległ awarii, wyświetla Exited (1) w kolumnie STATUS polecenia docker compose ps, a przyczyna błędu znajduje się w ostatnich liniach dziennika. Błędy migracji są tam wyraźnie widoczne, podczas gdy w innych miejscach pozostają ukryte. Gdy dzienniki przestaną generować nowe wpisy, należy zalogować się do aplikacji i przetestować jej działanie przez minutę.
Jeśli docker compose pull kończy się błędem no space left on device, najczęstszą przyczyną są stare warstwy obrazów, a usuwanie nieużywanych obrazów Docker pozwala odzyskać miejsce. Czyszczenie należy przeprowadzić po potwierdzeniu poprawności aktualizacji, a nie przed nią, ponieważ stare warstwy są niezbędne do szybkiego przywrócenia poprzedniej wersji.
Jak wykonać wycofanie zmian w przypadku nieudanej aktualizacji
Istnieją dwa przypadki, które wiążą się z zupełnie innymi kosztami. Jeśli nowa wersja nie zmieniła schematu bazy danych, wycofanie zmian sprowadza się do jednego polecenia: należy przywrócić stary tag w pliku compose i uruchomić docker compose up -d. Kontener zostanie zastąpiony, wolumeny pozostaną na swoim miejscu, a stary kod odczyta dane, które wcześniej zapisał.
Jeśli nowa wersja przeprowadziła migrację schematu, stary kod nie będzie już w stanie go odczytać. Migracje są tworzone z myślą o wykonywaniu ich w przód, a większość projektów nie dostarcza żadnych skryptów obniżających wersję. W rezultacie stara wersja uruchamia się, a następnie kończy działanie przy pierwszym zapytaniu do kolumny, która została zmieniona lub usunięta, generując błędy typu ERROR: column "avatar_url" does not exist. Jedyną drogą powrotną jest zrzut bazy danych wykonany przed pobraniem nowej wersji: należy przywrócić stary tag, usunąć wolumen bazy danych, utworzyć go ponownie jako pusty, zaimportować zrzut i uruchomić usługę. Bez takiego zrzutu powrót jest niemożliwy, co stanowi główny powód, dla którego kopię zapasową wykonuje się przed aktualizacją.
Główne wersje Postgres stanowią najbardziej krytyczny przypadek tego problemu i często zaskakują użytkowników, ponieważ błąd pojawia się już podczas aktualizacji, a nie dopiero przy próbie wycofania zmian. Format danych na dysku zmienia się wraz z każdym wydaniem głównym. Zmiana postgres:16.4 na postgres:17.2 i uruchomienie docker compose up -d spowoduje, że nowy serwer odmówi uruchomienia:
FATAL: database files are incompatible with server
DETAIL: The data directory was initialized by PostgreSQL version 16, which is not compatible with this version 17.2.Obraz nie wykonuje automatycznie pg_upgrade. Zalecaną ścieżką w ramach stosu Compose jest: zrzut, wymiana, przywrócenie. Należy wykonać zrzut, gdy stara wersja jeszcze działa, wykonać docker compose down, usunąć wolumen bazy danych, ustawić nowy tag, wykonać docker compose create w celu utworzenia świeżego, pustego katalogu danych, uruchomić bazę danych, zaimportować zrzut i uruchomić pozostałe usługi. Stary zrzut należy zachować do momentu, aż nowa wersja główna obsłuży rzeczywisty ruch przez co najmniej jeden dzień. Aktualizacje mniejsze w obrębie jednej wersji głównej, na przykład z 16.4 do 16.9, nie wymagają żadnych z tych kroków, ponieważ format danych pozostaje między nimi stabilny, a kontener po prostu się uruchamia.
Czy snapshoty VPS to kopia zapasowa?
Stanowią one uzupełnienie kopii zapasowej, a oba rozwiązania zawodzą w różnych sytuacjach. Snapshot kopiuje cały dysk na poziomie hypervisora, dzięki czemu przywraca całą maszynę w kilka minut, włącznie z elementami, o których zapomniano podczas tworzenia kopii zapasowej. Jest to właściwe narzędzie do jednego konkretnego zadania: aktualizacja uszkodziła serwer i wymagany jest powrót do stanu sprzed dwudziestu minut.
W każdym innym przypadku jest to narzędzie mało efektywne. Granularność obejmuje całą maszynę, więc odzyskanie jednej usuniętej tabeli wymaga przywrócenia całego serwera w innym miejscu i wyodrębnienia z niego tej tabeli. Okres przechowywania jest zazwyczaj krótki. Kopie zazwyczaj znajdują się na tym samym koncie dostawcy co serwer, więc utrata dostępu do konta oznacza jednoczesną utratę serwera i jego snapshotów. Ponadto snapshot działającej maszyny rejestruje bazę danych w trakcie zapisu, co wymusza na niej przeprowadzenie procedury crash recovery przy pierwszym uruchomieniu, przez co wszystkie transakcje będące w toku zostają utracone.
Należy stosować oba rozwiązania. Snapshot to przycisk „cofnij” na czas okna aktualizacji. Zrzut bazy danych (dump) to kopia, która przetrwa utratę konta. różnice między snapshotami a kopiami zapasowymi szczegółowo omawia, przed jakimi awariami chroni każde z tych rozwiązań. Ten sam katalog z kopiami zapasowymi sprawia, że przenoszenie stosu na nowy VPS staje się rutynowym zadaniem, a nie odtwarzaniem konfiguracji z pamięci.
Co może pójść nie tak i co zobaczysz
Flaga volumes przy poleceniu down. docker compose down -v usuwa nazwane wolumeny zadeklarowane w pliku, a Compose potwierdza to komunikatem Volume myapp_db_data Removed. Operacja jest nieodwracalna. Zwykłe docker compose down pozostawia je bez zmian. Używaj pełnej formy docker compose down --volumes, aby wymusić świadome wpisanie niszczącej flagi.
Zrzut bez ciągu magicznego. pg_restore: error: did not find magic string in file header oznacza, że plik nie jest archiwum. Najczęstszą przyczyną jest brak -T przy docker compose exec, ponieważ przy podłączonym TTY strumień jest tłumaczony w drodze do powłoki, co uszkadza binarny zrzut. Wykonaj zrzut ponownie z -T, a następnie sprawdź pierwsze pięć bajtów za pomocą head -c 5.
Hasło, którego nie można zmienić. FATAL: password authentication failed for user "appuser" po przywróceniu danych oznacza, że .env oraz katalog danych pochodzą z różnych momentów. Obraz ustawia hasło tylko podczas tworzenia pustego katalogu danych, więc późniejsza edycja .env nie zmienia niczego wewnątrz bazy danych. Przywróć pasujący .env lub zmień hasło bezpośrednio w bazie danych za pomocą ALTER USER.
Drugi, pusty wolumen. Docker tworzy wolumen na żądanie, więc docker run -v myapp_upload:/data przy braku s zapisuje dane do zupełnie nowego, pustego wolumenu i zgłasza sukces. docker volume ls pokazuje wtedy obie nazwy, z których jedna jest pusta. Kopiuj nazwy wolumenów z docker volume ls zamiast wpisywać je z pamięci.
Przywracanie danych na środowisku produkcyjnym. Uruchomienie poleceń przywracania w /srv/myapp zamiast w /srv/myapp-restore nadpisuje bieżące dane kopią zapasową, a polecenia wyglądają identycznie w obu lokalizacjach. Sprawdź pwd przed każdym poleceniem przywracania i przechowuj procedury testowe w osobnym katalogu.
FAQ
Czy docker compose down usuwa moje dane?
Nie. docker compose down usuwa kontenery oraz domyślną sieć, pozostawiając nienaruszone wolumeny nazwane oraz bind mounts. docker compose down -v usuwa wolumeny nazwane zadeklarowane w pliku, co jest operacją nieodwracalną. Bind mounts to katalogi na hoście, więc Compose nigdy ich nie usuwa. Jeśli celem jest zatrzymanie usług na czas tworzenia kopii zapasowej bez naruszania pozostałych elementów, należy użyć docker compose stop.
Czy mogę skopiować katalog danych Postgres zamiast uruchamiać pg_dump?
Tylko przy zatrzymanym kontenerze. Gdy serwer działa, pliki zmieniają się w trakcie operacji, a kopia może zawierać niespójny stan, którego nie da się odtworzyć. Kopia na poziomie plików jest również powiązana z konkretną wersją główną Postgres, więc nie uruchomi się pod inną wersją. Należy zatrzymać kontener, zarchiwizować wolumen, uruchomić go ponownie i traktować wynik jako szybką ścieżkę odtwarzania, a nie jedyną kopię zapasową. Zrzut (dump) jest kopią przenośną i to z niego należy przywracać dane.
Jak zaktualizować Postgres do nowej wersji głównej w Compose?
Zmiana tagu nie wystarczy. Nowy serwer odmówi uruchomienia na starym katalogu danych i zarejestruje błąd The data directory was initialized by PostgreSQL version 16, which is not compatible with this version 17.2. Należy wykonać pg_dump przy wciąż działającej starej wersji, następnie docker compose down, usunąć wolumen bazy danych, ustawić nowy tag, wykonać docker compose create w celu utworzenia nowego pustego wolumenu, uruchomić bazę danych i przywrócić do niej zrzut. Stary zrzut należy zachować do momentu, aż nowa wersja obsłuży rzeczywisty ruch.
Jak często wykonywać kopie zapasowe i jak długo je przechowywać?
Częstotliwość należy dostosować do ilości pracy, którą można zaakceptować do ponownego wykonania. Kopie nocne są odpowiednie dla stosów osobistych lub małych zespołów, dodatkowo należy wykonać jedną ręczną kopię bezpośrednio przed każdą aktualizacją. W zakresie retencji należy przechowywać wystarczającą historię, aby uwzględnić uszkodzenia, których nie zauważono od razu, ponieważ uszkodzona tabela wykryta w piątek nie zostanie naprawiona kopią z czwartku wieczorem. restic forget --keep-daily 7 --keep-weekly 4 --keep-monthly 6 --prune stanowi rozsądną politykę początkową. Niezależnie od harmonogramu, należy raz na kwartał przeprowadzić próbne przywracanie danych. Dopóki tego nie zrobisz, nie masz kopii zapasowych, a jedynie pliki.
Czy muszę zatrzymywać cały stos, aby wykonać kopię zapasową?
Zazwyczaj nie. Zrzut bazy danych jest spójny podczas pracy serwera, więc baza nie wymaga przestoju. Kwestią pozostają wolumeny. Jeśli aplikacja tylko dodaje pliki, na przykład w katalogu przesyłania, archiwizacja w czasie pracy jest wystarczająco bezpieczna. Jeśli aplikacja nadpisuje pliki w miejscu, należy zatrzymać tę konkretną usługę na czas kopiowania za pomocą docker compose stop app, a następnie uruchomić ją ponownie. Zatrzymanie aplikacji przy działającej bazie danych jest zazwyczaj najkrótszym bezpiecznym oknem serwisowym, jakie można zorganizować.