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 resource create 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