Ejemplo de PostgreSQL con Docker haciendo copias de seguridad incrementales (Continuous Archiving, Point In Time Recovery (PITR))
Enlaces de interés:
- Documentación de PostgreSQL: Continuous Archiving and Point-in-Time Recovery (PITR)
- Documentación de PostgreSQL: Configuración Write Ahead Log
- Herramientas de backup y restauración: wal-g, barman, pitrery, pg_backrest, pg_probackup
- Tutorial de scalingpostgres.com (Ojo, con la versión 10. Algunas cosas cambian)
- Info: reemplazo del fichero recovery.conf por recovery.signal en la v12
archive_mode = onwal_level = replicaarchive_command = 'arch-command %f %p'restore_command = 'rest-command %f %p'
Podemos hacerlo a través de la sentencia ALTER SYSTEM, que guarda los cambios en postgres.auto.conf, en vez de editar el fichero postgres.conf.
Copiando este script en el directorio /docker-entrypoint-initdb.d/ se ejecutará la primera vez que se inicie el contenedor.
/* Habilita el archivado */ ALTER SYSTEM SET archive_mode = on; /* Nivel de información de los ficheros WAL. Necesitaremos replica o logical */ ALTER SYSTEM SET wal_level = replica; -- Podríamos crear e indicar scripts más refinados para los comandos -- %f se sustituirá por el nombre del fichero y %p por la ruta del mismo /* Cada vez que se completa un fichero WAL (16 MB default) se ejecuta archive_command */ ALTER SYSTEM SET archive_command = 'test ! -f /var/lib/postgresql/backups/wal/%f && cp %p /var/lib/postgresql/backups/wal/%f'; /* Cuando la base de datos entre en modo de recuperación ejecutará restore_command */ ALTER SYSTEM SET restore_command = 'cp /var/lib/postgresql/backups/wal/%f %p';Utilizamos pg_basebackup para copiar el contenido del directorio $PGDATA (/var/lib/postgresql/data/)
IMPORTANTE: Primero debemos ajustar los permisos de los directorios en los que guardaremos las copias base y los ficheros WAL. El usuario postgres debe tener acceso.
# Creamos y hacemos propietario a postgres de los directorios donde se guardarán las copias mkdir /var/lib/postgresql/backups/wal/ mkdir /var/lib/postgresql/backups/base/ chown -R postgres:postgres /var/lib/postgresql/backups/Nota: Podemos crear copias base cada cierto tiempo y conseguir así restauraciones más ágiles
# Generamos una copia base # Flags interesantes: # -z: comprime los tar # -v: verboso # -P: muestra el progreso su - postgres pg_basebackup -Ft -D /var/lib/postgresql/backups/base/psql -c "CREATE DATABASE dbtest;" psql dbtest postgres -c " CREATE TABLE tabla ( id SERIAL, hora timestamp without time zone default now(), texto varchar(100) ); " psql dbtest postgres -c " INSERT INTO tabla (texto) VALUES ('En un lugar de la mancha'); INSERT INTO tabla (texto) VALUES ('de cuyo nombre no quiero acordarme'); SELECT * FROM tabla; " # Forzamos el cambio de fichero wal en vez de esperar a que se llene el actual psql -U postgres -c "select pg_switch_wal();" psql dbtest postgres -c " INSERT INTO tabla (texto) VALUES ('Country roads, take me home'); INSERT INTO tabla (texto) VALUES ('To the place I belong'); INSERT INTO tabla (texto) VALUES ('West Virginia, mountain mama'); INSERT INTO tabla (texto) VALUES ('Take me home, country roads'); SELECT * FROM tabla; " # Forzamos el cambio de fichero wal en vez de esperar a que se llene el actual psql -U postgres -c "select pg_switch_wal();" psql dbtest postgres -c " INSERT INTO tabla (texto) VALUES ('Dale a tu cuerpo alegria Macarena'); INSERT INTO tabla (texto) VALUES ('que tu cuerpo es para darle alegria y cosa buena'); INSERT INTO tabla (texto) VALUES ('eeeh Macarena.... aaahe'); SELECT * FROM tabla; " # Esta vez no forzamos el cambio del fichero wal. A ver qué pasaPodemos simular un fallo grave del sistema borrando ficheros de postgres:
# Podemos borrar algunos directorios y salir del contenedor rm -rf /var/lib/postgresql/data/global /var/lib/postgresql/data/base # O podemos borrar todo el directorio y automáticamente se detendrá el contenedor # Allá vamos rm -rf /var/lib/postgresql/data/*Ahora pasamos a ejecutar los comandos desde nuestra máquina
Debemos restaurar la copia base y hacer que postgres entre en modo recuperación
NOTA: Especificar correctamente el path de los volúmenes
# Desde nuestra máquina restauramos el directorio $PGDATA con la copia base que tengamos tar xvf path-volumen_backups/_data/base/base.tar -C path-volumen_data/_data/ tar xvf path-volumen_backups/_data/base/pg_wal.tar -C path-volumen_data/_data/pg_wal/ # Para que se inicie en modo de recuperación creamos el fichero recovery.signal # Solo importa su presencia en $PGDATA, desapareciendo al finalizar la restauración touch path-volumen_data/_data/recovery.signalSi queremos realizar la recuperación hasta cierto punto del tiempo (PITR) debemos indicar ese momento en postgres.conf o postgres.auto.conf
Ahora arrancamos el contenedor y se terminará la restauración a partir de los ficheros WAL.
Podemos comprobar que se restauró correctamente
psql dbtest postgres -c "select * from tabla;"Nota: Si restauramos con una marca de tiempo deberemos volver a habilitar manualmente el archivado:
psql -U postgres -c "select pg_wal_replay_resume();"