Pacemaker, Corosync, DRBD… High Availability de tres nodos en Centos7

Tutoriales de como configurar un Cluster de Alta Disponibilidad en Centos 7 con Pacemaker y Corosync hay muchos, de DRBD también, pero si en lugar de 2 nodos, queremos 3, ya no hay tantos.

A priori, la diferencia no debería ser tanta, sin embargo, sobre todo para el caso de DRBD, la diferencia entre 2 y 3 nodos a nivel de configuración es suficientemente importante como para que haya sido un quebradero de cabeza configurarlo…

Empecemos identificando las tecnologías que utilizaremos:

  • Pacemaker: Pacemaker es un gestor de recursos de Alta Disponibilidad (High Availability) Open Source utilizado en clusters de ordenadores.
  • Corosync: El motor de Cluster Corosync es el encargado de gestionar un sistema de comunicación implementando la alta disponibilidad entre aplicaciones. Podríamos decir que Corosync se encarga de la “mensajería” entre los nodos del cluster.
  • DRBD: DRBD es un sistema de almacenamiento replicado y distribuido (Distributed Replicated Block Device) para Linux, implementado a nivel de driver de Kernel, que nos permitirá replicar los datos en tiempo real entre nodos del cluster.

Una vez presentadas las tecnologías, veremos la configuración e instalación de las mismas.

Instalando DRBD

1. Para instalar DRBD deberemos activar el repositorio ElRepo en los nodos a utilizar. Esto es debido a que DRBD no viene en los repositorios por defecto de CentOS o RHEL.

 
rpm --import https://www.elrepo.org/RPM-GPG-KEY-elrepo.org
rpm -Uvh http://www.elrepo.org/elrepo-release-7.0-3.el7.elrepo.noarch.rpm

2. Instalar los paquetes necesarios para DRBD

 
yum install -y drbd90-utils kmod-drbd90

3. Comprobar que el módulo está correctamente cargado

 
lsmod | grep -i drbd
  drbd_transport_tcp 22144 2 
  drbd 541356  3 drbd_transport_tcp

4. En caso que no estuviera cargado, lo cargaríamos

modprobe drbd

5. Nótese que con este comando sólo se carga el módulo para la sesión actual, por lo que para que se cargue en el siguiente reinicio, aún nos quedaría un paso adicional

 
echo drbd > /etc/modules-load.d/drbd.conf

Configurando DRBD

Una vez instalado, pasamos a la configuración del servicio. Para ello, además del paso previo de instalar los paquetes, deberemos tener una partición disponible, del mismo tamaño en todos los servidores, que utilizaremos para el almacenamiento de los datos. Además, deberemos tener configuradas IPs estáticas en los tres servidores, que en este artículo llamaremos serv1, serv2 y serv3, además, configuraremos en el fichero de hosts de todos los nodos los nombres e IPs del resto de nodos del cluster.

cat /etc/hosts
 192.168.0.201 serv1
 192.168.0.202 serv2
 192.168.0.203 serv3

0. Como paso previo, configuraremos selinux en permissive, para facilitar los posibles problemas que tengamos posteriormente

cat /etc/selinux/config 
# This file controls the state of SELinux on the system.
# SELINUX= can take one of these three values:
# enforcing - SELinux security policy is enforced.
# permissive - SELinux prints warnings instead of enforcing.
# disabled - No SELinux policy is loaded.
SELINUX=permissive
# SELINUXTYPE= can take one of three two values:
# targeted - Targeted processes are protected,
# minimum - Modification of targeted policy. Only selected processes are protected. 
# mls - Multi Level Security protection.
SELINUXTYPE=targeted 

1. Primero configuraremos los parámetros globales y comunes del cluster. Estos son los que yo he escogido, para ver si hay otros que te encajen mejor, consulta la documentación

cat /etc/drbd.d/global_common.conf 
global {
  usage-count no;
}
common {
  net {
    protocol C;
    max-buffers 36k;
    sndbuf-size 1024k;
    rcvbuf-size 2048k;
  }
  disk {
    c-plan-ahead 5;
    c-min-rate 30M;
    c-max-ratec-max-rat 90M;
    c-fill-target 2M;
  }
}

Expliquemos un poco las opciones elegidas:

  • usage-count: Participar o no en las estadísticas de uso (anónimas) de DRBD
  • protocol C: Se considera una escritura como completa cuando está finalizada en el disco local y en los remotos. Es la opción mas lenta pero mas segura
  • max-buffers: Limita el uso de memoria por dispositivo en el lado de recepción, o para buffers internos durante la re-sincronización o la verificación online
  • sndbuf-size: Configura el tamaño del buffer de envío de TCP/IP
  • rcvbuf-size: Configura el tamaño del buffer de recepción de TCP/IP
  • c-plan-ahead: Este parámetro controla dinámicamente la velocidad de re-sincronización, definiendo como de rápido DRBD se adapta a cambios en la velocidad de re-sincronía.
  • c-min-rate: Este parámetro limita cuanto ancho de manda se deja disponible para la I/O de re-sincronización, el resto se utiliza para le I/O de aplicaciones
  • c-max-rate: Este parámetro configura el máximo ancho de banda utilizado
  • c-fill-target: Cantidad de datos que se llenará en el buffer como objetivo de c-plan-ahead

2. Ahora configuraremos el recurso que sincronizaremos, en nuestro caso, lo hemos llamado drbd0

cat /etc/drbd.d/drbd0.res
   resource drbd0 {
   device /dev/drbd0;
   meta-disk internal;
   on serv1 {
      disk /dev/sda3;
      node-id 0;
      address 192.168.0.201:7701;
   }
   on serv2 {
      disk /dev/sda3;
      node-id 1;
      address 192.168.0.202:7702;
   }
   on serv3 {
      disk /dev/sda3;
      node-id 2;
      address 192.168.0.203:7703;
   }
   connection-mesh {
      hosts serv1 serv2 serv3;
      net {
         use-rle no;
      }
   }
}

Expliquemos un poco las opciones elegidas en el fichero del recurso drbd0:

  • resource drbd0: El nombre del recurso
  • device /dev/drbd0: El dispositivo que se creará
  • meta-disk: Indica dónde se almacenarán los metadatos del dispositivo de bloques que repliquemos. Internal indica que el dispositivo de bloques a bajo nivel contendrá los datos y los metadatos.
  • Posteriormente indicamos la lista de servidores en los que replicaremos los datos, indicando para cada uno el id, su IP:Puerto donde DRBD se conectará, y el dispositivo local donde cada servidor almacenará los datos y metadatos
  • connection-mesh: Este es el parámetro mas importante cuando tenemos un cluster DRBD de mas de 2 nodos, pues define la malla de sincronización entre todos los servidores
  • use-rle no: Indica que el bitmap, usado en el cluster para comprobar el estado de la sincronización entre nodos, debe transferirse cifrado o no. Es útil en casos de ancho de banda limitado

3. Ahora configuraremos el Firewall para admitir conexiones en todos los nodos desde los otros nodos, para ello, ejecutaremos lo siguiente en todos los nodos del cluster. En caso que las IPs y/o puertos sean diferentes en el drbd0.conf, deberemos ajustarlos en el firewall

firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="192.168.0.201" port port="7701" protocol="tcp" accept'
firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="192.168.0.202" port port="7701" protocol="tcp" accept'
firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="192.168.0.203" port port="7701" protocol="tcp" accept'

firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="192.168.0.201" port port="7702" protocol="tcp" accept'
firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="192.168.0.202" port port="7702" protocol="tcp" accept'
firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="192.168.0.203" port port="7702" protocol="tcp" accept'

firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="192.168.0.201" port port="7703" protocol="tcp" accept'
firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="192.168.0.202" port port="7703" protocol="tcp" accept'
firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="192.168.0.203" port port="7703" protocol="tcp" accept'
firewall-cmd --reload

4. Ahora crearemos el almacenamiento de los metadatos en todos los nodos

drbdadm create-md drbd0

5. Iniciaremos el servicio y lo configuraremos para que se inicie automáticamente durante el arranque

 
systemctl start drbd
systemctl enable drbd

6. Una vez Iniciado el servicio, ya podremos levantar el dispositivo

 drbdadm up drbd0 

En este momento, el cluster debería indicar que tiene 3 nodos, pero en estado inconsistente, para ver el estado, ejecutaremos el siguiente comando

 
drbdadm status drbd0
  drbd0 role:Secondary
   disk: Inconsistent
   serv2 role:Secondary
      peer-disk: Inconsistent
   serv3 role:Secondary
      peer-disk: Inconsistent

7. Ahora, forzaremos al nodo 1 como maestro, de tal forma que sus datos serán considerados como los válidos

drbdadm primary drbd0

En el caso que la salida del comando sea un error, forzaremos el cambio

drbdadm primary drbd0 --force

8. Una vez ya tengamos el nodo maestro configurado, podremos crear un sistema de ficheros y montar los datos en el servidor que hayamos seleccionado como maestro (serv1 en nuestro caso)

 
mkfs.ext4 /dev/drbd0
mount /dev/drbd0 /mnt

Podemos comprobar el estado de la sincronización utilizando el comando de status, que mostrará el progreso de la copia de datos en los nodos secundarios, quedando en estado “UpToDate” cuando la sincronización esté completa

 
drbdadm status drbd0 
 drbd0 role:Primary 
   disk:UpToDate 
   serv2 role:Secondary 
      peer-disk: UpToDate 
   serv3 role:Secondary 
      peer-disk: UpToDate 

Con esto, ya tendríamos lista la replicación de los datos, pasaremos ahora a la instalación y configuración de la Alta Disponibilidad

Instalando Pacemaker y Corosync

1. Instalamos los paquetes necesarios para Pacemaker, Corosync y para la gestión del cluster

 
yum -y install corosync pacemaker pcs

2. Configuramos los servicios para su inicio automático durante el arranque

systemctl enable pcsd
systemctl enable corosync
systemctl enable pacemaker

3. Iniciamos pcs en todos los nodos

systemctl start pcsd 

4. Configuramos una contraseña para el usuario ‘hacluster’ (que se habrá creado automáticamente durante la instalación). La contraseña debe ser igual en todos los servidores

passwd hacluster
Enter new password:

5. En este paso autorizaremos los 3 servidores para el cluster. Este comando sólo se ejecutará en serv1. Obviamente, sustituiremos PASSWORD por la contraseña elegida. Si todo ha salido bien, obtendremos como salida que los servidores están Autorizados

pcs cluster auth serv1 serv2 serv3
 Username: hacluster
 Password: PASSWORD
  serv3: Authorized
  serv2: Authorized
  serv1: Authorized

6. Ahora crearemos un nuevo cluster. Este comando sólo se ejecutará en serv1. Sustituiremos el NOMBRE_CLUSTER por el nombre que le queramos poner al cluster.

pcs cluster setup --name NOMBRE_CLUSTER serv1 serv2 serv3

7. Iniciamos los servicios del cluster. Este comando sólo se ejecutará en serv1.

pcs cluster start --all
pcs cluster enable --all

8. Configuramos el Firewall. Este comando debe ejecutarse en todos los servidores

 
firewall-cmd --permanent --add-service=high-availability
firewall-cmd --reload

9. Comprobamos el estado del cluster

pcs status cluster
 Cluster Status:
 Stack: corosync
 Current DC: serv2 (version 1.1.18-11.el7_5.3-2b07d5c5a9) - partition with quorum
 Last updated: Sun Sep 9 22:19:42 2018
 Last change: Sun Sep 9 18:40:35 2018 by root via cibadmin on serv3
 3 nodes configured 
 0 resources configured
 PCSD Status:
   serv1: Online
   serv3: Online
   serv2: Online

9. Para nuestro ejemplo, desactivaremos STONITH y configuraremos la política de Quorum. Este comando sólo se ejecutará en serv1.

pcs property set stonith-enabled=false
pcs property set no-quorum-policy=ignore

STONITH (Shoot The Other Node In The Head) es la implementación de “cerco” o “fencing” de Pacemaker, protege los datos de corromperse debido a acceso concurrente no intencionado, en nuestro caso DRBD no nos lo permitirá, así que lo desactivaremos. Para mas información, consultar la documentación

La política de Quorum indica que haremos en caso que no exista quorum en el cluster, en nuestro caso, continuaremos con la gestión del cluster en ese caso, ya que tenemos 3 servidores para evitar que no consigamos quorum. Para mas opciones, consultar la documentación

Llegados a este punto, ya tenemos un cluster de Alta Disponibilidad listo, pero no está gestionando nada. Para que el cluster sea útil, deberemos configurarle tantos recursos como necesitemos. En nuestro caso, vamos a configurar una IP Flotante y la gestión del sistema de ficheros asociado a la partición DRBD

Configurar la IP Flotante en Pacemaker

Una IP Flotante es una dirección IP que puede ser migrada o movida automáticamente de un servidor a otro servidor dentro de la misma red. Para nuestro ejemplo, la IP elegida es la 192.168.0.205. Esta IP es la que el servidor maestro tendrá configurada siempre, y será a la que deberemos apuntar el DNS o los servicios, pues es la IP que siempre estará disponible, no importa que servidor sea el maestro.

1. Configuramos la IP Flotante

pcs resource create virtual_ip ocf:heartbeat:IPaddr2 ip=192.168.0.205 cidr_netmask=32 op monitor interval=30s

2. Comprobamos el estado del recurso que acabamos de crear, donde veremos en que servidor está configurada la IP flotante

pcs status resources
  virtual_ip	(ocf::heartbeat:IPaddr2):	Started serv1

3. En caso que queramos modificar la IP posteriormente, deberemos ejecutar el siguiente comando

  pcs resource update virtual_ip IPaddr2 ip=192.168.0.XXX

 

Configuración de DRBD en Pacemaker

La configuración de DRBD en Pacemaker implica que creemos varios recursos, para ello, utilizaremos una opción de pcs que nos permite encolar varios comandos y ejecutarlos al mismo tiempo. Estos comandos serán ejecutados únicamente en serv1

 
pcs cluster cib drbd_cfg

1. Creamos el recurso de los datos para DRBD

 
pcs -f drbd_cfg resource create DrbdData ocf:linbit:drbd drbd_resource=drbd0 op monitor interval=60s

2. Creamos el recurso de clonado de DRBD, que permitirá que el recurso esté funcionando en varios nodos al mismo tiempo. Este comando deberemos adaptarlo en caso que tengamos un número diferente de nodos

 
pcs -f drbd_cfg resource master DrbdDataClone DrbdData master-max=1 master-node-max=1 clone-max=3 clone-node-max=1 notify=true

3. Ahora ejecutaremos las instrucciones en el cluster

 
pcs cluster cib-push drbd_cfg

Comprobamos el estado del cluster. Si todo es correcto, veremos que el serv1 es el maestro de DRBD

pcs status resources
 virtual_ip	(ocf::heartbeat:IPaddr2): Started serv1
 Master/Slave Set: DrbdDataClone [DrbdData]
    Masters: [ serv1 ]
    Slaves: [ serv2 serv3 ]

4. Ahora crearemos un recurso que montará el sistema de ficheros en el servidor maestro, en la carpeta /var/datos

pcs cluster cib fs_cfg
pcs -f fs_cfg DrbdFS Filesystem device="/dev/drbd0" directory="/var/datos" fstype="ext4"

Una vez llegados a este punto, tenemos todos los recursos creados, sin embargo, necesitamos añadir restricciones, para que el cluster sepa en que orden deben los recursos ser configurados, así como dónde deben configurarse.

pcs -f fs_cfg constraint colocation add DrbdFS with DrbdDataClone INFINITY with-rsc-role=Master
pcs -f fs_cfg constraint order promote DrbdDataClone then start DrbdFS
pcs -f fs_cfg constraint colocation add virtual_ip with DrbdFS INFINITY
pcs -f fs_cfg constraint order DrbdFS then virtual_ip
pcs cluster cib-push fs_cfg

Como vemos, vamos a utilizar 2 tipos de restricciones, colocation y order

  • Restricción de tipo colocation: Esta restricción indica al cluster que recursos deben estar juntos (o no)
  • Restricción de tipo order: Esta restricción indica al cluster en que orden deben los recursos configurarse

Expliquemos un poco mas en profundidad las restricciones que estamos configurando

  • colocation DrbdFS con DrbdDataClone INFINITY with-rsc-role=Master: Esta restricción le indica al cluster que debe configurar el sistema de ficheros de DRBD únicamente con un nodo que tenga el rol master
  • order promote DrbdDataClone then start DrbdFS: Esta restricción le indica al cluster que debe promocionar a master primero el nodo de DRBD, y que posteriormente debe montar el sistema de ficheros. DRBD no permitirá que un nodo no Primary monte los datos, por lo que esta restricción es para evitar ese caso
  • colocation add virtual_ip with DrbdFS INFINITY: Esta restricción le indica al cluster que la IP Flotante debe estar junto con el nodo que tenga montado el sistema de ficheros DRBD
  • order DrbdFS then virtual_ip: Esta restricción le indica al cluster que primero debe configurarse el sistema de ficheros, y posteriormente, la IP Flotante, así evitaremos que el servicio sea accedido antes de que esté disponible

5. Comprobamos el estado del cluster

pcs status resources
 virtual_ip	(ocf::heartbeat:IPaddr2):	Started serv1
 Master/Slave Set: DrbdDataClone [DrbdData]
    Masters: [ serv1 ]
    Slaves: [ serv2 serv3 ]
 DrbdFS	(ocf::heartbeat:Filesystem):	Started serv1

6. Podemos forzar el fail-over manualmente para comprobar que el cluster funciona correctamente. Podemos ejecutar este comando en cualquier nodo del cluster, pero si no especificamos el nombre del nodo, detendremos el nodo en el cual lo estemos ejecutando

 pcs cluster stop serv1
 node1: Stopping Cluster (pacemaker)...
 node1: Stopping Cluster (corosync)...

Y comprobamos nuevamente el estado

 
pcs status resources 
 virtual_ip (ocf::heartbeat:IPaddr2): Started serv3 
 Master/Slave Set: DrbdDataClone [DrbdData] 
    Masters: [ serv3 ] 
    Slaves: [ serv2 ] 
    Stopped: [ serv1 ]
 DrbdFS (ocf::heartbeat:Filesystem): Started serv3 

Si introducimos nuevamente el nodo1 en el cluster, observaremos que los recursos continúan en el nodo3, aunque el nodo1 aparece nuevamente como slave, listo para retomar los recursos en caso de ser necesario

 
pcs cluster start serv1 
  node1: Starting Cluster (pacemaker)... 
  node1: Starting Cluster (corosync)... 

pcs status resources 
 virtual_ip (ocf::heartbeat:IPaddr2): Started serv3 
 Master/Slave Set: DrbdDataClone [DrbdData] 
   Masters: [ serv3 ] 
   Slaves: [ serv2 serv1 ] 
 DrbdFS (ocf::heartbeat:Filesystem): Started serv3 

Con esto, ya tendríamos un cluster de Pacemaker corriendo en 3 nodos Centos 7, así como una partición replicada entre ellos.

Obviamente, esto en sí no tiene mucha utilidad, ya que realmente no estamos corriendo ningún servicio en nuestro cluster, pero no es especialmente complejo ampliar el cluster para ejecutar cualquier servicio que deseemos, por ejemplo un servidor web, adaptando convenientemente las restricciones para que el servicio únicamente se ejecute en el servidor que tiene el sistema de ficheros y la IP Flotante.

Espero que os haya sido de utilidad y gracias por visitarme!

Málaga, Septiembre de 2018