Os backups são a parte vital e importante de qualquer plano de recuperação de desastres, fazer backups do banco de dados de produção também é uma parte básica e importante da administração do PostgreSQL. No entanto, os DBAs não costumam validar se esses backups são confiáveis.
Cada organização faz backups de banco de dados PostgreSQL de forma diferente, algumas podem fazer um backup do sistema de arquivos (físico) dos diretórios de dados PostgreSQL (usando ferramentas como Barman, PGBackRest), enquanto outras podem fazer apenas backups lógicos (usando pg_dump), e até mesmo outros podem tirar snapshots de nível de bloco usando ferramentas como EBS ou VMWare snapshot.
Neste blog, mostraremos como validar seu backup do PostgreSQL restaurando o backup em um contêiner do Docker usando a ferramenta pgBackRest para fazer e restaurar o backup. Estamos assumindo que você já tem conhecimento sobre como usar PostgreSQL, Docker e pgBackRest.
Por que você deve usar o Docker?
O Docker torna a automação mais simples, também facilita o trabalho de integração de nossa tarefa de validação de backup PostgreSQL em ferramentas de CI/CD como CircleCI, Travis, GitLab ou Jenkins. Usar o Docker evita o tempo e os recursos que temos que gastar para trazer o novo ambiente para testar o backup.
Configuração de demonstração
Host | Função | Instalado Pacotes | Crontab |
node-1 192.168.0.111 CentOS-7 | Instância primária do Posgresql-11. Criado usuário e banco de dados “pgbench“ e inicializado com tabelas pgbench. | postgresql-11, pgbackrest-2.15 | Executando o pgbench a cada 5 minutos para simular a carga de trabalho. |
node-2 | Máquina de teste - executaremos nossa validação do Docker neste host. | docker-ce-18.06, pgbackrest-2.15 | |
node-3 192.168.0.113 CentOS-7 | pgBackRest Host do Repositório | pgbackrest-2.15 | Executando pgbackrest para fazer backup do Incr a cada 4 horas Backup de diferenças todos os dias Backup completo semanalmente |
Para que o pgbackrest funcione, configurei o acesso SSH sem senha entre esses nós.
O usuário “postgres” no node-1 e node-2 pode fazer login sem senha para o usuário “pgbackrest” no node-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
O usuário “pgbackrest” no node-3 pode fazer login sem senha para o usuário “postgres” no node-1 e node-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
Visão geral da validação de backup
Abaixo está uma breve visão geral das etapas que seguiremos para nossa validação de backup do PostgreSQL.
- Usando o comando pgbackrest restore, buscaremos o backup mais recente do host de repositório pgBackRest (node-3) para o diretório da máquina de teste (node-2) /var/lib/pgsql/11/data
- Durante a execução do docker, montamos o diretório da máquina host (node-2) /var/lib/pgsql no contêiner do docker e iniciamos o daemon postgres/postmaster a partir do diretório montado. Também exporíamos a porta 5432 do contêiner para a porta 15432 da máquina host.
- Depois que o contêiner docker começar a ser executado, nos conectaremos ao banco de dados PostgreSQL via node-2:15432 e verificaremos se todas as tabelas e linhas foram restauradas. Também verificamos os logs do PostgreSQL para garantir que não haja mensagem de ERRO durante a recuperação e que a instância também tenha atingido o estado consistente.
A maioria das etapas de validação de backup será executada no host node-2.
Criando a imagem do Docker
No node-2, crie o Dockerfile e construa a imagem do docker “postgresql:11”. No Dockerfile abaixo, aplicaremos as seguintes alterações na imagem base centos:7.
- Instalando postgresql-11, pgbackrest e openssh-clients. O Openssh-clients é necessário para o pgbackrest.
- Configurando o pgbackrest - Precisamos da configuração do pgbackrest na imagem para testar o PITR, sem a configuração do pgbackrest restore_command falharia. Como parte da configuração do pgbackrest
- Estamos adicionando o ip do host do repositório pgbackrest (192.168.0.113) no arquivo de configuração /etc/pgbackrest.conf.
- Também precisamos de acesso SSH sem senha entre o contêiner docker e o host do repositório pgbackrest. Para isso, estou copiando SSH_PRIVATE_KEY que já gerei e também adicionei sua chave pública ao host do repositório pgbackrest ( [email protected] ).
- VOLUME ["${PGHOME_DIR}"] - Define o diretório do contêiner /var/lib/pgsql como um ponto de montagem. Ao executar o comando docker run, especificaremos o diretório do host node-2 para este ponto de montagem.
- USER postgres - Qualquer comando executado no container será executado como usuário 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
Agora temos dois arquivos, Dockerfile usado pelo docker build e SSH_PRIVATE_KEY que serão copiados para a imagem do docker.
$ ls
Dockerfile SSH_PRIVATE_KEY
Execute o comando abaixo no node-2 para construir nossa imagem docker. Eu mencionei o IP do host do repositório pgbackrest no comando e este IP será usado no parâmetro 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
Certifique-se de que a imagem foi construída com sucesso e verifique se a imagem “postgresql:11” foi criada recentemente, conforme mostrado abaixo.
$ docker image ls postgresql:11
REPOSITORY TAG IMAGE ID CREATED SIZE
postgresql 11 2e03ed2a5946 3 minutes ago 482MB
Restaurando o backup do PostgreSQL
Agora vamos restaurar nosso backup do PostgreSQL mantido no host node-3 do repositório de backup pgbackrest.
Abaixo está o arquivo de configuração pgbackrest presente no host node-2 e mencionei o node-3 como host do repositório pgbackrest. O diretório mencionado no parâmetro pg1-path é onde o diretório de dados do PostgreSQL seria restaurado.
[[email protected] ~]$ cat /etc/pgbackrest.conf
[global]
log-level-file=detail
repo1-host=node-3
[pgbench]
pg1-path=/var/lib/pgsql/11/data
Usando o comando pgbackrest restore abaixo, o diretório de dados postgresql será restaurado em node-2:/var/lib/pgsql/11/data.
Para validar o PITR com o backup pgbackrest, configurei --type=time --target='2019-07-30 06:24:50.241352+00', para que a recuperação do WAL pare antes do tempo mencionado.
[[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"
O comando acima pode demorar dependendo do tamanho do backup e da largura de banda da rede. Uma vez restaurado, verifique o tamanho do diretório de dados e verifique também o 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'
Desabilite o modo de arquivamento para o contêiner do Docker PostgreSQL.
[[email protected] ~]$ sudo -u postgres bash -c "echo 'archive_mode = off' >> /var/lib/pgsql/11/data/postgresql.auto.conf"
Inicie o container docker com a imagem “postgresql:11”. No comando estamos
-
Definindo o nome do contêiner como “pgbench”
-
Montando o diretório do docker host(node-2) /var/lib/psql no diretório do contêiner do docker /var/lib/psql
-
Expondo a porta do contêiner 5432 para a porta 15432 no nó-2.
-
Iniciando o daemon postgres usando o 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
Verifique se o contêiner “pgbench” está criado e em execução.
[[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
Validando o PostgreSQL
Como o diretório do host /var/lib/pgsql é compartilhado com o contêiner docker, os logs gerados pelo serviço PostgreSQL também são visíveis a partir do node-2. Verifique o log de hoje para ter certeza de que o PostgreSQL foi iniciado sem nenhum ERRO e certifique-se de que as linhas de log abaixo estejam presentes.
[[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",,,,,,,,,""
A mensagem "estado de recuperação consistente alcançado em E/CE000210", indica que com o diretório de dados de backup pgbackrest conseguimos atingir um estado consistente.
Mensagem "recuperação de arquivo concluída", indica que podemos reproduzir o arquivo WAL com backup feito pelo pgbackrest e recuperá-lo sem nenhum problema.
Conecte-se à instância postgresql por meio da porta local 15432 e verifique as tabelas e as contagens de linhas.
[[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)
Agora restauramos nosso backup do PostgreSQL em um contêiner docker e também verificamos o PITR. Uma vez validado o backup podemos parar o container e remover o diretório de dados.
[[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"
Conclusão
Neste blog, demonstrei a validação de backup usando um pequeno banco de dados em uma pequena VM VirtualBox. Por isso, a validação do backup foi concluída em apenas alguns minutos. É importante observar que, na produção, você precisará escolher uma VM adequada com memória, CPU e disco suficientes para permitir que a validação do backup seja concluída com êxito. Você também pode automatizar todo o processo de validação em um script bash ou até mesmo integrando com um pipeline de CI/CD para validar regularmente nossos backups PostgreSQL.