Kopie zapasowe są istotną i ważną częścią każdego planu odzyskiwania po awarii, tworzenie kopii zapasowych produkcyjnej bazy danych jest również podstawową i ważną częścią administracji PostgreSQL. Jednak administratorzy baz danych często nie sprawdzają, czy te kopie zapasowe są niezawodne.
Każda organizacja wykonuje kopie zapasowe bazy danych PostgreSQL w innej formie, niektóre mogą wykonywać kopię zapasową systemu plików (fizyczną) katalogów danych PostgreSQL (przy użyciu narzędzi takich jak Barman, PGBackRest), podczas gdy inne mogą wykonywać tylko kopie logiczne (przy użyciu pg_dump), a nawet inne mogą wykonywać migawki na poziomie bloków za pomocą narzędzi takich jak migawka EBS lub VMWare.
W tym blogu pokażemy, jak sprawdzić poprawność kopii zapasowej PostgreSQL, przywracając kopię zapasową do kontenera Docker za pomocą narzędzia pgBackRest do wykonywania i przywracania kopii zapasowej. Zakładamy, że masz już wiedzę na temat korzystania z PostgreSQL, Dockera i pgBackRest.
Dlaczego powinieneś używać Dockera?
Docker ułatwia automatyzację, a także ułatwia integrację naszego zadania PostgreSQL Backup Validation z narzędziami CI/CD, takimi jak CircleCI, Travis, GitLab lub Jenkins. Korzystanie z Dockera pozwala uniknąć czasu i zasobów, które musimy poświęcić na wprowadzenie nowego środowiska do testowania kopii zapasowej.
Konfiguracja wersji demonstracyjnej
Host | Rola | Zainstalowane Pakiety | Crontab |
węzeł-1 192.168.0.111 CentOS-7 | Podstawowa instancja Posgresql-11. Utworzono użytkownika i bazę danych „pgbench” i zainicjalizowano za pomocą tabel pgbench. | postgresql-11, pgbackrest-2.15 | Uruchamianie pgbench co 5 minut w celu symulacji obciążenia. |
węzeł-2 | Maszyna testowa - uruchomimy naszą walidację Dockera na tym hoście. | docker-ce-18.06, pgbackrest-2.15 | |
węzeł-3 192.168.0.113 CentOS-7 | pgBackRest Host repozytorium | pgbackrest-2.15 | Uruchamianie pgbackrest w celu wykonywania kopii zapasowej Incr co 4 godziny Diff backup każdego dnia Pełna kopia zapasowa raz w tygodniu |
Aby pgbackrest działał, ustawiłem bezhasłowy dostęp SSH między tymi węzłami.
Użytkownik „postgres” na węźle-1 i węźle-2 może logować się bez hasła do użytkownika „pgbackrest” na węźle-3.
[[email protected] ~]$ sudo -u postgres ssh [email protected] uptime
13:31:51 up 7:00, 1 user, load average: 0.00, 0.01, 0.05
[[email protected] ~]$ sudo -u postgres ssh [email protected] uptime
13:31:27 up 7:00, 1 user, load average: 0.00, 0.01, 0.05
Użytkownik „pgbackrest” na węźle 3 może logować się bez hasła do użytkownika „postgres” na węźle-1 i węźle-2.
[[email protected] ~]$ sudo -u pgbackrest ssh [email protected] uptime
13:32:29 up 7:02, 1 user, load average: 1.18, 0.83, 0.58
[[email protected] ~]$ sudo -u pgbackrest ssh [email protected] uptime
13:32:33 up 7:01, 1 user, load average: 0.00, 0.01, 0.05
Przegląd walidacji kopii zapasowych
Poniżej znajduje się krótki przegląd kroków, które będziemy wykonywać w ramach naszej weryfikacji kopii zapasowej PostgreSQL.
- Za pomocą polecenia przywracania pgbackrest pobierzemy najnowszą kopię zapasową z hosta repozytorium pgBackRest (node-3) do katalogu maszyny testowej (node-2) /var/lib/pgsql/11/data
- Podczas uruchamiania dockera montujemy katalog maszyny hosta (node-2) /var/lib/pgsql w kontenerze dockera i uruchamiamy demona postgres/postmaster z zamontowanego katalogu. Ujawnilibyśmy również port 5432 z kontenera do portu 15432 komputera hosta.
- Gdy kontener dockera zacznie działać, połączymy się z bazą danych PostgreSQL przez węzeł-2:15432 i sprawdzimy, czy wszystkie tabele i wiersze zostały przywrócone. Sprawdzilibyśmy również logi PostgreSQL, aby upewnić się, że podczas odzyskiwania nie ma komunikatu BŁĄD, a instancja również osiągnęła stan spójności.
Większość kroków sprawdzania poprawności kopii zapasowej zostanie wykonana na węźle hosta-2.
Tworzenie obrazu Docker
W węźle-2 utwórz plik Dockerfile i skompiluj obraz dockera „postgresql:11”. W poniższym pliku Dockerfile zastosujemy następujące zmiany w stosunku do obrazu podstawowego centos:7.
- Instalacja klientów postgresql-11, pgbackrest i openssh. Klienci Openssh są potrzebni do pgbackrest.
- Konfigurowanie pgbackrest - Potrzebujemy konfiguracji pgbackrest w obrazie, aby przetestować PITR, bez konfiguracji pgbackrest restore_command nie powiedzie się. W ramach konfiguracji pgbackrest
- Dodajemy adres IP hosta repozytorium pgbackrest (192.168.0.113) w pliku konfiguracyjnym /etc/pgbackrest.conf.
- Potrzebujemy również dostępu SSH bez hasła między kontenerem docker a hostem repozytorium pgbackrest. W tym celu kopiuję klucz SSH_PRIVATE_KEY, który już wygenerowałem i dodałem również jego klucz publiczny do hosta repozytorium pgbackrest (przykł[email protected]).
- VOLUME ["${PGHOME_DIR}"] — definiuje katalog kontenera /var/lib/pgsql jako punkt podłączenia. Podczas uruchamiania polecenia docker run określimy katalog hosta node-2 w tym punkcie montowania.
- USER postgres – każde polecenie uruchomione w kontenerze zostanie wykonane jako użytkownik postgres.
$ cat Dockerfile
FROM centos:7
ARG PGBACKREST_REPO_HOST
ARG PGHOME_DIR=/var/lib/pgsql
## Adding Postgresql Repo for CentOS7
RUN yum -y install https://download.postgresql.org/pub/repos/yum/reporpms/EL-7-x86_64/pgdg-redhat-repo-latest.noarch.rpm
## Installing PostgreSQL
RUN yum -y install postgresql11 postgresql11-server postgresql11-devel postgresql11-contrib postgresql11-libs pgbackrest openssh-clients
## Adding configuration for pgbackrest, needed for WAL recovery and replication.
RUN echo -ne "[global]\nrepo1-host=${PGBACKREST_REPO_HOST}\n\n[pgbench]\npg1-path=/var/lib/pgsql/11/data\n" > /etc/pgbackrest.conf
## Adding Private Key to the Docker. Docker container would use this private key for pgbackrest wal recovery.
RUN mkdir -p ${PGHOME_DIR}/.ssh && chmod 0750 ${PGHOME_DIR}/.ssh
COPY --chown=postgres:postgres ./SSH_PRIVATE_KEY ${PGHOME_DIR}/.ssh/id_rsa
RUN chmod 0600 ${PGHOME_DIR}/.ssh/id_rsa
RUN echo -ne "Host ${PGBACKREST_REPO_HOST}\n\tStrictHostKeyChecking no\n" >> ${PGHOME_DIR}/.ssh/config
## Making "/var/lib/pgsql" as a mountable directory in the container
VOLUME ["${PGHOME_DIR}"]
## Setting postgres as the default user for any remaining commands
USER postgres
Mamy teraz dwa pliki, Dockerfile używany przez kompilację dockera i SSH_PRIVATE_KEY, które zostaną skopiowane do obrazu dockera.
$ ls
Dockerfile SSH_PRIVATE_KEY
Uruchom poniższe polecenie na węźle-2, aby zbudować nasz obraz dockera. W poleceniu wspomniałem o adresie IP hosta repozytorium pgbackrest, który zostanie użyty w parametrze pgbackrest „repo-host”.
$ docker build --no-cache -t postgresql:11 --build-arg PGBACKREST_REPO_HOST=192.168.0.113 .
Sending build context to Docker daemon 230.4kB
Step 1/12 : FROM centos:7
---> 9f38484d220f
Step 2/12 : ARG PGBACKREST_REPO_HOST
---> Running in 8b7b36c6f151
Removing intermediate container 8b7b36c6f151
---> 31510e46e286
Step 3/12 : ARG PGHOME_DIR=/var/lib/pgsql
...
Step 4/12 : RUN yum -y install https://download.postgresql.org/pub/repos/yum/reporpms/EL-7-x86_64/pgdg-redhat-repo-latest.noarch.rpm
...
...
Step 12/12 : USER postgres
---> Running in c91abcf46440
Removing intermediate container c91abcf46440
---> bebce78df5ae
Successfully built bebce78df5ae
Successfully tagged postgresql:11
Upewnij się, że obraz został pomyślnie utworzony i sprawdź, czy obraz „postgresql:11” został utworzony niedawno, jak pokazano poniżej.
$ docker image ls postgresql:11
REPOSITORY TAG IMAGE ID CREATED SIZE
postgresql 11 2e03ed2a5946 3 minutes ago 482MB
Przywracanie kopii zapasowej PostgreSQL
Przywrócimy teraz naszą kopię zapasową PostgreSQL utrzymywaną w repozytorium kopii zapasowych pgbackrest host node-3.
Poniżej znajduje się plik konfiguracyjny pgbackrest obecny na hoście node-2 i wspomniałem o node-3 jako hoście repozytorium pgbackrest. Katalog wymieniony w param pg1-ścieżka to miejsce, w którym zostanie przywrócony katalog danych PostgreSQL.
[[email protected] ~]$ cat /etc/pgbackrest.conf
[global]
log-level-file=detail
repo1-host=node-3
[pgbench]
pg1-path=/var/lib/pgsql/11/data
Za pomocą poniższego polecenia przywracania pgbackrest, katalog danych postgresql zostanie przywrócony na node-2:/var/lib/pgsql/11/data.
Aby sprawdzić poprawność PITR za pomocą kopii zapasowej pgbackrest, ustawiłem --type=time --target='2019-07-30 06:24:50.241352+00', tak aby odzyskiwanie WAL zatrzymało się przed wspomniany czas.
[[email protected] ~]$ sudo -u postgres bash -c "/usr/bin/pgbackrest --type=time --target='2019-07-30 06:24:50.241352+00' --target-action=promote --recovery-option='standby_mode=on' --stanza=pgbench restore"
Powyższe polecenie może zająć trochę czasu w zależności od rozmiaru kopii zapasowej i przepustowości sieci. Po przywróceniu sprawdź rozmiar katalogu danych, a także sprawdź plik recovery.conf.
[[email protected] ~]$ sudo -u postgres du -sh /var/lib/pgsql/11/data
2.1G /var/lib/pgsql/11/data
[[email protected] ~]$ sudo -u postgres cat /var/lib/pgsql/11/data/recovery.conf
standby_mode = 'on'
restore_command = '/usr/bin/pgbackrest --stanza=pgbench archive-get %f "%p"'
recovery_target_time = '2019-07-30 06:24:50.241352+00'
Wyłącz tryb archiwizacji dla kontenera dockera PostgreSQL.
[[email protected] ~]$ sudo -u postgres bash -c "echo 'archive_mode = off' >> /var/lib/pgsql/11/data/postgresql.auto.conf"
Uruchom kontener docker z obrazem „postgresql:11”. W poleceniu jesteśmy
-
Ustawianie nazwy kontenera jako „pgbench”
-
Montowanie katalogu hosta platformy docker (node-2) /var/lib/psql do katalogu kontenera platformy docker /var/lib/psql
-
Ujawnianie portu 5432 kontenera na port 15432 w węźle-2.
-
Uruchamianie demona postgres za pomocą polecenia /usr/pgsql-11/bin/postmaster -D /var/lib/pgsql/11/data
[[email protected] ~]$ docker run --rm --name "pgbench" -v /var/lib/pgsql:/var/lib/pgsql -p 15432:5432 -d postgresql:11 /usr/pgsql-11/bin/postmaster -D /var/lib/pgsql/11/data
e54f2f65afa13b6a09236a476cb1de3d8e499310abcec2b121a6b35611dac276
Sprawdź, czy kontener „pgbench” został utworzony i uruchomiony.
[[email protected] ~]$ docker ps -f name=pgbench
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
e54f2f65afa1 postgresql:11 "/usr/pgsql-11/bin/p…" 34 seconds ago Up 33 seconds 0.0.0.0:15432->5432/tcp pgbench
Weryfikacja PostgreSQL
Ponieważ katalog hosta /var/lib/pgsql jest współdzielony z kontenerem docker, logi generowane przez usługę PostgreSQL są również widoczne z węzła 2. Sprawdź dzisiejszy dziennik, aby upewnić się, że PostgreSQL uruchomił się poprawnie bez żadnych BŁĘDÓW i upewnij się, że obecne są poniższe wiersze dziennika.
[[email protected] ~]$ sudo -u postgres tailf /var/lib/pgsql/11/data/log/postgresql-Tue.csv
..
2019-07-30 06:38:34.633 UTC,,,7,,5d3fe5e9.7,5,,2019-07-30 06:38:33 UTC,1/0,0,LOG,00000,"consistent recovery state reached at E/CE000210",,,,,,,,,""
2019-07-30 06:38:34.633 UTC,,,1,,5d3fe5e9.1,2,,2019-07-30 06:38:33 UTC,,0,LOG,00000,"database system is ready to accept read only connections",,,,,,,,,""
2019-07-30 06:38:35.236 UTC,,,7,,5d3fe5e9.7,6,,2019-07-30 06:38:33 UTC,1/0,0,LOG,00000,"restored log file ""000000010000000E000000CF"" from archive",,,,,,,,,""
2019-07-30 06:38:36.210 UTC,,,7,,5d3fe5e9.7,7,,2019-07-30 06:38:33 UTC,1/0,0,LOG,00000,"restored log file ""000000010000000E000000D0"" from archive",,,,,,,,,""
...
2019-07-30 06:39:57.221 UTC,,,7,,5d3fe5e9.7,37,,2019-07-30 06:38:33 UTC,1/0,0,LOG,00000,"recovery stopping before commit of transaction 52181192, time 2019-07-30 06:25:01.576689+00",,,,,,,,,""
...
2019-07-30 06:40:00.682 UTC,,,7,,5d3fe5e9.7,47,,2019-07-30 06:38:33 UTC,1/0,0,LOG,00000,"archive recovery complete",,,,,,,,,""
Komunikat „spójny stan odzyskiwania osiągnięty w E/CE000210” wskazuje, że z katalogiem danych kopii zapasowej pgbackrest byliśmy w stanie osiągnąć spójny stan.
Komunikat „zakończono odzyskiwanie archiwów” wskazuje, że jesteśmy w stanie odtworzyć plik WAL, którego kopię zapasową utworzono za pomocą pgbackrest, i możemy go odzyskać bez żadnych problemów.
Połącz się z instancją postgresql przez lokalny port 15432 i zweryfikuj liczbę tabel i wierszy.
[[email protected] ~]$ sudo -iu postgres /usr/pgsql-11/bin/psql -p 15432 -h localhost -U pgbench
Password for user pgbench:
psql (11.4)
Type "help" for help.
pgbench=> \dt
List of relations
Schema | Name | Type | Owner
--------+------------------+-------+---------
public | pgbench_accounts | table | pgbench
public | pgbench_branches | table | pgbench
public | pgbench_history | table | pgbench
public | pgbench_tellers | table | pgbench
(4 rows)
pgbench=> select * from pgbench_history limit 1;
tid | bid | aid | delta | mtime | filler
-----+-----+---------+-------+----------------------------+--------
98 | 3 | 2584617 | 507 | 2019-07-30 06:20:01.412226 |
(1 row)
pgbench=> select max(mtime) from pgbench_history ;
max
----------------------------
2019-07-30 06:22:01.402245
(1 row)
pgbench=> select count(1) from pgbench_history ;
count
-------
90677
(1 row)
pgbench=> select count(1) from pgbench_accounts ;
count
----------
10000000
(1 row)
Przywróciliśmy teraz naszą kopię zapasową PostgreSQL w kontenerze dockera, a także zweryfikowaliśmy PITR. Po sprawdzeniu poprawności kopii zapasowej możemy zatrzymać kontener i usunąć katalog danych.
[[email protected] ~]$ docker stop pgbench
pgbench
[[email protected] ~]$ sudo -u postgres bash -c "rm -rf /var/lib/pgsql/11/data && mkdir -p /var/lib/pgsql/11/data && chmod 0700 /var/lib/pgsql/11/data"
Wnioski
W tym blogu zademonstrowałem walidację kopii zapasowych przy użyciu małej bazy danych na małej maszynie wirtualnej VirtualBox. Z tego powodu sprawdzanie poprawności kopii zapasowej zostało zakończone w ciągu zaledwie kilku minut. Należy pamiętać, że w środowisku produkcyjnym należy wybrać odpowiednią maszynę wirtualną z wystarczającą ilością pamięci, procesora i dysku, aby umożliwić pomyślne zakończenie weryfikacji kopii zapasowej. Możesz także zautomatyzować cały proces walidacji w skrypcie bash lub nawet poprzez integrację z potokiem CI/CD, dzięki czemu możesz regularnie sprawdzać poprawność naszych kopii zapasowych PostgreSQL.