Snapshot, backup czy klon VPS: różnice i zastosowania
Dowiedz się, dlaczego snapshot nie jest kopią zapasową i kiedy stosować poszczególne metody ochrony danych. Sprawdź, co zmienić w konfiguracji po sklonowaniu instancji VPS.
Czym w rzeczywistości jest snapshot, kopia zapasowa i klon
Snapshot VPS to obraz dysku serwera, przechowywany przez dostawcę w jego infrastrukturze, w ramach konta użytkownika. Kopia zapasowa to niezależna kopia danych, którą można przywrócić w innym miejscu bez udziału dostawcy przechowującego oryginał. Klon to nowa instancja wdrożona ze snapshotu, która zaczyna działanie jako dokładna kopia oryginału, łącznie z jego tożsamością.
Rozwiązują one różne problemy. Snapshot pozwala wycofać skutki nieudanej aktualizacji w kilka minut, ale nie chroni w przypadku zamknięcia konta. Kopia zapasowa przetrwa awarię lub likwidację dostawcy, a jej przywrócenie trwa dłużej, ponieważ wymaga wcześniejszego przygotowania maszyny. Klon pozwala uzyskać drugi działający serwer w jednym kroku, co skutkuje istnieniem dwóch maszyn przekonanych, że są tym samym urządzeniem.
Dlaczego snapshot VPS nie jest kopią zapasową
Problemem jest domena awarii, a nie jakość obrazu. Snapshot znajduje się na platformie pamięci masowej dostawcy, zazwyczaj w tym samym regionie co serwer, z którego pochodzi, i zawsze w ramach tego samego konta. Jedno zdarzenie może zniszczyć serwer wraz z jego snapshotem.
- Konto zostaje zawieszone, płatność nie dochodzi do skutku lub ktoś przejmuje dane logowania.
- Osoba lub skrypt z dostępem do API usuwa instancję. U wielu dostawców usunięcie instancji powoduje usunięcie powiązanych z nią snapshotów. Należy zapoznać się z dokumentacją dostawcy przed założeniem, że działa to inaczej.
- Region ma awarię i wszystko, co się w nim znajduje, staje się jednocześnie niedostępne.
- Proces działający z uprawnieniami root na serwerze odnajduje token API dostawcy pozostawiony w
/rooti usuwa snapshoty, zanim jeszcze zmodyfikuje dysk.
Kopia zapasowa to kopia, która przetrwa wszystkie cztery powyższe scenariusze. Testem jest jedno pytanie: jeśli konto u dostawcy przestałoby istnieć dzisiaj po południu, co można by jeszcze przywrócić i gdzie? Wszystko, co nie przechodzi tego testu, jest jedynie narzędziem do wycofywania zmian. Należy nadal wykonywać snapshoty, ponieważ nic nie przywraca danych szybciej. Następnie należy przechowywać drugą kopię na nośniku, nad którym dostawca nie ma kontroli.
Stara zasada pozostaje aktualna: trzy kopie danych, na dwóch rodzajach nośników, z których jeden znajduje się poza platformą. Snapshot dostawcy oraz repozytorium kopii zapasowych restic na oddzielnej infrastrukturze realizują to założenie przy użyciu dwóch niezależnych elementów.
Dlaczego migawka działającej bazy danych może przywrócić uszkodzone dane
Migawka dostawcy kopiuje urządzenie blokowe w stanie z jednej konkretnej chwili. Nie prosi aplikacji o wcześniejsze zatrzymanie i nie widzi danych znajdujących się w pamięci podręcznej stron (page cache). Obraz jest więc co najwyżej spójny w przypadku awarii (crash-consistent). Wygląda dokładnie tak, jak wyglądałby dysk po nagłym odcięciu zasilania.
Większość stosu oprogramowania radzi sobie z taką sytuacją. Systemy ext4 oraz XFS odtwarzają swój dziennik podczas montowania, więc system plików uruchamia się poprawnie. PostgreSQL odtwarza swój dziennik transakcji (write-ahead log) przy starcie, co jest odnotowywane w logach:
LOG: database system was not properly shut down; automatic recovery in progressInnoDB wykonuje to samo i wyświetla własne komunikaty o odzyskiwaniu po awarii podczas uruchamiania. Takie odzyskiwanie jest elementem standardowego działania bazy danych, dlatego migawka pojedynczego wolumenu z nieobciążonej bazy PostgreSQL lub MySQL zazwyczaj przywraca się bez problemów.
Przypadki, w których spójność po awarii jest niewystarczająca, są realne i najbardziej dotkliwe. Jeśli dane rozciągają się na dwa wolumeny, dysk główny i oddzielny dysk z danymi są kopiowane w różnych momentach. W efekcie pliki danych i katalog dziennika mogą być niespójne, a proces odzyskiwania nie ma poprawnych danych do przetworzenia. Każdy plik, który aplikacja zapisuje bez wywołania fsync, na przykład częściowo odebrany plik lub plik kolejki, może zostać przywrócony jako ucięty. Wszystko, co aplikacja przechowuje w pamięci i zapisuje na dysk okresowo, po prostu nie znajduje się w obrazie.
Dlatego przed wykonaniem migawki należy zapisać zrzut danych na dysk. Wtedy obraz zawiera jeden plik, co do którego masz pewność, że jest wewnętrznie spójny, niezależnie od stanu aktywnych plików danych.
sudo -u postgres pg_dumpall --clean --file=/var/backups/pg-$(date +%F).sql
sudo mysqldump --single-transaction --routines --all-databases > /var/backups/mysql-$(date +%F).sql--single-transaction tworzy spójny zrzut tabel InnoDB bez blokowania operacji zapisu, ponieważ zrzut odbywa się w ramach jednej transakcji o poziomie izolacji repeatable-read. Nie obejmuje on tabel MyISAM, które wymagają blokady lub zatrzymania serwera. Przed zaufaniem zrzutowi sprawdź, czy nie jest on pusty ani ucięty: tail -n 1 /var/backups/mysql-$(date +%F).sql dla pełnego zrzutu mysqldump kończy się komentarzem Dump completed.
Jeśli posiadasz oddzielny wolumen z danymi, możesz go zamrozić na czas trwania migawki:
sudo fsfreeze -f /srv
# take the snapshot from your provider's panel or API
sudo fsfreeze -u /srvZamrażaj tylko wolumen z danymi. Nigdy nie zamrażaj /. Zamrożony główny system plików blokuje każdy zapis w systemie, w tym powłokę, której użyłbyś do wpisania polecenia odblokowania. W rezultacie zablokujesz sobie dostęp do systemu i będziesz zmuszony wykonać twardy reset.
Część zdalna: restic lub Borg
Migawka to szybka część procesu. Kopia zdalna to część, która przetrwa awarię dostawcy. restic jest dobrym wyborem domyślnym, ponieważ wykonuje deduplikację, szyfrowanie po stronie klienta i zapisuje dane w pamięci obiektowej zgodnej z S3, przez SFTP lub w zwykłym katalogu. VPS z pamięcią masową jako cel zdalny sprawdza się tutaj dobrze, ponieważ repozytoria kopii zapasowych wymagają pojemności, a nie wysokich IOPS.
sudo apt update && sudo apt install -y restic
sudo sh -c 'umask 077; head -c 24 /dev/urandom | base64 > /root/.restic-pass'
sudo chmod 600 /root/.restic-pass
sudo cat /root/.restic-passSkopiuj to hasło do menedżera haseł już teraz, na urządzeniu innym niż ten serwer. Repozytorium restic nie może zostać otwarte bez niego i nie istnieje ścieżka odzyskiwania. Jeśli jedyna kopia hasła znajdowała się na utraconym serwerze, kopia zapasowa jest tylko zaszyfrowanym szumem.
export RESTIC_REPOSITORY="s3:https://s3.example.com/vps-backups"
export RESTIC_PASSWORD_FILE=/root/.restic-pass
export AWS_ACCESS_KEY_ID="..."
export AWS_SECRET_ACCESS_KEY="..."
sudo -E restic init
sudo -E restic backup /etc /srv /var/backups
sudo -E restic snapshotssudo -E przechowuje te zmienne, ponieważ bez tego root otrzymuje czyste środowisko, a restic zgłasza brak określonej lokalizacji repozytorium. restic snapshots powinno wyświetlić ostatnio wykonane uruchomienie wraz z hostem i ścieżkami. Weryfikuj repozytorium zgodnie z harmonogramem i odczytuj część danych, zamiast sprawdzać tylko strukturę:
sudo -E restic check --read-data-subset=5%
sudo -E restic restore latest --target /tmp/restore-check
sudo -E restic forget --keep-daily 7 --keep-weekly 4 --keep-monthly 6 --pruneNietestowana kopia zapasowa to tylko przypuszczenie. Przywróć dane na inny VPS przynajmniej raz, zmierz czas tej operacji i zapisz go, ponieważ ta liczba jest Twoim rzeczywistym celem odzyskiwania. Borg to drugie solidne rozwiązanie, które przechowuje repozytorium przez SSH zamiast w pamięci obiektowej; różnice między nimi opisano w porównaniu restic i BorgBackup.
Co należy naprawić przed uruchomieniem sklonowanego VPS w środowisku produkcyjnym
Klon jest dokładną kopią. To jego główna zaleta, ale i problem. Wszystko, co czyniło oryginał unikalnym, zostaje powielone, co prowadzi do konfliktów.
Wygeneruj ponownie klucze hosta SSH. Klon zawiera pliki /etc/ssh/ssh_host_* oryginału, więc oba serwery przedstawiają się tą samą tożsamością. Każdy, kto kontroluje jeden serwer, może podszyć się pod drugi przed każdym klientem, który zaakceptował ten klucz. SSH nie wyświetli ostrzeżenia, ponieważ klucz jest zgodny z oczekiwaniami klienta.
sudo rm -f /etc/ssh/ssh_host_*
sudo ssh-keygen -A
sudo systemctl restart ssh
ssh-keygen -lf /etc/ssh/ssh_host_ed25519_key.pubssh-keygen -A zapisuje nowy klucz każdego typu oczekiwanego przez demona. Odcisk palca (fingerprint) uzyskany ostatnim poleceniem musi różnić się od tego z oryginału. Bieżąca sesja przetrwa restart, ponieważ ponowne uruchomienie sshd nie zrywa ustanowionych połączeń. Wykonaj to, zanim ktokolwiek połączy się z klonem. Jeśli odłożysz to na później, każdy klient, który już zaufał odziedziczonemu kluczowi, otrzyma WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! i będzie musiał najpierw wykonać ssh-keygen -R <host>.
Zresetuj identyfikator maszyny. /etc/machine-id to unikalny identyfikator generowany przez systemd raz, przy pierwszym uruchomieniu, który klon dziedziczy.
sudo truncate -s 0 /etc/machine-id
sudo rm -f /var/lib/dbus/machine-id
sudo ln -s /etc/machine-id /var/lib/dbus/machine-id
sudo rebootPusty plik /etc/machine-id instruuje systemd, aby wygenerował nową wartość przy następnym rozruchu, dlatego plik należy wyczyścić, a nie usuwać. Duplikacja tego identyfikatora powoduje dwa problemy. W obrazach pobierających adres przez DHCP, systemd-networkd domyślnie wywodzi identyfikator klienta DHCP z identyfikatora maszyny. W rezultacie oba klony proszą o dzierżawę jako ten sam klient, a serwer przydziela im ten sam adres. Ponadto journald oznacza każdy wpis identyfikatorem maszyny, więc centralny kolektor logów przypisuje wpisy z obu serwerów do jednej maszyny. Po restarcie wykonaj cat /etc/machine-id i sprawdź, czy wartość uległa zmianie.
Zmień nazwę hosta.
sudo hostnamectl set-hostname web-02
grep 127.0.1.1 /etc/hostshostnamectl zapisuje /etc/hostname i natychmiast stosuje nazwę. Nie modyfikuje jednak /etc/hosts, więc edytuj linię 127.0.1.1, aby była zgodna. W przeciwnym razie nowa nazwa nie zostanie rozpoznana, a każde wywołanie sudo będzie oczekiwać na nieudane zapytanie i wyświetli sudo: unable to resolve host web-02: Name or service not known.
Zmień wszystkie poświadczenia zaszyte w obrazie. Klon posiada sekrety oryginału, więc teraz dwie maszyny mogą działać jako oryginał. Przejrzyj pliki authorized_keys SSH, tokeny API dostawców i DNS, pliki .env aplikacji, hasła do baz danych, klucze prywatne TLS, tokeny rejestracji monitoringu oraz hasło do repozytorium restic. Poniższe polecenie pozwala znaleźć większość z nich:
sudo grep -rIlE 'PASSWORD|SECRET|TOKEN|API_KEY' /etc /srv /opt /home 2>/dev/null
sudo find / -name '.env' -not -path '/proc/*' -not -path '/sys/*' 2>/dev/nullJeśli klon jest kopią testową, która nie będzie obsługiwać ruchu, lepiej unieważnij poświadczenia zamiast je zmieniać. Środowisko stagingowe z aktywnym produkcyjnym tokenem API to w rzeczywistości środowisko produkcyjne z gorszymi poprawkami bezpieczeństwa.
Wyłącz zadania, które teraz uruchamiają się dwukrotnie. Dwa serwery z tym samym crontabem odpytują te same systemy zewnętrzne w tej samej minucie.
systemctl list-timers --all
sudo crontab -l
sudo ls -l /etc/cron.d /etc/cron.dailyPrzypadek restic wymaga uwagi, ponieważ prowadzi do uszkodzenia polityki retencji, a nie tylko do błędów. restic oznacza każdy snapshot nazwą hosta, a restic forget --keep-daily 7 stosuje politykę dla każdego hosta z osobna. Dwie maszyny zgłaszające tę samą nazwę hosta są traktowane jako jeden host, więc siedem "dziennych" snapshotów może pochodzić wyłącznie z klona, podczas gdy snapshoty oryginału zostaną usunięte. Napraw nazwę hosta przed pierwszym uruchomieniem kopii zapasowej lub zatrzymaj timer na klonie. W przypadku certbot sytuacja jest prostsza: dwa serwery odnawiające te same nazwy przekraczają limit certyfikatów urzędu certyfikacji dla danego zestawu nazw, a proces kończy się błędem o zbyt dużej liczbie wydanych certyfikatów. Klon, którego domena nadal wskazuje na oryginał, i tak nie przejdzie wyzwania HTTP, więc wyłącz tam odnawianie.
Skonfiguruj agenta monitoringu. Większość agentów identyfikuje się nazwą hosta lub plikiem identyfikatora zapisanym podczas instalacji. Dwaj agenci zgłaszający się jako jeden host mieszają metryki w jednej serii danych. Wykresy CPU pokazują wtedy wartości, których nie wygenerowała żadna pojedyncza maszyna, a alerty stają się niestabilne. Zatrzymaj i usuń agenta na klonie lub zarejestruj go ponownie pod nową nazwą hosta zgodnie z dokumentacją dostawcy.
Sprawdź konfigurację sieci pod kątem adresu oryginału. Jeśli obraz zawiera statyczny adres w netplan, klon przejmuje adres IP należący do innej maszyny.
ip -br addr
sudo grep -r addresses /etc/netplan/Wyczyść stan cloud-init, jeśli klon ma stać się szablonem.
sudo cloud-init clean --logsTo usuwa stan cloud-init w /var/lib/cloud, dzięki czemu przy następnym uruchomieniu ponownie wykonają się moduły pierwszego rozruchu, w tym generowanie kluczy hosta SSH, jeśli ich brakuje. Niektóre wersje oferują również flagę do resetowania identyfikatora maszyny. Uruchom cloud-init clean --help na własnym obrazie, aby sprawdzić, co obsługuje Twoja wersja, zamiast polegać na listach flag z innych źródeł.
Kiedy stosować poszczególne rozwiązania
Wycofywanie ryzykownych aktualizacji: wykonaj snapshot. Wykonaj go na kilka minut przed wprowadzeniem zmian, przeprowadź aktualizację, a w razie niepowodzenia przywróć obraz. Przywrócenie powoduje utratę wszystkich zapisów dokonanych od momentu wykonania snapshotu, więc w przypadku serwera obsługującego aktywny ruch, najpierw wykonaj zrzut bazy danych i określ dokładnie zakres utraconych danych. W przypadku do-release-upgrade na maszynie, którą można wyłączyć na dziesięć minut, snapshot stanowi kompletny plan działania.
Migracja na wyższy plan: wdróż klon. Zbuduj klon ze snapshotu na większym planie, przejdź przez powyższą listę weryfikacji tożsamości, a następnie przetestuj go na własnym adresie IP przed skierowaniem jakiegokolwiek ruchu. Skróć czas TTL dla DNS z jednodniowym wyprzedzeniem, aby przełączenie było szybkie, i utrzymuj działanie oryginału, dopóki nowa maszyna nie obsłuży rzeczywistego ruchu. Najpierw potwierdź, czy większy plan faktycznie przyspiesza pracę dla danego obciążenia, używając tej samej metody testów wydajnościowych na obu serwerach, ponieważ większa liczba vCPU na bardziej obciążonym sprzęcie nie zawsze oznacza ulepszenie.
Tworzenie szablonu: wykonaj snapshot oczyszczonej maszyny. Zainstaluj i zabezpiecz jeden serwer, a następnie usuń wszystkie unikalne dane przed wykonaniem obrazu. Usuń klucze hosta, wyczyść machine ID, usuń dane osobowe authorized_keys, poświadczenia oraz zresetuj konfigurację cloud-init. Wykonaj snapshot. Każda instancja wdrożona na jego podstawie wygeneruje własną tożsamość przy pierwszym uruchomieniu, dzięki czemu powyższa lista kontrolna przestaje być potrzebna. Połącz to z standardowymi pierwszymi dziesięcioma minutami na nowym VPS, aby szablon zawierał już pracę, którą w przeciwnym razie trzeba by powtarzać.
FAQ
Czy snapshot VPS jest kopią zapasową?
Nie, ponieważ współdzieli on domenę awarii z serwerem, z którego pochodzi. Snapshot znajduje się w pamięci masowej dostawcy, w ramach Twojego konta, zazwyczaj w tym samym regionie. Zawieszenie konta, kradzież klucza API lub przypadkowe usunięcie instancji może spowodować usunięcie serwera wraz z jego snapshotami w jednej operacji, a u wielu dostawców usunięcie instancji domyślnie usuwa również jej snapshoty. Snapshot jest najszybszą metodą przywracania stanu, więc należy je wykonywać, ale należy również przechowywać drugą, zaszyfrowaną kopię na infrastrukturze, której dostawca nie kontroluje.
Czy muszę zatrzymać bazę danych przed wykonaniem snapshotu?
Nie zawsze, ale trzeba zaakceptować stan, który się uzyska. Snapshot dostawcy jest spójny w przypadku awarii (crash-consistent), co oznacza, że obraz odzwierciedla stan dysku po nagłym odcięciu zasilania. PostgreSQL i InnoDB odzyskują spójność przy starcie, a PostgreSQL rejestruje database system was not properly shut down; automatic recovery in progress podczas tego procesu. Odzyskanie danych nie jest gwarantowane, gdy dane obejmują dwa wolumeny, których snapshoty wykonano w różnych momentach, lub gdy aplikacja zapisuje dane bez fsync. Należy najpierw zapisać pg_dumpall lub mysqldump --single-transaction na dysk, aby obraz zawierał jeden plik, co do którego istnieje pewność, że jest spójny.
Dlaczego dwa sklonowane serwery rywalizują o ten sam adres IP?
Ponieważ współdzielą one /etc/machine-id. W obrazach korzystających z DHCP, systemd-networkd domyślnie buduje identyfikator klienta DHCP na podstawie machine ID, więc oba klony żądają dzierżawy jako ten sam klient, a serwer DHCP oferuje obu ten sam adres. Należy wyzerować /etc/machine-id, usunąć /var/lib/dbus/machine-id, utworzyć dowiązanie symboliczne do /etc/machine-id i zrestartować system, aby systemd wygenerował nową wartość. Inną częstą przyczyną jest statyczny adres zapisany w /etc/netplan/, który klon skopiował w niezmienionej formie; należy to sprawdzić za pomocą ip -br addr.
Jaki jest najszybszy sposób sprawdzenia, czy klon jest gotowy do pracy produkcyjnej?
Należy porównać cztery elementy z oryginałem. Uruchom ssh-keygen -lf /etc/ssh/ssh_host_ed25519_key.pub na obu maszynach i potwierdź, że odciski palców (fingerprints) są różne. Uruchom cat /etc/machine-id na obu i potwierdź, że wartości są różne. Uruchom hostnamectl status i potwierdź, że nazwa jest nowa i poprawnie rozwiązywana, dzięki czemu sudo nie zgłosi ostrzeżenia. Następnie uruchom systemctl list-timers --all i zatrzymaj każdy timer, który komunikuje się ze współdzielonym systemem, taki jak kopie zapasowe, odnawianie certyfikatów lub agent monitorujący, dopóki nie zostanie ustalone, która maszyna odpowiada za dane zadanie.