1. Introducción
Este manual está diseñado para guiarte a través del proceso de instalación y configuración de una base de datos PostgreSQL en alta disponibilidad utilizando Patroni y etcd como servicio de coordinación. Patroni facilita la gestión del clúster de bases de datos PostgreSQL y asegura la conmutación por error automática, mientras que etcd proporciona la sincronización de la configuración entre los nodos del clúster.
Este tipo de configuración es ideal para entornos de producción donde se necesita garantizar alta disponibilidad y resistencia ante fallos de nodo.
2. Requisitos Previos
Antes de comenzar con la instalación, asegúrate de cumplir con los siguientes requisitos previos:
- Sistema Operativo: GNU/Linux (En este caso emplearemos Debian).
- Privilegios de root: Acceso a una cuenta con permisos de superusuario para realizar instalaciones y configuraciones del sistema.
- Red: Tres servidores (o más) en la misma red con direcciones IP estáticas.
- Conectividad SSH: Asegúrate de que todos los nodos puedan comunicarse entre sí mediante SSH.
- Dependencias: Necesitarás herramientas como
curl
,wget
, y otros paquetes necesarios para descargar e instalar componentes.
2.1 Elección de la Cantidad de Nodos en Alta Disponibilidad
Cuando se configura un clúster de PostgreSQL en alta disponibilidad con Patroni y etcd, una de las decisiones clave es el número de nodos que formarán parte del clúster. La cantidad de nodos tiene un impacto directo en la tolerancia a fallos, la capacidad de realizar conmutaciones por error y la disponibilidad general del sistema. A continuación, explicamos cómo calcular el número adecuado de nodos y por qué se recomienda utilizar un número impar de nodos en algunos casos.
¿Cuántos Nodos Necesito?
El número mínimo recomendado para configurar un clúster de alta disponibilidad es de tres nodos. Este número de nodos asegura que el sistema sea lo suficientemente robusto como para tolerar fallos de al menos un nodo sin que se pierda la disponibilidad o el consenso en el clúster.
Para calcular el número de nodos necesarios en un clúster con etcd, se sigue una fórmula relacionada con el quorum. El quorum es la cantidad mínima de nodos que deben estar disponibles para que el sistema tome decisiones de manera confiable. Esta fórmula es la siguiente:
quorum=nodos2+1quorum = \frac{nodos}{2} + 1
Por ejemplo:
- Con 3 nodos: el quorum es de 2 nodos, lo que permite que el sistema siga funcionando si uno de los nodos falla.
- Con 5 nodos: el quorum es de 3 nodos, permitiendo que el sistema siga operativo incluso si dos nodos fallan.
- Con 7 nodos: el quorum es de 4 nodos, lo que permite una mayor tolerancia a fallos.
¿Por qué es importante tener un número impar de nodos?
El uso de un número impar de nodos es fundamental cuando se utilizan tecnologías de consenso, como etcd o Raft, que son responsables de mantener la consistencia de los datos en el clúster. Esto se debe a que el consenso depende de un proceso de votación entre los nodos para tomar decisiones. Si hay un número par de nodos, existe el riesgo de que no se pueda alcanzar un consenso en caso de un fallo, ya que no se podría determinar qué nodo tiene la mayoría.
Por ejemplo:
- Si el clúster tiene 2 nodos y uno de ellos falla, el otro nodo quedaría sin quorum, ya que no puede decidir por sí mismo si el nodo caído debe ser promovido o no.
- Con 3 nodos, si uno falla, los otros dos pueden seguir trabajando y decidir qué hacer con el nodo caído.
Por lo tanto, siempre que se utilicen servicios de coordinación y consenso (como etcd o Consul), es recomendable tener un número impar de nodos en el clúster para garantizar que siempre se pueda alcanzar el quorum y evitar problemas de «split-brain» (división del clúster).
¿Cuándo se podrían usar nodos pares?
En algunos casos, los nodos pares pueden ser adecuados, pero solo para ciertos tipos de servicios que no dependen de un proceso de consenso, como en la distribución de carga o en clústeres de Kubernetes donde los nodos de worker no participan en decisiones críticas de consenso. Algunos ejemplos de estos casos son:
- Balanceadores de carga: En servicios como HAProxy o NGINX, los nodos de balanceo pueden ser pares, ya que su objetivo es distribuir el tráfico sin necesidad de consenso.
- Servidores de aplicaciones: Si el servicio solo necesita alta disponibilidad pero no se requiere un proceso de consenso entre los nodos, los nodos de aplicaciones pueden ser pares.
Resumen
- Para clústeres de alta disponibilidad que utilizan Patroni y etcd, 3 nodos es el mínimo recomendado, y se debe utilizar un número impar para garantizar el consenso y la disponibilidad en caso de fallos.
- 5 nodos es ideal para entornos más grandes o donde se espera una mayor carga, ya que proporciona más tolerancia a fallos.
- El número de nodos puede ser par en servicios que no requieren consenso, como balanceadores de carga o servidores de aplicaciones.
3. Instalación de la Base de Datos en Alta Disponibilidad
Este paso te guiará a través de la instalación de PostgreSQL y Patroni en tres nodos (servidores) que formarán parte del clúster de alta disponibilidad.
3.0 Instalación de PostgreSQL, Patroni y etcd
Para comenzar, actualiza los paquetes del sistema e instala las herramientas necesarias:
sudo apt update && sudo apt install -y postgresql postgresql-contrib patroni etcd-server etcd-client curl wget pgbackrest jq
Descargaremos e instalaremos las herramientas de gestión de certificados, necesarias para asegurar las comunicaciones entre los nodos.
sudo wget https://pkg.cfssl.org/R1.2/cfssl_linux-amd64 -O /bin/cfssl
sudo wget https://pkg.cfssl.org/R1.2/cfssljson_linux-amd64 -O /bin/cfssljson
sudo wget https://pkg.cfssl.org/R1.2/cfssl-certinfo_linux-amd64 -O /bin/cfssl-certinfo
sudo chmod +x /bin/cfssl*
A continuación, modifica el archivo /etc/hosts
de cada nodo para que se reconozcan los demás servidores del clúster.
sudo bash -c 'cat <<EOF >> /etc/hosts
192.168.1.214 srvlropsql01
192.168.1.215 srvlropsql02
192.168.1.216 srvlropsql03
EOF'
3.1 Crear un grupo común para compartir acceso a certificados y claves
Para permitir que los servicios como postgres
y etcd
compartan acceso a los archivos de certificados y claves necesarias, puedes crear un grupo común y añadir los usuarios correspondientes a ese grupo.
Crear el grupo común
Puedes crear un grupo llamado, por ejemplo, db-etcd
, que tendrá acceso a los certificados y claves necesarias para ambos servicios.
sudo groupadd db-etcd
Añadir los usuarios al grupo
Añade los usuarios postgres
y etcd
al grupo db-etcd
. Esto permitirá que ambos servicios tengan acceso a los archivos de claves de forma compartida.
sudo usermod -aG db-etcd postgres
sudo usermod -aG db-etcd etcd
3.2 Configuración de etcd-Server
Generación de Certificados (Manual)
Para asegurar las comunicaciones entre los nodos del clúster, es necesario generar certificados SSL. Los certificados se generan mediante cfssl (CloudFlare’s PKI toolkit).
Crea los directorios necesarios y entra en el directorio donde almacenarás los certificados.
mkdir /etc/etcd && mkdir ~/etcd-ca && cd ~/etcd-ca
- Crea la Autoridad Certificadora (CA) utilizando
cfssl
.
echo '{"CN":"CA","key":{"algo":"rsa","size":2048}}' | cfssl gencert -initca - | cfssljson -bare ca -
- Crea la configuración para la firma de certificados.
echo '{"signing":{"default":{"expiry":"43800h","usages":["signing","key encipherment","server auth","client auth"]}}}' > ca-config.json
- Repite el proceso para cada nodo en el clúster, usando la siguiente secuencia de comandos, reemplazando los valores de
NAME
yADDRESS
para cada servidor:
export NAME=srvlropsql01
export ADDRESS=192.168.1.214,$NAME
echo '{"CN":"'$NAME'","hosts":[""],"key":{"algo":"rsa","size":2048}}' | cfssl gencert -config=ca-config.json -ca=ca.pem -ca-key=ca-key.pem -hostname="$ADDRESS" - | cfssljson -bare $NAME
Luego, transfiere los certificados al directorio adecuado y asegúrate de establecer los permisos correctos:
scp ca.pem $NAME:/etc/etcd/etcd-ca.crt
scp $NAME.pem $NAME:/etc/etcd/server.crt
scp $NAME-key.pem $NAME:/etc/etcd/server.key
scp ca* $NAME:/etc/etcd/
ssh $NAME chmod 600 /etc/etcd/server.key
ssh $NAME sudo chown etcd:db-etcd /etc/etcd/*
Repite este proceso para cada nodo en el clúster, cambiando los valores de NAME
y ADDRESS
según sea necesario.
3.3 Configuración de etcd (Automatizado)
Si prefieres automatizar el proceso de creación y distribución de los certificados, puedes usar el siguiente script. Este script crea los certificados y los distribuye a todos los nodos de forma automática.
#!/bin/bash
# Crear la CA
echo "Generando la CA"
echo '{"CN":"CA","key":{"algo":"rsa","size":2048}}' | cfssl gencert -initca - | cfssljson -bare ca -
echo '{"signing":{"default":{"expiry":"43800h","usages":["signing","key encipherment","server auth","client auth"]}}}' > ca-config.json
# Lista de servidores y sus direcciones IP
declare -A SERVERS
SERVERS=(
["srvlropsql01"]="192.168.1.214"
["srvlropsql02"]="192.168.1.215"
["srvlropsql03"]="192.168.1.216"
)
# Ruta del archivo CA
CA_PATH="/etc/etcd/"
# Certificados generados
CA_PEM="ca.pem"
CA_KEY="ca-key.pem"
# Iterar sobre cada servidor
for NAME in "${!SERVERS[@]}"; do
ADDRESS="${SERVERS[$NAME]},$NAME"
# Generar certificado
echo "Generando certificado de $NAME"
echo '{"CN":"'$NAME'","hosts":[""],"key":{"algo":"rsa","size":2048}}' | cfssl gencert -config=ca-config.json -ca=$CA_PEM -ca-key=$CA_KEY -hostname="$ADDRESS" - | cfssljson -bare $NAME
if [ "$NAME" == "srvlropsql01" ]; then
# Copiar archivos al servidor local
sudo cp $CA_PEM $CA_PATH/etcd-ca.crt
sudo cp $NAME.pem $CA_PATH/server.crt
sudo cp $NAME-key.pem $CA_PATH/server.key
sudo cp ca* $CA_PATH/
sudo chmod 600 $CA_PATH/server.key
sudo chown etcd:db-etcd $CA_PATH/*
else
# Copiar archivos a servidores remotos
scp $CA_PEM $NAME:$CA_PATH/etcd-ca.crt
scp $NAME.pem $NAME:$CA_PATH/server.crt
scp $NAME-key.pem $NAME:$CA_PATH/server.key
scp ca* $NAME:$CA_PATH/
ssh $NAME "sudo chmod 600 $CA_PATH/server.key"
ssh $NAME "sudo chown etcd:db-etcd $CA_PATH/*"
fi
done
Este script automatiza todo el proceso de creación y distribución de los certificados, asegurando que cada nodo tenga los certificados adecuados y que los permisos estén correctamente configurados.
3.4 Verificación de los Certificados
Una vez que hayas configurado los certificados y los permisos, verifica la validez de los certificados generados en cada nodo.
openssl x509 -in /etc/etcd/server.crt -text -noout | grep -E "CN=|DNS:|IP Address:"
Este comando muestra los detalles del certificado para asegurarte de que todo esté configurado correctamente.
3.5 Configuración de Etcd
Configuración de los archivos de Etcd en cada nodo
En cada uno de los nodos que forman parte del clúster, debes configurar el archivo /etc/default/etcd
con los siguientes parámetros:
Para el nodo srvlropsql01
:
ETCD_NAME="srvlropsql01"
ETCD_INITIAL_CLUSTER_STATE="new"
ETCD_INITIAL_CLUSTER_TOKEN="etcd-cluster"
ETCD_DATA_DIR="/var/lib/etcd"
ETCD_LISTEN_PEER_URLS="https://192.168.1.214:2380"
ETCD_LISTEN_CLIENT_URLS="https://192.168.1.214:2379"
ETCD_INITIAL_CLUSTER="srvlropsql01=https://srvlropsql01:2380,srvlropsql02=https://srvlropsql02:2380,srvlropsql03=https://srvlropsql03:2380"
ETCD_INITIAL_ADVERTISE_PEER_URLS="https://192.168.1.214:2380"
ETCD_ADVERTISE_CLIENT_URLS="https://192.168.1.214:2379"
ETCD_TRUSTED_CA_FILE="/etc/etcd/etcd-ca.crt"
ETCD_CERT_FILE="/etc/etcd/server.crt"
ETCD_KEY_FILE="/etc/etcd/server.key"
ETCD_PEER_CLIENT_CERT_AUTH=true
ETCD_PEER_TRUSTED_CA_FILE="/etc/etcd/etcd-ca.crt"
ETCD_PEER_KEY_FILE="/etc/etcd/server.key"
ETCD_PEER_CERT_FILE="/etc/etcd/server.crt"
ETCD_LOG_LEVEL="info"
ETCD_ENABLE_V2="true"
Para el nodo srvlropsql02
:
ETCD_NAME="srvlropsql02"
ETCD_INITIAL_CLUSTER_STATE="new"
ETCD_INITIAL_CLUSTER_TOKEN="etcd-cluster"
ETCD_DATA_DIR="/var/lib/etcd"
ETCD_LISTEN_PEER_URLS="https://192.168.1.215:2380"
ETCD_LISTEN_CLIENT_URLS="https://192.168.1.215:2379"
ETCD_INITIAL_CLUSTER="srvlropsql01=https://srvlropsql01:2380,srvlropsql02=https://srvlropsql02:2380,srvlropsql03=https://srvlropsql03:2380"
ETCD_INITIAL_ADVERTISE_PEER_URLS="https://192.168.1.215:2380"
ETCD_ADVERTISE_CLIENT_URLS="https://192.168.1.215:2379"
ETCD_TRUSTED_CA_FILE="/etc/etcd/etcd-ca.crt"
ETCD_CERT_FILE="/etc/etcd/server.crt"
ETCD_KEY_FILE="/etc/etcd/server.key"
ETCD_PEER_CLIENT_CERT_AUTH=true
ETCD_PEER_TRUSTED_CA_FILE="/etc/etcd/etcd-ca.crt"
ETCD_PEER_KEY_FILE="/etc/etcd/server.key"
ETCD_PEER_CERT_FILE="/etc/etcd/server.crt"
ETCD_LOG_LEVEL="info"
ETCD_ENABLE_V2="true"
Para el nodo srvlropsql03
:
ETCD_NAME="srvlropsql03"
ETCD_INITIAL_CLUSTER_STATE="new"
ETCD_INITIAL_CLUSTER_TOKEN="etcd-cluster"
ETCD_DATA_DIR="/var/lib/etcd"
ETCD_LISTEN_PEER_URLS="https://192.168.1.216:2380"
ETCD_LISTEN_CLIENT_URLS="https://192.168.1.216:2379"
ETCD_INITIAL_CLUSTER="srvlropsql01=https://srvlropsql01:2380,srvlropsql02=https://srvlropsql02:2380,srvlropsql03=https://srvlropsql03:2380"
ETCD_INITIAL_ADVERTISE_PEER_URLS="https://192.168.1.216:2380"
ETCD_ADVERTISE_CLIENT_URLS="https://192.168.1.216:2379"
ETCD_TRUSTED_CA_FILE="/etc/etcd/etcd-ca.crt"
ETCD_CERT_FILE="/etc/etcd/server.crt"
ETCD_KEY_FILE="/etc/etcd/server.key"
ETCD_PEER_CLIENT_CERT_AUTH=true
ETCD_PEER_TRUSTED_CA_FILE="/etc/etcd/etcd-ca.crt"
ETCD_PEER_KEY_FILE="/etc/etcd/server.key"
ETCD_PEER_CERT_FILE="/etc/etcd/server.crt"
ETCD_LOG_LEVEL="info"
ETCD_ENABLE_V2="true"
Reiniciar y habilitar Etcd en cada nodo
En cada nodo, ejecuta los siguientes comandos para reiniciar y habilitar el servicio Etcd para que inicie automáticamente al arranque:
sudo systemctl restart etcd
sudo systemctl enable etcd
Verificación del estado de Etcd
Una vez que Etcd esté configurado y en funcionamiento, puedes verificar la salud de los nodos con el siguiente comando:
sudo etcdctl --endpoints=https://srvlropsql01:2379,https://srvlropsql02:2379,https://srvlropsql03:2379 --cacert=/etc/etcd/ca.pem --cert=/etc/etcd/server.crt --key=/etc/etcd/server.key endpoint health
Output
https://srvlropsql01:2379 is healthy: successfully committed proposal: took = 27.537946ms
https://srvlropsql03:2379 is healthy: successfully committed proposal: took = 38.517279ms
https://srvlropsql02:2379 is healthy: successfully committed proposal: took = 35.582262ms
Comprobación del estado de los endpoints de Etcd
Puedes verificar el estado de los endpoints de Etcd utilizando el siguiente comando:
sudo etcdctl --endpoints=https://srvlropsql01:2379,https://srvlropsql02:2379,https://srvlropsql03:2379 --cacert=/etc/etcd/ca.pem --cert=/etc/etcd/server.crt --key=/etc/etcd/server.key endpoint status --write-out=table
Output
+---------------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+
| ENDPOINT | ID | VERSION | DB SIZE | IS LEADER | IS LEARNER | RAFT TERM | RAFT INDEX | RAFT APPLIED INDEX | ERRORS |
+---------------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+
| https://srvlropsql01:2379 | 1d73939a04e3e9e0 | 3.4.23 | 20 kB | true | false | 6 | 9 | 9 | |
| https://srvlropsql02:2379 | bce2231f6867959d | 3.4.23 | 25 kB | false | false | 6 | 9 | 9 | |
| https://srvlropsql03:2379 | 2ce6d020bc93183f | 3.4.23 | 20 kB | false | false | 6 | 9 | 9 | |
+---------------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+
Revisión de los logs de Etcd
Para verificar si hay errores en el servicio Etcd, puedes consultar los logs ejecutando:
sudo journalctl -u etcd --no-pager | tail -n 20
En caso de tener problemas con el certificado cambiar la configuración a la siguiente y realizar pruebas
ETCD_PEER_CLIENT_CERT_AUTH=false
CLIENT-CERT-AUTH=false
ETCD_AUTO_TLS=false
Configuración de Patroni
Detener el servicio PostgreSQL
Antes de iniciar la configuración de Patroni, es necesario detener el servicio de PostgreSQL para evitar conflictos.
sudo systemctl stop postgresql.service
Acceso al usuario PostgreSQL
Se cambia al usuario postgres
para ejecutar comandos dentro de PostgreSQL.
sudo su - postgres
psql
Configuración de roles y usuarios en PostgreSQL
Se crean y configuran los roles necesarios para la replicación y la copia de seguridad con pgBackRest
.
Creación del usuario replicador
Se crea un rol con permisos de replicación.
CREATE ROLE replicator WITH REPLICATION LOGIN ENCRYPTED PASSWORD 'Temporal01.';
ALTER ROLE replicator WITH REPLICATION;
Configuración del usuario administrador
Se cambia la contraseña del usuario postgres
para garantizar la autenticación segura.
ALTER USER postgres WITH PASSWORD 'Temporal01.';
Creación del usuario para pgBackRest
Se crea un usuario con permisos de superusuario y se otorgan privilegios de conexión y acceso a secuencias y tablas.
CREATE ROLE pgbackrest WITH LOGIN PASSWORD 'Temporal01.' SUPERUSER;
GRANT CONNECT ON DATABASE postgres TO pgbackrest;
GRANT USAGE, SELECT ON ALL SEQUENCES IN SCHEMA public TO pgbackrest;
GRANT SELECT ON ALL TABLES IN SCHEMA public TO pgbackrest;
GRANT CONNECT ON DATABASE postgres TO pgbackrest;
Creación y ajuste de permisos
touch /var/lib/postgresql/.pgpass
chmod 600 /var/lib/postgresql/.pgpass
chown postgres:postgres /var/lib/postgresql/.pgpass
Edición del archivo .pgpass
Se agregan las credenciales para la replicación en cada nodo del clúster.
vi /var/lib/postgresql/.pgpass
Contenido del archivo:
192.168.1.214:5432:*:replicator:Temporal01.
192.168.1.215:5432:*:replicator:Temporal01.
192.168.1.216:5432:*:replicator:Temporal01.
192.168.1.214:5432:*:postgres:Temporal01.
192.168.1.215:5432:*:postgres:Temporal01.
192.168.1.216:5432:*:postgres:Temporal01.
Configuración de la variable de entorno PGPASSFILE
Es necesario exportar la variable de entorno que apunta al archivo .pgpass
para que PostgreSQL la utilice de forma automática.
vi ~/.bashrc
Agregar la siguiente línea:
export PGPASSFILE=/var/lib/postgresql/.pgpass
Aplicar los cambios:
source ~/.bashrc
Eliminación de datos previos y reinicio del servicio
Antes de iniciar Patroni, es recomendable eliminar los datos previos de PostgreSQL y detener el servicio nuevamente.
sudo systemctl stop postgresql.service
sudo rm -rf /var/lib/postgresql/15/main
Configuración de los archivos de Patroni en cada nodo
Cada nodo tiene su propio archivo de configuración config.yml
, en el que se especifican los detalles de la configuración, como la dirección del restapi
, la configuración de etcd
para la coordinación del clúster, y los parámetros de PostgreSQL. Este es un ejemplo de configuración para tres nodos en un clúster de Patroni:
Para el nodo srvlropsql01
:
scope: keycloak-cluster
namespace: /service/
name: srvlropsql01
restapi:
listen: 192.168.1.214:8008
connect_address: 192.168.1.214:8008
authentication:
username: admin
password: admin_password
etcd:
hosts: 192.168.1.214:2379,192.168.1.215:2379,192.168.1.216:2379
protocol: https
cacert: /etc/etcd/etcd-ca.crt
cert: /etc/etcd/server.crt
key: /etc/etcd/server.key
bootstrap:
dcs:
ttl: 30
loop_wait: 10
retry_timeout: 10
maximum_lag_on_failover: 1048576
postgresql:
use_pg_rewind: true
parameters:
wal_level: replica
hot_standby: "on"
max_wal_senders: 10
max_replication_slots: 10
wal_keep_size: 256MB
initdb:
- encoding: UTF8
- data-checksums
users:
replication:
password: replicator_password
options:
- replication
admin:
password: admin_password
options:
- createrole
- createdb
post_init:
- createuser --superuser admin
postgresql:
listen: 0.0.0.0:5432
connect_address: 192.168.1.214:5432
data_dir: /var/lib/postgresql/15/main
bin_dir: /usr/lib/postgresql/15/bin
pgpass: /tmp/pgpass
authentication:
replication:
username: replicator
password: replicator_password
superuser:
username: postgres
password: postgres_password
parameters:
archive_mode: "on"
archive-command: 'pgbackrest --stanza=postgres archive-push %f'
wal_level: replica
max_wal_senders: 10
max_replication_slots: 10
wal_keep_size: 256MB
pg_hba:
- local all postgres trust
- hostssl replication replicator 127.0.0.1/32 trust
- hostssl replication replicator 192.168.1.215/32 trust
- hostssl replication replicator 192.168.1.216/32 trust
- hostssl replication replicator 192.168.1.214/32 trust
- host replication replicator 127.0.0.1/32 trust
- host replication replicator 192.168.1.215/32 trust
- host replication replicator 192.168.1.216/32 trust
- host replication replicator 192.168.1.214/32 trust
- hostssl all all 192.168.1.0/24 trust
- host all all 192.168.1.0/24 trust
- hostssl all pgbackrest 192.168.1.0/24 trust
- host all pgbackrest 192.168.1.0/24 trust
- hostssl all all 0.0.0.0/0 md5
- host all all 0.0.0.0/0 md5
tags:
nofailover: false
noloadbalance: false
clonefrom: false
Para el nodo srvlropsql02
:
scope: keycloak-cluster
namespace: /service/
name: srvlropsql02
restapi:
listen: 192.168.1.215:8008
connect_address: 192.168.1.215:8008
authentication:
username: admin
password: admin_password
etcd:
hosts: 192.168.1.214:2379,192.168.1.215:2379,192.168.1.216:2379
protocol: https
cacert: /etc/etcd/etcd-ca.crt
cert: /etc/etcd/server.crt
key: /etc/etcd/server.key
bootstrap:
dcs:
ttl: 30
loop_wait: 10
retry_timeout: 10
maximum_lag_on_failover: 1048576
postgresql:
use_pg_rewind: true
parameters:
wal_level: replica
hot_standby: "on"
max_wal_senders: 10
max_replication_slots: 10
wal_keep_size: 256MB
initdb:
- encoding: UTF8
- data-checksums
users:
replication:
password: replicator_password
options:
- replication
admin:
password: admin_password
options:
- createrole
- createdb
post_init:
- createuser --superuser admin
postgresql:
listen: 0.0.0.0:5432
connect_address: 192.168.1.215:5432
data_dir: /var/lib/postgresql/15/main
bin_dir: /usr/lib/postgresql/15/bin
pgpass: /tmp/pgpass
authentication:
replication:
username: replicator
password: replicator_password
superuser:
username: postgres
password: postgres_password
parameters:
archive_mode: "on"
archive-command: 'pgbackrest --stanza=postgres archive-push %f'
wal_level: replica
max_wal_senders: 10
max_replication_slots: 10
wal_keep_size: 256MB
pg_hba:
- local all postgres trust
- hostssl replication replicator 127.0.0.1/32 trust
- hostssl replication replicator 192.168.1.215/32 trust
- hostssl replication replicator 192.168.1.216/32 trust
- hostssl replication replicator 192.168.1.214/32 trust
- host replication replicator 127.0.0.1/32 trust
- host replication replicator 192.168.1.215/32 trust
- host replication replicator 192.168.1.216/32 trust
- host replication replicator 192.168.1.214/32 trust
- hostssl all all 192.168.1.0/24 trust
- host all all 192.168.1.0/24 trust
- hostssl all pgbackrest 192.168.1.0/24 trust
- host all pgbackrest 192.168.1.0/24 trust
- hostssl all all 0.0.0.0/0 md5
- host all all 0.0.0.0/0 md5
tags:
nofailover: false
noloadbalance: false
clonefrom: false
Para el nodo srvlropsql03
:
scope: keycloak-cluster
namespace: /service/
name: srvlropsql03
restapi:
listen: 192.168.1.216:8008
connect_address: 192.168.1.216:8008
authentication:
username: admin
password: admin_password
etcd:
hosts: 192.168.1.214:2379,192.168.1.215:2379,192.168.1.216:2379
protocol: https
cacert: /etc/etcd/etcd-ca.crt
cert: /etc/etcd/server.crt
key: /etc/etcd/server.key
bootstrap:
dcs:
ttl: 30
loop_wait: 10
retry_timeout: 10
maximum_lag_on_failover: 1048576
postgresql:
use_pg_rewind: true
parameters:
wal_level: replica
hot_standby: "on"
max_wal_senders: 10
max_replication_slots: 10
wal_keep_size: 256MB
initdb:
- encoding: UTF8
- data-checksums
users:
replication:
password: replicator_password
options:
- replication
admin:
password: admin_password
options:
- createrole
- createdb
post_init:
- createuser --superuser admin
postgresql:
listen: 0.0.0.0:5432
connect_address: 192.168.1.216:5432
data_dir: /var/lib/postgresql/15/main
bin_dir: /usr/lib/postgresql/15/bin
pgpass: /tmp/pgpass
authentication:
replication:
username: replicator
password: replicator_password
superuser:
username: postgres
password: postgres_password
parameters:
archive_mode: "on"
archive-command: 'pgbackrest --stanza=postgres archive-push %f'
wal_level: replica
max_wal_senders: 10
max_replication_slots: 10
wal_keep_size: 256MB
pg_hba:
- local all postgres trust
- hostssl replication replicator 127.0.0.1/32 trust
- hostssl replication replicator 192.168.1.215/32 trust
- hostssl replication replicator 192.168.1.216/32 trust
- hostssl replication replicator 192.168.1.214/32 trust
- host replication replicator 127.0.0.1/32 trust
- host replication replicator 192.168.1.215/32 trust
- host replication replicator 192.168.1.216/32 trust
- host replication replicator 192.168.1.214/32 trust
- hostssl all all 192.168.1.0/24 trust
- host all all 192.168.1.0/24 trust
- hostssl all pgbackrest 192.168.1.0/24 trust
- host all pgbackrest 192.168.1.0/24 trust
- hostssl all all 0.0.0.0/0 md5
- host all all 0.0.0.0/0 md5
tags:
nofailover: false
noloadbalance: false
clonefrom: false
Configuración de pgBackRest
Después de configurar Patroni, es necesario configurar pgBackRest, una herramienta utilizada para gestionar los respaldos de PostgreSQL. Este es el archivo de configuración pgbackrest.conf
que se debe utilizar:
[global]
repo1-path=/var/lib/pgbackrest # Directorio donde se guardarán los respaldos
log-level-console=info
log-level-file=detail
compress=y
start-fast=y
log-path=/var/log/pgbackrest # Ruta para logs detallados
# Nodo 1 (Líder)
[nodo1]
pg1-path=/var/lib/postgresql/15/main
pg1-port=5432
pg1-host=localhost # El nodo líder se encuentra en el localhost
stanza=postgres
archive-mode=on
archive-command='pgbackrest --stanza=postgres archive-push %p'
# Nodo 2 (Réplika)
[nodo2]
pg1-path=/var/lib/postgresql/15/main
pg1-port=5432
pg1-host=192.168.1.215 # Dirección IP del nodo 2
stanza=postgres
archive-mode=on
archive-command='pgbackrest --stanza=postgres archive-push %p'
# Nodo 3 (Réplika)
[nodo3]
pg1-path=/var/lib/postgresql/15/main
pg1-port=5432
pg1-host=192.168.1.216 # Dirección IP del nodo 3
stanza=postgres
archive-mode=on
archive-command='pgbackrest --stanza=postgres archive-push %p'
- Se configura el directorio donde se almacenarán los respaldos (
repo1-path
). - Se habilitan los respaldos rápidos (
start-fast=y
) y la compresión (compress=y
). - Cada nodo tiene su propia configuración de
pg1-path
ypg1-host
, y los parámetros dearchive-command
se ajustan para realizar los respaldos con pgBackRest.
Iniciando los Servicios
Una vez que la configuración de Patroni y pgBackRest está lista, se deben iniciar los servicios correspondientes:
sudo systemctl start patroni.service
sudo systemctl enable patroni.service
Esto iniciará el servicio de Patroni en los tres nodos y lo habilitará para que se inicie automáticamente en cada reinicio.
Verificando el Estado de Patroni
Puedes verificar el estado de Patroni usando una herramienta como curl
para realizar una solicitud HTTP a la API REST de Patroni en el nodo líder:
Para el nodo srvlropsql01
:
curl http://192.168.1.214:8008/patroni | jq .
Output
{
"state": "running",
"postmaster_start_time": "2025-02-27 10:38:12.906725+00:00",
"role": "master",
"server_version": 150010,
"xlog": {
"location": 285213000
},
"timeline": 14,
"replication": [
{
"usename": "replicator",
"application_name": "srvlropsql02",
"client_addr": "192.168.1.215",
"state": "streaming",
"sync_state": "async",
"sync_priority": 0
},
{
"usename": "replicator",
"application_name": "srvlropsql03",
"client_addr": "192.168.1.216",
"state": "streaming",
"sync_state": "async",
"sync_priority": 0
}
],
"dcs_last_seen": 1740653075,
"database_system_identifier": "7476020745627849320",
"patroni": {
"version": "3.0.2",
"scope": "keycloak-cluster"
}
}
Para el nodo srvlropsql01
:
curl http://192.168.1.215:8008/patroni | jq .
Output
{
"state": "running",
"postmaster_start_time": "2025-02-27 10:38:20.602283+00:00",
"role": "replica",
"server_version": 150010,
"xlog": {
"received_location": 285213000,
"replayed_location": 285213000,
"replayed_timestamp": null,
"paused": false
},
"timeline": 14,
"dcs_last_seen": 1740653115,
"database_system_identifier": "7476020745627849320",
"patroni": {
"version": "3.0.2",
"scope": "keycloak-cluster"
}
}
Para el nodo srvlropsql03
:
curl http://192.168.1.216:8008/patroni | jq .
Output
{
"state": "running",
"postmaster_start_time": "2025-02-27 10:38:36.525932+00:00",
"role": "replica",
"server_version": 150010,
"xlog": {
"received_location": 285213000,
"replayed_location": 285213000,
"replayed_timestamp": null,
"paused": false
},
"timeline": 14,
"dcs_last_seen": 1740653125,
"database_system_identifier": "7476020745627849320",
"patroni": {
"version": "3.0.2",
"scope": "keycloak-cluster"
}
}
Verificación del estado de la recuperación en PostgreSQL
-
Cambia al usuario
postgres
:
sudo su - postgres
Verifica si el servidor está en modo de recuperación utilizando el comando pg_is_in_recovery
:
psql -U postgres -c "SELECT pg_is_in_recovery();"
Output
pg_is_in_recovery
-------------------
f
(1 row)
f
: El servidor está en modo operativo normal (no en recuperación).t
: El servidor está en modo de recuperación (probablemente en una réplica o recuperando de una falla).
Comprobar el estado de la replicación
- Consulta el estado de la replicación en el servidor utilizando el siguiente comando:
psql -U postgres -c "SELECT * FROM pg_stat_replication;"
Output
pid | usesysid | usename | application_name | client_addr | client_hostname | client_port | backend_start | backend_xmin | state | sent_lsn | write_lsn | flush_lsn | replay_lsn | write_lag | flush_lag | replay_lag | sync_priority | sync_state | reply_time
------+----------+------------+------------------+---------------+-----------------+-------------+-------------------------------+--------------+-----------+------------+------------+------------+------------+-----------+-----------+------------+---------------+------------+-------------------------------
1602 | 16384 | replicator | srvlropsql02 | 192.168.1.215 | | 38202 | 2025-02-27 10:38:20.756912+00 | | streaming | 0/11000060 | 0/11000060 | 0/11000060 | 0/11000060 | | | | 0 | async | 2025-02-27 10:41:53.23572+00
1609 | 16384 | replicator | srvlropsql03 | 192.168.1.216 | | 53922 | 2025-02-27 10:38:46.672521+00 | | streaming | 0/11000060 | 0/11000060 | 0/11000060 | 0/11000060 | | | | 0 | async | 2025-02-27 10:41:56.916286+00
(2 rows)
Esto muestra los detalles de los procesos de replicación, incluyendo los nombres de las aplicaciones (srvlropsql02
, srvlropsql03
), las direcciones IP de los clientes, los estados de replicación (streaming
), y las posiciones de los registros de la réplica.
Comprobar los slots de replicación
Consulta los slots de replicación con el siguiente comando:
psql -U postgres -c "SELECT * FROM pg_replication_slots;"
Output
slot_name | plugin | slot_type | datoid | database | temporary | active | active_pid | xmin | catalog_xmin | restart_lsn | confirmed_flush_lsn | wal_status | safe_wal_size | two_phase
--------------+--------+-----------+--------+----------+-----------+--------+------------+------+--------------+-------------+---------------------+------------+---------------+-----------
srvlropsql02 | | physical | | | f | t | 1602 | | | 0/11000060 | | reserved | | f
srvlropsql03 | | physical | | | f | t | 1609 | | | 0/11000060 | | reserved | | f
(2 rows)
Los slots de replicación muestran el nombre del slot (srvlropsql02
, srvlropsql03
), el tipo de slot (físico), y si están activos. Los slots están reservados, lo que indica que la replicación está en marcha.
Ver los registros de Patroni
- Para revisar los registros del servicio Patroni, puedes usar
journalctl
:
sudo journalctl -u patroni --no-pager | tail -n 20
Recomendaciones y Mejores Prácticas
-
Monitoreo: Implementa herramientas como Prometheus y Grafana para supervisar el estado del clúster y configurar alertas ante fallos.
-
Respaldos: Realiza copias de seguridad regulares con herramientas como pgBackRest y asegúrate de almacenarlas de forma segura.
-
Escalabilidad: Añade nodos de lectura y ajusta la configuración para escalar horizontalmente según la carga.
-
Seguridad: Usa TLS para cifrar la comunicación entre nodos y clientes, y aplica políticas de acceso estrictas en PostgreSQL.
-
etcd: Mantén etcd replicado y monitoreado para asegurar la consistencia entre nodos.
-
Failover: Realiza pruebas periódicas de failover para asegurar la disponibilidad en caso de fallos.
-
Mantenimiento: Actualiza regularmente los componentes del sistema, verificando compatibilidad entre versiones.
-
Redundancia: Asegura redes y hardware redundantes para evitar interrupciones.
-
Optimización: Ajusta los parámetros de PostgreSQL según la carga y los recursos disponibles.
Conclusión
Implementar un sistema de PostgreSQL con Patroni, etcd y TLS ofrece una solución robusta para alta disponibilidad y escalabilidad. Patroni proporciona una gestión automatizada de failover y promoción de nodos, asegurando una disponibilidad continua de la base de datos. etcd garantiza una coordinación eficiente entre nodos, lo que permite mantener el consenso y la configuración distribuida. Además, TLS asegura las comunicaciones entre nodos, protegiendo los datos en tránsito con cifrado de alto nivel. Esta arquitectura asegura una base de datos altamente disponible, segura y fácil de escalar, ideal para entornos de producción críticos.
:wq!