Configuración de HA de servidores web con Pacemaker y Corosync
Introducción
En entornos de producción modernos, la alta disponibilidad (HA) de los servidores web no es un lujo, sino un requisito contractual. La interrupción del servicio web implica pérdida de ingresos, degradación de la marca y posibles penalizaciones por SLA. Para lograr una HA robusta y predecible, la combinación de Pacemaker como gestor de recursos de cluster y Corosync como capa de comunicación y membresía sigue siendo el estándar de facto en infraestructuras Linux.
Este artículo detalla la configuración de un clúster activo-pasivo para servidores web Apache/Nginx utilizando Pacemaker y Corosync sobre CentOS/Rocky Linux 9. Se asume que el lector posee conocimientos sólidos de administración de sistemas Linux y redes.
¿Por qué Pacemaker y Corosync?
Aunque existen alternativas como Keepalived (VRRP) o soluciones cloud-managed, Pacemaker ofrece un control granular sobre las dependencias, restricciones y órdenes de arranque de los recursos. Corosync proporciona el mecanismo de latido y la membresía del clúster.
| Característica | Keepalived + VRRP | Pacemaker + Corosync |
|---|---|---|
| Modelo | Activo-Pasivo simple | Activo-Pasivo / Activo-Activo |
| Dependencias | IP flotante + script | Múltiples recursos orquestados |
| Recuperación | Básica (script de fallo) | Políticas complejas (stickiness, migraciones) |
| Split-brain | No resuelto por defecto | Mecanismos de quorum y fencing |
| Escalabilidad | Baja | Alta (hasta 16 nodos) |
Pacemaker permite definir un recurso como una IP virtual (VIP), un servicio web, un sistema de archivos compartido, e incluso ejecutar scripts de verificación de estado antes de considerar el recurso como iniciado.
Arquitectura del Clúster
Para este tutorial, desplegaremos un clúster de dos nodos:
- Nodo1:
web-ha-01(IP: 192.168.1.10) - Nodo2:
web-ha-02(IP: 192.168.1.11) - VIP:
192.168.1.100 - Sistema operativo: Rocky Linux 9.3 minimal
- Servicio web: Nginx 1.24
- Almacenamiento: NFS compartido para
/var/www/html(opcional, pero recomendado para contenido estático)
Nota importante: Para entornos productivos, se recomienda un tercer nodo (o un voto externo) para evitar split-brain. En este ejemplo usaremos dos nodos con un quorum ignorado (no recomendado en producción sin fencing).
Paso 1: Preparación del Sistema Base
1.1 Configuración de Red y Hosts
Cada nodo debe tener una resolución de nombres consistente. Configuramos /etc/hosts en ambos nodos:
cat <<EOF >> /etc/hosts
192.168.1.10 web-ha-01
192.168.1.11 web-ha-02
EOF
1.2 Sincronización de Tiempo (NTP/Chrony)
Pacemaker depende de la sincronización temporal para los timestamps de eventos. Instalamos y configuramos chrony:
dnf install -y chrony
systemctl enable --now chronyd
chronyc sources -v
1.3 Configuración de Firewall
Pacemaker y Corosync requieren puertos específicos. En RHEL9, usamos firewalld:
firewall-cmd --permanent --add-service=high-availability
firewall-cmd --add-service=high-availability
firewall-cmd --permanent --add-port={5404/udp,5405/udp,21064/tcp}
firewall-cmd --add-port={5404/udp,5405/udp,21064/tcp}
Explicación:
5404/udpy5405/udpson para Corosync (multicast).21064/tcpes para Pacemaker Remote (si se usa en modo remoto). El serviciohigh-availabilityabre puertos adicionales como 2224/tcp (pacemaker).
1.4 Instalación de Pacemaker y Corosync
dnf install -y pacemaker corosync pcs resource-agents
pcs es la herramienta de gestión de clúster de línea de comandos. resource-agents proporciona los scripts OCF necesarios para controlar servicios como Nginx.
Paso 2: Configuración de Corosync
Corosync gestiona la comunicación entre nodos. Editamos /etc/corosync/corosync.conf:
totem {
version: 2
cluster_name: webcluster
secauth: off
transport: udpu
interface {
ringnumber: 0
bindnetaddr: 192.168.1.0
mcastport: 5405
ttl: 1
}
}
nodelist {
node {
ring0_addr: 192.168.1.10
name: web-ha-01
nodeid: 1
}
node {
ring0_addr: 192.168.1.11
name: web-ha-02
nodeid: 2
}
}
quorum {
provider: corosync_votequorum
two_node: 1
}
logging {
to_logfile: yes
logfile: /var/log/cluster/corosync.log
to_syslog: yes
}
Explicación de parámetros clave:
transport: udpu: Usa unicast en lugar de multicast, más fiable en entornos cloud.two_node: 1: Permite que el clúster funcione con solo dos nodos (ignora quorum). Requiere fencing.ring0_addr: IP real del nodo para comunicación interna.
Iniciamos Corosync en ambos nodos:
systemctl enable --now corosync
corosync-cfgtool -s # Verificar estado del anillo
corosync-cmapctl | grep members # Ver miembros
Nota de seguridad:
secauth: offdesactiva la autenticación entre nodos. En producción, se debe habilitar usandocrypto_cipherycrypto_hash.
Paso 3: Configuración de Pacemaker
Pacemaker se gestiona a través de pcsd, el daemon de configuración. Autenticamos los nodos:
systemctl enable --now pcsd
pcs host auth web-ha-01 web-ha-02 -u hacluster -p 'StrongPassword123'
Creamos el clúster desde un nodo:
pcs cluster setup webcluster web-ha-01 web-ha-02
pcs cluster start --all
pcs cluster status
Veremos algo como:
Cluster Status:
Stack: corosync
Current DC: web-ha-01 (version 2.1.5-1.el9_3.1-2b03bacd5d) - partition with quorum
Last updated: ...
Last change: ...
2 nodes configured
0 resource instances configured
Paso 4: Configuración de Recursos del Clúster
Ahora definimos los recursos: IP virtual, servicio Nginx y su verificación de estado.
4.1 Recurso IP Virtual (VIP)
pcs resource create VirtualIP ocf:heartbeat:IPaddr2 \
ip=192.168.1.100 \
cidr_netmask=24 \
nic=eth0 \
op monitor interval=10s timeout=30s \
--group WebGroup
Explicación:
ocf:heartbeat:IPaddr2: Agente OCF estándar para IP flotante.op monitor: Pacemaker verifica cada 10s que la IP esté configurada. Si falla, considera el recurso como degradado.--group WebGroup: Agrupa recursos para que se inicien y migren juntos.
4.2 Recurso Servicio Nginx
Necesitamos un agente OCF para Nginx. El paquete resource-agents incluye nginx pero puede no estar disponible en todas las versiones. Verificamos:
pcs resource agents ocf:heartbeat | grep nginx
Si no aparece, creamos un script personalizado o usamos systemd. Usaremos el agente systemd para mayor simplicidad:
pcs resource create WebService systemd:nginx \
op monitor interval=5s timeout=20s \
op start interval=0s timeout=60s \
op stop interval=0s timeout=60s \
--group WebGroup
Explicación:
systemd:nginx: Pacemaker controlará la unidad systemdnginx.service.op monitor: Cada 5s ejecutasystemctl is-active nginx. Si falla, Pacemaker intenta reiniciar en el mismo nodo.- Si el reinicio falla tras el número configurado de intentos (por defecto 1), migra el grupo
WebGroupal otro nodo.
4.3 Recurso de Filesystem Compartido (Opcional)
Si el contenido web está en un NFS compartido, añadimos:
pcs resource create WebFS ocf:heartbeat:Filesystem \
device="192.168.1.200:/exports/www" \
directory="/var/www/html" \
fstype="nfs" \
options="rw,hard,intr" \
op monitor interval=10s timeout=40s \
--group WebGroup
Orden de recursos: Pacemaker inicia WebFS primero, luego VirtualIP, y finalmente WebService. Esto se logra mediante el grupo. Para dependencias más complejas, usar
pcs constraint order.
4.4 Verificación de Configuración
pcs status resources
pcs constraint list --full
Salida esperada:
Resource Group: WebGroup
WebFS (ocf::heartbeat:Filesystem): Started web-ha-01
VirtualIP (ocf::heartbeat:IPaddr2): Started web-ha-01
WebService (systemd:nginx): Started web-ha-01
Paso 5: Configuración de Fencing (STONITH)
El fencing es obligatorio en producción para evitar corrupción de datos. Sin fencing, un nodo que falla puede seguir accediendo a recursos compartidos (split-brain). Implementamos fencing mediante IPMI o un switch gestionado.
Para este ejemplo (entorno de laboratorio), deshabilitamos el fencing, pero no es recomendado:
pcs property set stonith-enabled=false
pcs property set no-quorum-policy=ignore
Advertencia:
no-quorum-policy=ignorepermite que el clúster funcione con un solo nodo. Si los dos nodos pierden comunicación, ambos intentarán tomar el control de los recursos. Esto puede provocar corrupción de datos en sistemas de archivos compartidos.
5.1 Configuración de Fencing con IPMI (Ejemplo)
pcs stonith create MyIPMI fence_ipmilan \
pcmk_host_list="web-ha-01 web-ha-02" \
ipaddr="192.168.1.201" \
login="admin" \
passwd="secret" \
lanplus=1 \
action=reboot \
op monitor interval=60s timeout=20s
Explicación:
fence_ipmilan: Agente de fencing para IPMI.pcmk_host_list: Mapea nombres de nodos a IPMI.action=reboot: El nodo problemático será reiniciado por IPMI antes de que el otro nodo tome los recursos.
Paso 6: Pruebas de Failover
6.1 Fallo Manual del Servicio Web
Detenemos Nginx en el nodo activo:
ssh web-ha-01 'systemctl stop nginx'
Pacemaker detecta el fallo en la monitorización (5s) y reinicia Nginx automáticamente en el mismo nodo. Verificamos:
pcs status
6.2 Fallo del Nodo Activo
Simulamos un crash del nodo primario:
ssh web-ha-01 'echo c > /proc/sysrq-trigger' # ¡Cuidado! Reinicia el nodo
En el nodo superviviente, Pacemaker detecta la pérdida de comunicación, espera el tiempo de dead-time (por defecto 20s) y migra todos los recursos:
pcs status
La VIP y el servicio Nginx ahora están en web-ha-02. El tiempo total de conmutación suele ser inferior a 30 segundos.
6.3 Recuperación del Nodo Caído
Cuando web-ha-01 se reinicia, Corosync lo detecta y lo une al clúster. Por defecto, los recursos no vuelven automáticamente al nodo original (stickiness). Para forzar la vuelta:
pcs resource move WebGroup web-ha-01
O configurar resource-stickiness:
pcs resource defaults resource-stickiness=100
Con stickiness=100, el recurso permanece en el nodo actual a menos que el otro nodo tenga una puntuación mayor (por ejemplo, por una restricción de ubicación).
Paso 7: Monitoreo y Mantenimiento
7.1 Logs del Clúster
Los logs principales están en:
/var/log/cluster/corosync.log(comunicación)/var/log/pacemaker.log(decisiones de recursos)journalctl -u pacemaker -f(tiempo real)
7.2 Herramientas de Monitoreo
pcs status– Estado resumido.pcs resource debug-start WebService– Prueba manual de inicio de recurso.crm_mon -1– Vista detallada de recursos y restricciones.pcs constraint show --full– Muestra todas las restricciones de orden y ubicación.
7.3 Actualizaciones del Clúster
Para actualizar el sistema operativo sin downtime:
- Poner el nodo en modo mantenimiento:
pcs node standby web-ha-01 - Verificar que todos los recursos están en
web-ha-02. - Actualizar paquetes en
web-ha-01y reiniciar. - Una vez operativo, quitar el standby:
pcs node unstandby web-ha-01 - Repetir para
web-ha-02.
Nota: Durante la actualización, el clúster es vulnerable si el nodo activo falla. Para entornos críticos, considere un tercer nodo.
Conclusión y Mejores Prácticas
Hemos configurado un clúster HA funcional con Pacemaker y Corosync para servidores web. Los puntos clave a recordar:
- Fencing es obligatorio en producción. Sin él, no hay garantía de integridad de datos.
- Pruebe el failover regularmente – Documente y automatice las pruebas.
- Monitoree los logs – Los fallos silenciosos de Corosync pueden pasar desapercibidos.
- Use grupos para recursos relacionados – Simplifica la migración y las dependencias.
- Ajuste los tiempos de monitorización – Valores demasiado agresivos pueden causar falsos positivos; demasiado lentos, mayor tiempo de inactividad.
Para entornos con alta carga, considere extender el clúster a modo activo-activo con balanceo de carga (por ejemplo, HAProxy + Pacemaker), aunque esto añade complejidad en la sincronización de sesiones y archivos.
El clúster configurado es la base sobre la que puede añadir recursos adicionales: bases de datos, colas de mensajes, o incluso contenedores Docker gestionados por Pacemaker. La flexibilidad de Pacemaker permite orquestar cualquier recurso que tenga un agente OCF, convirtiéndolo en la herramienta definitiva para la alta disponibilidad en Linux.
