I backup sono la parte vitale e importante di qualsiasi piano di ripristino di emergenza, anche l'esecuzione di backup del database di produzione è una parte fondamentale e importante dell'amministrazione di PostgreSQL. Tuttavia, i DBA spesso non convalidano l'affidabilità di tali backup.
Ogni organizzazione esegue backup del database PostgreSQL in forma diversa, alcune possono eseguire un backup (fisico) del file system delle directory dei dati PostgreSQL (utilizzando strumenti come Barman, PGBackRest) mentre altre possono eseguire solo backup logici (utilizzando pg_dump) e anche altri possono acquisire istantanee a livello di blocco utilizzando strumenti come EBS o VMWare snapshot.
In questo blog, ti mostreremo come convalidare il tuo backup PostgreSQL ripristinando il backup su un contenitore Docker utilizzando lo strumento pgBackRest per eseguire e ripristinare il backup. Partiamo dal presupposto che tu abbia già delle conoscenze su come utilizzare PostgreSQL, Docker e pgBackRest.
Perché dovresti usare Docker?
Docker semplifica l'automazione, semplifica anche il lavoro di integrazione della nostra attività di convalida del backup PostgreSQL in strumenti CI/CD come CircleCI, Travis, GitLab o Jenkins. L'utilizzo di Docker evita il tempo e le risorse che dobbiamo spendere per portare il nuovo ambiente per testare il backup.
Impostazione demo
Ospite | Ruolo | Installato Pacchetti | Crontab |
node-1 192.168.0.111 CentOS-7 | Istanza primaria Posgresql-11. Creato utente e database “pgbench” e inizializzato con le tabelle pgbench. | postgresql-11, pgbackrest-2.15 | Esecuzione di pgbench ogni 5 minuti per simulare il carico di lavoro. |
node-2 | Test Machine:eseguiremo la nostra convalida Docker su questo host. | docker-ce-18.06, pgbackrest-2.15 | |
nodo-3 192.168.0.113 CentOS-7 | pgBackRest Repository Host | pgbackrest-2.15 | Esecuzione di pgbackrest per eseguire il backup Incr ogni 4 ore Backup differenziale ogni giorno Backup completo settimanale |
Affinché pgbackrest funzioni, ho configurato l'accesso SSH senza password tra questi nodi.
L'utente "postgres" sul nodo-1 e sul nodo-2 può accedere senza password all'utente "pgbackrest" sul nodo-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
L'utente "pgbackrest" sul nodo-3 può accedere senza password all'utente "postgres" sul nodo-1 e sul nodo-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
Panoramica della convalida del backup
Di seguito è riportata una breve panoramica dei passaggi che seguiremo per la nostra convalida del backup PostgreSQL.
- Utilizzando il comando di ripristino pgbackrest recupereremo l'ultimo backup dal pgBackRest Repository Host (nodo-3) nella directory Test Machine (nodo-2) /var/lib/pgsql/11/data
- Durante l'esecuzione della finestra mobile, montiamo la directory della macchina host (nodo-2) /var/lib/pgsql sul contenitore della finestra mobile e avviamo il demone postgres/postmaster dalla directory montata. Esporremmo anche la porta 5432 dal container alla porta 15432 della macchina host.
- Una volta avviata l'esecuzione del contenitore Docker, ci collegheremo al database PostgreSQL tramite il nodo-2:15432 e verificheremo che tutte le tabelle e le righe siano state ripristinate. Verificheremo anche i log di PostgreSQL per assicurarci che non ci siano messaggi di ERRORE durante il ripristino e che anche l'istanza abbia raggiunto lo stato coerente.
La maggior parte dei passaggi di convalida del backup verrà eseguita sul nodo host-2.
Costruzione dell'immagine Docker
Nel nodo-2, crea Dockerfile e crea l'immagine della finestra mobile "postgresql:11". Nel Dockerfile sottostante, applicheremo le seguenti modifiche all'immagine di base centos:7.
- Installazione di postgresql-11, pgbackrest e openssh-clients. Openssh-clients è necessario per pgbackrest.
- Configurazione di pgbackrest - Abbiamo bisogno della configurazione di pgbackrest nell'immagine per testare PITR, senza la configurazione di pgbackrest restore_command fallirebbe. Come parte della configurazione di pgbackrest
- Stiamo aggiungendo l'ip host del repository pgbackrest (192.168.0.113) nel file di configurazione /etc/pgbackrest.conf.
- Abbiamo anche bisogno di accesso SSH meno password tra il contenitore docker e l'host del repository pgbackrest. Per questo, sto copiando SSH_PRIVATE_KEY che ho già generato e ho anche aggiunto la sua chiave pubblica all'host del repository pgbackrest ( [email protected] ).
- VOLUME ["${PGHOME_DIR}"] - Definisce la directory del contenitore /var/lib/pgsql come punto di montaggio. Durante l'esecuzione del comando docker run, specificheremo la directory host del nodo 2 in questo punto di montaggio.
- USER postgres - Qualsiasi comando eseguito sul container verrà eseguito come utente 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
Ora abbiamo due file, Dockerfile utilizzato dalla build della finestra mobile e SSH_PRIVATE_KEY che verranno copiati nell'immagine della finestra mobile.
$ ls
Dockerfile SSH_PRIVATE_KEY
Esegui il comando seguente sul nodo-2 per creare la nostra immagine Docker. Ho menzionato l'IP host del repository pgbackrest nel comando e questo IP verrà utilizzato nel parametro 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
Assicurati che l'immagine sia stata creata correttamente e controlla che l'immagine "postgresql:11" sia stata creata di recente come mostrato di seguito.
$ docker image ls postgresql:11
REPOSITORY TAG IMAGE ID CREATED SIZE
postgresql 11 2e03ed2a5946 3 minutes ago 482MB
Ripristino del backup di PostgreSQL
Ora ripristineremo il nostro backup PostgreSQL mantenuto nel repository di backup pgbackrest host node-3.
Di seguito è riportato il file di configurazione di pgbackrest presente sul nodo host-2 e ho menzionato il nodo-3 come host del repository pgbackrest. La directory menzionata nel parametro pg1-path è il punto in cui la directory dei dati di PostgreSQL verrebbe ripristinata.
[[email protected] ~]$ cat /etc/pgbackrest.conf
[global]
log-level-file=detail
repo1-host=node-3
[pgbench]
pg1-path=/var/lib/pgsql/11/data
Utilizzando il comando pgbackrest restore sotto, la directory dei dati postgresql verrà ripristinata nel nodo-2:/var/lib/pgsql/11/data.
Per convalidare PITR con il backup di pgbackrest ho impostato --type=time --target='2019-07-30 06:24:50.241352+00', in modo che il ripristino WAL si interrompa prima del tempo menzionato.
[[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"
Il comando precedente potrebbe richiedere del tempo a seconda delle dimensioni del backup e della larghezza di banda della rete. Una volta ripristinato, verifica la dimensione della directory dei dati e controlla anche 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'
Disabilita la modalità archivio per il contenitore Docker PostgreSQL.
[[email protected] ~]$ sudo -u postgres bash -c "echo 'archive_mode = off' >> /var/lib/pgsql/11/data/postgresql.auto.conf"
Avvia il contenitore della finestra mobile con l'immagine "postgresql:11". Nel comando siamo
-
Impostazione del nome del contenitore come "pgbench"
-
Montaggio della directory host della finestra mobile (nodo-2) /var/lib/psql nella directory del contenitore della finestra mobile /var/lib/psql
-
Esposizione della porta container 5432 alla porta 15432 sul nodo-2.
-
Avvio del demone postgres usando il comando /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
Verifica che il contenitore "pgbench" sia creato e in esecuzione.
[[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
Convalida di PostgreSQL
Poiché la directory host /var/lib/pgsql è condivisa con il contenitore docker, i log generati dal servizio PostgreSQL sono visibili anche dal nodo-2. Verifica il registro di oggi per assicurarti che PostgreSQL sia stato avviato correttamente senza alcun ERRORE e assicurati che le righe di registro seguenti siano presenti.
[[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",,,,,,,,,""
Il messaggio "stato di ripristino coerente raggiunto a E/CE000210", indica che con la directory dei dati di backup di pgbackrest siamo stati in grado di raggiungere uno stato coerente.
Il messaggio "recupero archivio completato", indica che siamo in grado di riprodurre il file WAL di cui è stato eseguito il backup da pgbackrest e di ripristinarlo senza alcun problema.
Connettiti all'istanza postgresql tramite la porta locale 15432 e verifica le tabelle e il conteggio delle righe.
[[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)
Ora abbiamo ripristinato il nostro backup PostgreSQL su un contenitore mobile e verificato anche PITR. Una volta convalidato il backup possiamo fermare il contenitore e rimuovere la directory dei dati.
[[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"
Conclusione
In questo blog, ho dimostrato la convalida del backup utilizzando un piccolo database su una piccola macchina virtuale VirtualBox. Per questo motivo, la convalida del backup è stata completata in pochi minuti. È importante notare che in produzione dovrai scegliere una macchina virtuale adeguata con memoria, CPU e disco sufficienti per consentire il completamento della convalida del backup. Puoi anche automatizzare l'intero processo di convalida in uno script bash o anche integrandoti con una pipeline CI/CD in modo da poter convalidare regolarmente i nostri backup PostgreSQL.