Las copias de seguridad son la parte vital e importante de cualquier plan de recuperación ante desastres, realizar copias de seguridad de la base de datos de producción también es una parte básica e importante de la administración de PostgreSQL. Sin embargo, los administradores de bases de datos no suelen validar que esas copias de seguridad sean confiables.
Cada organización realiza copias de seguridad de la base de datos de PostgreSQL de forma diferente, algunas pueden realizar una copia de seguridad (física) del sistema de archivos de los directorios de datos de PostgreSQL (utilizando herramientas como Barman, PGBackRest) mientras que otras pueden realizar solo copias de seguridad lógicas (utilizando pg_dump), e incluso otros pueden tomar instantáneas a nivel de bloque utilizando herramientas como EBS o VMWare snapshot.
En este blog, le mostraremos cómo validar su copia de seguridad de PostgreSQL restaurando la copia de seguridad en un contenedor Docker utilizando la herramienta pgBackRest para tomar y restaurar la copia de seguridad. Asumimos que ya tiene conocimiento sobre cómo usar PostgreSQL, Docker y pgBackRest.
¿Por qué debería usar Docker?
Docker simplifica la automatización, también facilita el trabajo de integrar nuestra tarea de validación de copia de seguridad de PostgreSQL en herramientas de CI/CD como CircleCI, Travis, GitLab o Jenkins. El uso de Docker evita el tiempo y los recursos que tenemos que gastar en traer el nuevo entorno para probar la copia de seguridad.
Configuración de demostración
Host | Rol | Instalado Paquetes | Crontab |
nodo-1 192.168.0.111 CentOS-7 | Instancia principal de Posgresql-11. Usuario creado y base de datos “pgbench“ e inicializado con tablas pgbench. | postgresql-11, pgbackrest-2.15 | Ejecutar pgbench cada 5 minutos para simular la carga de trabajo. |
nodo-2 | Máquina de prueba:ejecutaremos nuestra validación de Docker en este host. | docker-ce-18.06, pgbackrest-2.15 | |
nodo-3 192.168.0.113 CentOS-7 | pgBackRest Repository Host | pgbackrest-2.15 | Ejecutar pgbackrest para realizar una copia de seguridad de Incr cada 4 horas Copia de seguridad diferencial todos los días Copia de seguridad completa semanal |
Para que pgbackrest funcione, configuré el acceso SSH sin contraseña entre estos nodos.
El usuario "postgres" en el nodo 1 y el nodo 2 pueden iniciar sesión sin contraseña para el usuario "pgbackrest" en el 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
El usuario "pgbackrest" en el nodo 3 puede iniciar sesión sin contraseña para el usuario "postgres" en el nodo 1 y el 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
Descripción general de la validación de copias de seguridad
A continuación se muestra una breve descripción general de los pasos que seguiremos para nuestra validación de copia de seguridad de PostgreSQL.
- Usando el comando pgbackrest restore, buscaremos la última copia de seguridad del host de repositorio pgBackRest (nodo-3) en el directorio de la máquina de prueba (nodo-2) /var/lib/pgsql/11/data
- Durante la ejecución de la ventana acoplable, montamos el directorio /var/lib/pgsql de la máquina host (nodo-2) en el contenedor de la ventana acoplable e iniciamos el demonio postgres/postmaster desde el directorio montado. También expondríamos el puerto 5432 del contenedor al puerto 15432 de la máquina host.
- Una vez que el contenedor docker comenzó a ejecutarse, nos conectaremos a la base de datos PostgreSQL a través del nodo-2:15432 y verificaremos que todas las tablas y filas estén restauradas. También verificaríamos los registros de PostgreSQL para asegurarnos de que no haya un mensaje de ERROR durante la recuperación y que la instancia también haya alcanzado el estado consistente.
La mayoría de los pasos de validación de respaldo se realizarán en el nodo de host-2.
Creación de la imagen de Docker
En el nodo 2, cree Dockerfile y cree la imagen de Docker "postgresql:11". En el siguiente Dockerfile, aplicaremos los siguientes cambios sobre la imagen base de centos:7.
- Instalando postgresql-11, pgbackrest y openssh-clients. Se necesita Openssh-clients para pgbackrest.
- Configuración de pgbackrest:necesitamos la configuración de pgbackrest en la imagen para probar PITR, sin la configuración de pgbackrest, el comando de restauración fallaría. Como parte de la configuración de pgbackrest
- Estamos agregando la IP del host del repositorio de pgbackrest (192.168.0.113) en el archivo de configuración /etc/pgbackrest.conf.
- También necesitamos contraseña sin acceso SSH entre el contenedor docker y el host del repositorio pgbackrest. Para esto, estoy copiando SSH_PRIVATE_KEY que ya he generado y también he agregado su clave pública al host del repositorio pgbackrest ([email protected]).
- VOLUMEN ["${PGHOME_DIR}"]:define el directorio contenedor /var/lib/pgsql como punto de montaje. Mientras ejecutamos el comando docker run, especificaremos el directorio host del nodo 2 en este punto de montaje.
- USUARIO postgres:cualquier comando que se ejecute en el contenedor se ejecutará como usuario de 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
Ahora tenemos dos archivos, Dockerfile usado por la construcción de la ventana acoplable y SSH_PRIVATE_KEY que se copiará en la imagen de la ventana acoplable.
$ ls
Dockerfile SSH_PRIVATE_KEY
Ejecute el siguiente comando en el nodo 2 para crear nuestra imagen acoplable. Mencioné la IP del host del repositorio de pgbackrest en el comando y esta IP se usará en el parámetro de 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
Asegúrese de que la imagen se haya creado correctamente y verifique que la imagen "postgresql:11" se haya creado recientemente, como se muestra a continuación.
$ docker image ls postgresql:11
REPOSITORY TAG IMAGE ID CREATED SIZE
postgresql 11 2e03ed2a5946 3 minutes ago 482MB
Restauración de la copia de seguridad de PostgreSQL
Ahora restauraremos nuestra copia de seguridad de PostgreSQL mantenida en el nodo-3 del host del repositorio de copias de seguridad de pgbackrest.
A continuación se muestra el archivo de configuración de pgbackrest presente en el nodo de host 2 y mencioné el nodo 3 como host de repositorio de pgbackrest. El directorio mencionado en el parámetro pg1-path es donde se restauraría el directorio de datos de PostgreSQL.
[[email protected] ~]$ cat /etc/pgbackrest.conf
[global]
log-level-file=detail
repo1-host=node-3
[pgbench]
pg1-path=/var/lib/pgsql/11/data
Usando el siguiente comando de restauración pgbackrest, el directorio de datos de postgresql se restaurará en el nodo-2:/var/lib/pgsql/11/data.
Para validar PITR con la copia de seguridad de pgbackrest, configuré --type=time --target='2019-07-30 06:24:50.241352+00', para que la recuperación de WAL se detenga antes de la tiempo 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"
El comando anterior puede llevar tiempo según el tamaño de la copia de seguridad y el ancho de banda de la red. Una vez restaurado, verifique el tamaño del directorio de datos y también verifique 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'
Deshabilitar el modo de archivo para el contenedor docker de PostgreSQL.
[[email protected] ~]$ sudo -u postgres bash -c "echo 'archive_mode = off' >> /var/lib/pgsql/11/data/postgresql.auto.conf"
Inicie el contenedor docker con la imagen “postgresql:11”. En el comando estamos
-
Configurando el nombre del contenedor como “pgbench”
-
Montar el directorio del host de la ventana acoplable (nodo-2) /var/lib/psql en el directorio del contenedor de la ventana acoplable /var/lib/psql
-
Exponiendo el puerto del contenedor 5432 al puerto 15432 en el nodo-2.
-
Iniciando el demonio de postgres usando el 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 que el contenedor "pgbench" esté creado y funcionando.
[[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
Validación de PostgreSQL
Dado que el directorio host /var/lib/pgsql se comparte con el contenedor docker, los registros generados por el servicio PostgreSQL también son visibles desde el nodo-2. Verifique el registro de hoy para asegurarse de que PostgreSQL haya comenzado bien sin ningún ERROR y asegúrese de que las líneas de registro a continuación estén 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",,,,,,,,,""
Mensaje "Estado de recuperación consistente alcanzado en E/CE000210", indica que con el directorio de datos de respaldo de pgbackrest pudimos alcanzar un estado consistente.
El mensaje "recuperación completa del archivo", indica que podemos reproducir el archivo WAL respaldado por pgbackrest y recuperarlo sin ningún problema.
Conéctese a la instancia de postgresql a través del puerto local 15432 y verifique las tablas y el recuento de filas.
[[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)
Ahora restauramos nuestra copia de seguridad de PostgreSQL en un contenedor docker y también verificamos PITR. Una vez validada la copia de seguridad, podemos detener el contenedor y eliminar el directorio de datos.
[[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"
Conclusión
En este blog, demostré la validación de la copia de seguridad utilizando una pequeña base de datos en una pequeña máquina virtual VirtualBox. Debido a esto, la validación de la copia de seguridad se completó en solo unos minutos. Es importante tener en cuenta que en producción deberá elegir una máquina virtual adecuada con suficiente memoria, CPU y disco para permitir que la validación de la copia de seguridad se complete con éxito. También puede automatizar todo el proceso de validación en un script bash o incluso mediante la integración con una canalización de CI/CD para que pueda validar regularmente nuestras copias de seguridad de PostgreSQL.