Tutorial de Pacemaker – Configurar un Cluster en Linux Centos

Share on facebook
Share on twitter
Share on linkedin
Share on whatsapp
Share on telegram
Share on email

Pacemaker es un software opensource, con soporte de RedHat, para la configuración de servicios en cluster o con alta disponibilidad.

A continuación, puedes ver cómo configurar Pacemaker con DRBD, un software de réplica de datos de filesystems en modo activo-pasivo. Más adelante tienes acceso a la documentación.

Tutorial de Pacemaker
Configuración de un Cluster de MySQL en Linux con Pacemaker y Réplica de Datos con DRBD

Instalación del software necesario

Lo primero de todo es instalar el software necesario en todos los nodos donde vayamos a compartir el mismo disco. Todo el procedimiento lo voy a realizar en Linux CentOS 7.

yum -y install pcs fence-agents-all lvm2-cluster

Si lo instalas en RedHat 7 en vez de en CentOS 7, necesitarás la suscripción de los paquetes de Hight Availability o, bien, descargarte la ISO de RedHat e instalarlos manualmente. Sin embarglo, para tener soporte oficial de RedHat y poder abrir casos en caso de incidencia, se necesita comprar la suscripción.

[[email protected] HighAvailability]# pwd
/RHEL76/mnt/addons/HighAvailability
[[email protected] HighAvailability]# ll |grep pcs
-r--r--r-- 1 root root    12084 Jun 26  2018 clufter-lib-pcs-0.77.1-1.el7.noarch.rpm
-r--r--r-- 1 root root  5290156 Aug 31  2018 pcs-0.9.165-6.el7.x86_64.rpm
-r--r--r-- 1 root root    79808 Aug 31  2018 pcs-snmp-0.9.165-6.el7.x86_64.rpm
[[email protected] HighAvailability]#

Bloqueo de LVM para que sea gestionado por el cluster

Habilitamos el bloqueo por cluster en todos los nodos:

lvmconf --enable-cluster
reboot


Este comando, configura la directiva locking_type en el fichero /etc/lvm/lvm.conf:

[[email protected] ~]# grep locking_type /etc/lvm/lvm.conf |grep -v "#"
    locking_type = 3
[[email protected] ~]#

Configuración del cluster con Pacemaker

Arrancamos los servicios en ambos nodos:

[[email protected] ~]# systemctl start pcsd
[[email protected] ~]# systemctl enable pcsd
Created symlink from /etc/systemd/system/multi-user.target.wants/pcsd.service to /usr/lib/systemd/system/pcsd.service.
[[email protected] ~]#

Repetimos los mismos comandos en el resto de nodos del cluster

Asignamos una contraseña al usuario de administración de Pacemaker):

[[email protected] ~]# passwd hacluster
Changing password for user hacluster.
New password: 
BAD PASSWORD: The password fails the dictionary check - it is based on a dictionary word
Retype new password: 
passwd: all authentication tokens updated successfully.
[[email protected] ~]#

Autorizamos el acceso de los nodos que forman parte del cluster:

[[email protected] ~]# pcs cluster auth pacemakercl1 pacemakercl2
Username: hacluster
Password:
pacemakercl2: Authorized
pacemakercl1: Authorized
[[email protected] ~]#

Creamos la configuración básica del cluster, lo arrancamos y comprobamos su estado:

[[email protected] ~]# pcs cluster setup --name ha_cluster pacemakercl1 pacemakercl2
Destroying cluster on nodes: pacemakercl1, pacemakercl2...
pacemakercl1: Stopping Cluster (pacemaker)...
pacemakercl2: Stopping Cluster (pacemaker)...
pacemakercl1: Successfully destroyed cluster
pacemakercl2: Successfully destroyed cluster

Sending 'pacemaker_remote authkey' to 'pacemakercl1', 'pacemakercl2'
pacemakercl1: successful distribution of the file 'pacemaker_remote authkey'
pacemakercl2: successful distribution of the file 'pacemaker_remote authkey'
Sending cluster config files to the nodes...
pacemakercl1: Succeeded
pacemakercl2: Succeeded

Synchronizing pcsd certificates on nodes pacemakercl1, pacemakercl2...
pacemakercl2: Success
pacemakercl1: Success
Restarting pcsd on the nodes in order to reload the certificates...
pacemakercl2: Success
pacemakercl1: Success
[[email protected] ~]#

[[email protected] ~]# pcs cluster start --all
pacemakercl1: Starting Cluster (corosync)...
pacemakercl2: Starting Cluster (corosync)...
pacemakercl1: Starting Cluster (pacemaker)...
pacemakercl2: Starting Cluster (pacemaker)...
[[email protected] ~]#

[[email protected] ~]# pcs status cluster
Cluster Status:
 Stack: unknown
 Current DC: NONE
 Last updated: Sat Jun 15 10:16:51 2019
 Last change: Sat Jun 15 10:16:33 2019 by hacluster via crmd on pacemakercl2
 2 nodes configured
 0 resources configured

PCSD Status:
  pacemakercl1: Online
  pacemakercl2: Online
[[email protected] ~]#

[[email protected] ~]# pcs status corosync

Membership information
----------------------
    Nodeid      Votes Name
         1          1 pacemakercl1 (local)
         2          1 pacemakercl2
[[email protected] ~]#

Creamos un grupo de recursos o servicios

Para este ejemplo, voy a crear un grupo de recursos llamado MySQLGroup que montará un filesystem y dará de alta una IP. Lo haremos de la siguiente manera:

  • Añadimos el filesystem
[[email protected] ~]# pcs resource create MySQL_fs Filesystem device="/dev/vgmysql/lvmysql" directory="/MySQL" fstype="xfs" --group MySQLGroup
Assumed agent name 'ocf:heartbeat:Filesystem' (deduced from 'Filesystem')
[[email protected] ~]#
  • Añadimos la IP de servicio
[[email protected] ~]# pcs resource create VirtualIP IPaddr2 ip=10.0.1.50 cidr_netmask=24 --group MySQLGroup
Assumed agent name 'ocf:heartbeat:IPaddr2' (deduced from 'IPaddr2')
[[email protected] ~]#
  • Comprobamos el estado de los recursos que acabamos de crear
[[email protected] ~]# pcs resource show
 Resource Group: MySQLGroup
     MySQL_fs   (ocf::heartbeat:Filesystem):    Stopped
     VirtualIP  (ocf::heartbeat:IPaddr2):       Stopped
[[email protected] ~]#

Desde el otro nodo también se puede comprobar:

[[email protected] ~]# pcs resource show
 Resource Group: MySQLGroup
     MySQL_fs   (ocf::heartbeat:Filesystem):    Stopped
     VirtualIP  (ocf::heartbeat:IPaddr2):       Stopped
[[email protected] ~]#

Arrancamos los recursos del cluster

[[email protected] ~]# pcs property set stonith-enabled=false
[[email protected] ~]# pcs resource show
 Resource Group: MySQLGroup
     MySQL_fs   (ocf::heartbeat:Filesystem):    Started pacemakercl1
     VirtualIP  (ocf::heartbeat:IPaddr2):       Started pacemakercl1
[[email protected] ~]#
  • Comprobamos que tanto el filesystem como la IP de servicio están disponibles:
[[email protected] ~]# df -hP /MySQL/
Filesystem                   Size  Used Avail Use% Mounted on
/dev/mapper/vgmysql-lvmysql 1017M   33M  985M   4% /MySQL
[[email protected] ~]# ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9001 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 06:7d:c0:f8:2d:60 brd ff:ff:ff:ff:ff:ff
    inet 10.0.1.16/24 brd 10.0.1.255 scope global dynamic eth0
       valid_lft 3375sec preferred_lft 3375sec
    inet 10.0.1.50/24 brd 10.0.1.255 scope global secondary eth0
       valid_lft forever preferred_lft forever
    inet6 fe80::47d:c0ff:fef8:2d60/64 scope link
       valid_lft forever preferred_lft forever
[[email protected] ~]#

Mover recursos del cluster

Ahora movemos el grupo de recursos al grupo secundario:

[[email protected] ~]# pcs resource move MySQLGroup pacemakercl2
[[email protected] ~]# pcs resource show
 Resource Group: MySQLGroup
     MySQL_fs   (ocf::heartbeat:Filesystem):    Started pacemakercl2
     VirtualIP  (ocf::heartbeat:IPaddr2):       Started pacemakercl2
[[email protected] ~]#

Comprobamos que en el nodo primario ya no está ni montado el filesystem ni dada de alta la IP de servicio:

[[email protected] ~]# ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9001 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 06:7d:c0:f8:2d:60 brd ff:ff:ff:ff:ff:ff
    inet 10.0.1.16/24 brd 10.0.1.255 scope global dynamic eth0
       valid_lft 3126sec preferred_lft 3126sec
    inet6 fe80::47d:c0ff:fef8:2d60/64 scope link
       valid_lft forever preferred_lft forever
[[email protected] ~]#

En cambio sí están habilitados ambos servicios en el nodo secundario, tal y como esperábamos:

[[email protected] ~]# ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9001 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 06:f6:c7:1a:06:40 brd ff:ff:ff:ff:ff:ff
    inet 10.0.1.237/24 brd 10.0.1.255 scope global dynamic eth0
       valid_lft 2964sec preferred_lft 2964sec
    inet 10.0.1.50/24 brd 10.0.1.255 scope global secondary eth0
       valid_lft forever preferred_lft forever
    inet6 fe80::4f6:c7ff:fe1a:640/64 scope link
       valid_lft forever preferred_lft forever
[[email protected] ~]#

Parar y volver a arrancar los recursos del cluster

Parada:

[[email protected] ~]# pcs resource disable MySQLGroup
[[email protected] ~]# pcs resource show
 Resource Group: MySQLGroup
     MySQL_fs   (ocf::heartbeat:Filesystem):    Stopped (disabled)
     VirtualIP  (ocf::heartbeat:IPaddr2):       Stopped (disabled)
[[email protected] ~]#

Arranque:

[[email protected] ~]# pcs resource enable MySQLGroup
[[email protected] ~]# pcs resource show
 Resource Group: MySQLGroup
     MySQL_fs   (ocf::heartbeat:Filesystem):    Started pacemakercl1
     VirtualIP  (ocf::heartbeat:IPaddr2):       Started pacemakercl1
[[email protected] ~]#

Eliminar un recurso del cluster

Si queremos eliminar alguno de los recursos del cluster de Pacemaker que hemos creado anteriormente, utilizaremos el siguiente comando:

[[email protected] ~]# pcs resource delete MySQL_fs
Deleting Resource - MySQL_fs
[[email protected] ~]# pcs resource show
 Resource Group: MySQLGroup
     VirtualIP  (ocf::heartbeat:IPaddr2):       Stopped (disabled)
[[email protected] ~]#

Modificar recursos del cluster

[[email protected] ~]# pcs resource update drbdmysqlFS op start interval=10 timeout=60
[[email protected] ~]# pcs resource update drbdmysqlFS op notify interval=10 timeout=60
[[email protected] ~]# pcs resource update drbdmysqlFS op stop interval=10 timeout=60
[[email protected] ~]#

[[email protected] ~]# pcs config show drbdmysqlFS
Cluster Name: ha_cluster
Corosync Nodes:
 pacemakercl1 pacemakercl2
Pacemaker Nodes:
 pacemakercl1 pacemakercl2

Resources:
 Group: MySQLGroup
  Resource: VirtualIP (class=ocf provider=heartbeat type=IPaddr2)
   Attributes: cidr_netmask=24 ip=10.0.1.50
   Operations: monitor interval=10s timeout=20s (VirtualIP-monitor-interval-10s)
               start interval=0s timeout=20s (VirtualIP-start-interval-0s)
               stop interval=0s timeout=20s (VirtualIP-stop-interval-0s)
  Resource: drbdmysqlFS (class=ocf provider=heartbeat type=Filesystem)
   Attributes: device=/dev/drbd0 directory=/MySQL fstype=xfs
   Operations: monitor interval=20s timeout=40s (drbdmysqlFS-monitor-interval-20s)
               notify interval=10 timeout=60 (drbdmysqlFS-notify-interval-10)
               start interval=10 timeout=60 (drbdmysqlFS-start-interval-10)
               stop interval=10 timeout=60 (drbdmysqlFS-stop-interval-10)
 Master: DrbdDataClone
  Meta Attrs: master-node-max=1 clone-max=2 notify=true master-max=1 clone-node-max=1
  Resource: DrbdMySQLData (class=ocf provider=linbit type=drbd)
   Attributes: drbd_resource=drbmysql
   Operations: demote interval=0s timeout=90 (DrbdMySQLData-demote-interval-0s)
               monitor interval=20 role=Slave timeout=20 (DrbdMySQLData-monitor-interval-20)
               monitor interval=10 role=Master timeout=20 (DrbdMySQLData-monitor-interval-10)
               notify interval=0s timeout=90 (DrbdMySQLData-notify-interval-0s)
               promote interval=0s timeout=90 (DrbdMySQLData-promote-interval-0s)
               reload interval=0s timeout=30 (DrbdMySQLData-reload-interval-0s)
               start interval=0s timeout=240 (DrbdMySQLData-start-interval-0s)
               stop interval=0s timeout=100 (DrbdMySQLData-stop-interval-0s)

Stonith Devices:
Fencing Levels:

Location Constraints:
  Resource: MySQLGroup
    Enabled on: pacemakercl1 (score:INFINITY) (role: Started) (id:cli-prefer-MySQLGroup)
Ordering Constraints:
Colocation Constraints:
Ticket Constraints:

Alerts:
 No alerts defined

Resources Defaults:
 No defaults set
Operations Defaults:
 timeout: 240s

Cluster Properties:
 cluster-infrastructure: corosync
 cluster-name: ha_cluster
 dc-version: 1.1.19-8.el7_6.4-c3c624ea3d
 have-watchdog: false
 stonith-enabled: false

Quorum:
  Options:
[[email protected] ~]#

Utilizar DRBD con Pacemaker

En el artículo Réplica activa-pasiva de filesystems con DRBD en Linux CentOS expliqué cómo crear una réplica activa-pasiva de filesystems, ideal para utilizarla en clusters activos-pasivos como los que creamos con Pacemaker y en entornos de bajo coste en lo que no está implementada la réplica por cabina.

Para incorporar DRBD a un cluster de Pacemaker, por ejemplo, para replicar una base de datos SQL entre los diferentes nodos del cluster, seguiremos los siguientes pasos (me salto la parte de configuración de DRBD porque ya la expliqué en el post indicado anteriormente).

  • Integramos el servicio de DRBD en el cluster:
[[email protected] ~]# pcs cluster cib drbd_cfg
[[email protected] ~]#
  • Creamos el recurso de DRBD, que llamaremos «DrbdMySQLData»:
[[email protected] ~]# pcs -f drbd_cfg resource create DrbdMySQLData ocf:linbit:drbd drbd_resource=drbmysql --group MySQLGroup
[[email protected] ~]#
  • Añadimos el servicio de réplica de datos dr DRBD:
[[email protected] ~]# pcs -f drbd_cfg resource master DrbdDataClone DrbdMySQLData master-max=1 master-node-max=1 clone-max=2 clone-node-max=1 notify=true --group MySQLGroup
[[email protected] ~]#
  • Actualizamos la configuración del cluster:
[[email protected] ~]# pcs cluster cib-push drbd_cfg
CIB updated
[[email protected] ~]#
  • Creamos el recurso del filesystem DRBD, el orden en que se tiene que arrancar cada recurso y volvemos a actualizar el cluster de Pacemaker:
[[email protected] ~]# pcs cluster cib fs_cfg
[[email protected] ~]#

[[email protected] ~]# pcs -f fs_cfg resource create drbdmysqlFS Filesystem device="/dev/drbd0" directory="/MySQL" fstype="xfs" --group MySQLGroup
Assumed agent name 'ocf:heartbeat:Filesystem' (deduced from 'Filesystem')
[[email protected] ~]#

[[email protected] ~]# pcs -f fs_cfg constraint colocation add drbdmysqlFS with DrbdDataClone INFINITY with-rsc-role=Master --group MySQLGroup
[[email protected] ~]# pcs  -f fs_cfg constraint order promote DrbdDataClone then start drbdmysqlFS --group MySQLGroup
[[email protected] ~]#

[[email protected] ~]# pcs cluster cib-push fs_cfg
CIB updated
[[email protected] ~]#

Adjunto también la configuración del FS DRBD para que podamos entender mejor cómo lo hemos añadido al cluster de Pacemaker:

[[email protected] ~]# cat /etc/drbd.d/drbmysql.res
resource drbmysql {
        on pacemaker1 {
                device /dev/drbd0;
                disk /dev/vgmysql/lvmysql;
                        meta-disk internal;
                        address 10.0.1.16:7789;
        }
        on pacemaker2 {
                device /dev/drbd0;
                        disk /dev/vgmysql/lvmysql;
                        meta-disk internal;
                        address 10.0.1.237:7789;
        }
}
[[email protected] ~]#
  • Aumentamos los delays de los recursos de DRBD porque fallaban al arrancar:
pcs resource update DrbdMySQLData op start interval=10 timeout=60
pcs resource update DrbdMySQLData op notify interval=10 timeout=60
pcs resource update DrbdMySQLData op stop interval=10 timeout=60
pcs resource update DrbdMySQLData op demote interval=10 timeout=60
pcs resource update DrbdMySQLData op promote interval=10 timeout=60

pcs resource update drbdmysqlFS op start interval=10 timeout=60
pcs resource update drbdmysqlFS op notify interval=10 timeout=60
pcs resource update drbdmysqlFS op stop interval=10 timeout=60
pcs resource update drbdmysqlFS op demote interval=10 timeout=60
pcs resource update drbdmysqlFS op promote interval=10 timeout=60
  • Comprobamos el estado del cluster:
[[email protected] ~]# pcs status resources
 Resource Group: MySQLGroup
     VirtualIP  (ocf::heartbeat:IPaddr2):       Started pacemakercl2
     drbdmysqlFS        (ocf::heartbeat:Filesystem):    Started pacemakercl2
 Master/Slave Set: DrbdDataClone [DrbdMySQLData]
     Masters: [ pacemakercl2 ]
     Slaves: [ pacemakercl1 ]
[[email protected] ~]#
  • Verificamos que el filesystem y la IP están arrancados en el nodo indicado:
[[email protected] drbd.d]# df -hP /MySQL/
Filesystem      Size  Used Avail Use% Mounted on
/dev/drbd0     1017M   33M  985M   4% /MySQL
[[email protected] drbd.d]# 

[[email protected] drbd.d]# ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9001 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 06:f6:c7:1a:06:40 brd ff:ff:ff:ff:ff:ff
    inet 10.0.1.237/24 brd 10.0.1.255 scope global dynamic eth0
       valid_lft 2701sec preferred_lft 2701sec
    inet 10.0.1.50/24 brd 10.0.1.255 scope global secondary eth0
       valid_lft forever preferred_lft forever
    inet6 fe80::4f6:c7ff:fe1a:640/64 scope link
       valid_lft forever preferred_lft forever
[[email protected] drbd.d]#

Ejecutar un script personalizado como recurso de Pacemaker

Con Pacemaker podemos ejecutar, parar y monitorizar scripts personalizados si nos interesa. Para ello, tendremos que definir las funciones y metadatos dentro del script:

Acciones

  • start: Función de arranque del script
  • stop: Función de parada
  • monitor: Monitorización del estado de salud del script. Hay que devolver un Exit 0 si el script está corriendo.
  • meta-data: Provee información en formato XLM, sobre las funciones definidas dentro del script.
  • validate-all: Valida que los parámetros de ejecución del script son correctos. Exit 0 si está todo bien, 2 si no es válido, 6 si el recurso no está configurado.
  • promote: La instancia local hace de nodo primario del cluster.
  • demote: La instancia local hace de nodo secundario.
  • reload: Recarga la configuración del script sin afectación al servicio.

También es posible definir parámetros de ejecución del script. Por ejemplo, cuando hemos creado anteriormente un recurso para dar de alta una IP virtual de servicio, hemos tenido que pasar como parámetro la IP que queríamos.

Ubicación de los scripts de Pacemaker

Por defecto, Pacemaker trae consigo una serie de scripts predefinidos para arrancar procesos o aplicaciones populares, como podría ser dar de alta una IP o arrancar un servidor WEB Apache, por ejemplo.

Todos esos script se encuentran en el directorio /usr/lib/ocf/resource.d/heartbeat y nos pueden ser muy útiles para tomarlos como ejemplo para crear nuestro propio script personalizado.

Creación de un script personalizado

En la ruta indicada anteriormente de ambos nodos del cluster, he creado un script muy sencillo que, lo único que hace es escribir un fichero en /tmp para saber que el script se ha ejecutado. Ni siquiera he programado la monitorización del mismo, pues con este ejemplo y con todos los scripts predefinidos ya nos podemos hacer una idea de cómo añadir un script personalizado dentro de nuestro cluster de Pacemaker.

Veamos el código fuente del script de test:

[[email protected] ~]# cat /usr/lib/ocf/resource.d/heartbeat/ScriptDavidTest
#!/bin/sh
#
# Resource script for MailTo
#
# Author: David Martinez
#
# Description: Testeando script personalizado con Pacemaker
#

: ${OCF_FUNCTIONS_DIR=${OCF_ROOT}/lib/heartbeat}
. ${OCF_FUNCTIONS_DIR}/ocf-shellfuncs


meta_data() {
        cat <<END
<?xml version="1.0"?>
<!DOCTYPE resource-agent SYSTEM "ra-api-1.dtd">
<resource-agent name="ScriptDavidTest">
<version>1.0</version>

<longdesc lang="en">
Este es un script de pruebas.
</longdesc>
<shortdesc lang="en">Script de pruebas</shortdesc>

<actions>
<action name="start" timeout="10s" />
<action name="stop" timeout="10s" />
<action name="meta-data" timeout="5s" />
</actions>
</resource-agent>
END
}

EchoToStart() {

   echo $(date +%Y%m%d_%H%M) - Script start $(hostname) >> /tmp/pacemakertest.log

}

EchoToStop () {

   echo $(date +%Y%m%d_%H%M) - Script stop $(hostname) >> /tmp/pacemakertest.log

}

usage () {

   echo "Instrucciones para el modo de uso del script"

}

case $1 in
  start)                EchoToStart
                        ;;
  stop)                 EchoToStop
                        ;;
  meta-data)            meta_data;;
  *)                    usage
                        exit $OCF_ERR_UNIMPLEMENTED
                        ;;
esac
exit $?

[[email protected] ~]#

Y ahora, vamos a instalarlo como un recurso del cluster:

[[email protected] heartbeat]# pcs resource create ScriptDavidTest ocf:heartbeat:ScriptDavidTest --group GrupoRecursosTest
[[email protected] heartbeat]#

[[email protected] ~]# pcs resource show
 Resource Group: GrupoRecursosTest
     VirtualIP  (ocf::heartbeat:IPaddr2):       Started pacemaker1
     ScriptDavidTest    (ocf::heartbeat:ScriptDavidTest):       Stopped
[[email protected] ~]#

Aparece como «stopped» porque no he creado la función para monitorizarlo. Pero vamos a ejecutarlo:

[[email protected] ~]# pcs resource debug-start ScriptDavidTest
Operation start for ScriptDavidTest (ocf:heartbeat:ScriptDavidTest) returned: 'ok' (0)
[[email protected] ~]#

[[email protected] ~]# cat /tmp/pacemakertest.log
20190616_1757 - Script start pacemaker1
[[email protected] ~]#

Como vemos, se ha creado el fichero que queríamos. Podemos utilizar este procedimiento para ejecutar cualquier script que queramos como, por ejemplo, arrancar una base de datos Oracle, etc.

Añadir un nuevo nodo al cluster

Si queremos pasar de dos nodos a tres en el cluster, podemos hacerlo de una manera muy sencilla.

Para no repetirme, en el tercer nodo seguiremos todos los pasos de instalación de Pacemaker descritos anteriormente en este artículo y, por supuesto, arrancaremos todos los servicios del cluster (instalación del producto, habilitar el servicio, arrancarlo y dar de alta el usuario hacluster y la contraseña).

Así que, una vez que tenemos el tercer nodo con todos los requerimientos necesarios ya configurados, lo añadiremos al cluster.

[[email protected] ~]# pcs cluster node add pacemaker3
Disabling SBD service...
pacemaker3: sbd disabled
Sending remote node configuration files to 'pacemaker3'
pacemaker3: successful distribution of the file 'pacemaker_remote authkey'
pacemaker1: Corosync updated
pacemaker2: Corosync updated
Setting up corosync...
pacemaker3: Succeeded
Synchronizing pcsd certificates on nodes pacemaker3...
pacemaker3: Success
Restarting pcsd on the nodes in order to reload the certificates...
pacemaker3: Success
[[email protected] ~]# 

[[email protected] ~]# pcs cluster enable
[[email protected] ~]#

[[email protected] ~]# pcs cluster start --all
pacemaker1: Starting Cluster (corosync)...
pacemaker2: Starting Cluster (corosync)...
pacemaker3: Starting Cluster (corosync)...
pacemaker2: Starting Cluster (pacemaker)...
pacemaker3: Starting Cluster (pacemaker)...
pacemaker1: Starting Cluster (pacemaker)...
[[email protected] ~]#

[[email protected] ~]# pcs status
Cluster name: ClusterTest
Stack: corosync
Current DC: pacemaker2 (version 1.1.19-8.el7_6.4-c3c624ea3d) - partition with quorum
Last updated: Sun Jun 16 18:53:00 2019
Last change: Sun Jun 16 18:52:55 2019 by hacluster via crmd on pacemaker2

3 nodes configured
2 resources configured

Online: [ pacemaker1 pacemaker2 pacemaker3 ]

Full list of resources:

 Resource Group: GrupoRecursosTest
     VirtualIP  (ocf::heartbeat:IPaddr2):       Started pacemaker1
     ScriptDavidTest    (ocf::heartbeat:ScriptDavidTest):       Stopped

Failed Actions:
* ScriptDavidTest_monitor_0 on pacemaker1 'unimplemented feature' (3): call=11, status=complete, exitreason='',
    last-rc-change='Sun Jun 16 18:49:18 2019', queued=0ms, exec=12ms
* ScriptDavidTest_monitor_0 on pacemaker2 'unimplemented feature' (3): call=9, status=complete, exitreason='',
    last-rc-change='Sun Jun 16 18:49:18 2019', queued=0ms, exec=15ms


Daemon Status:
  corosync: active/enabled
  pacemaker: active/enabled
  pcsd: active/enabled
[[email protected] ~]#

Como podemos observar, el nodo pacemaker3 se ha añadido al cluster satisfactoriamente.

¿Quién hace de servidor de Quorum?

[[email protected] ~]# pcs status |grep -i quorum
Current DC: pacemaker2 (version 1.1.19-8.el7_6.4-c3c624ea3d) - partition with quorum
[[email protected] ~]#

Ahora hago un shutdown del servidor pacemaker2 y comprobamos que ahora es otro servidor el que hace de Quorum:

[[email protected] ~]# pcs status |grep -i quorum
Current DC: pacemaker1 (version 1.1.19-8.el7_6.4-c3c624ea3d) - partition with quorum
[[email protected] ~]#

Eliminar un nodo del cluster

Ahora vamos a eliminar del cluster el nodo que acabamos de incorporar, a modo de prueba.

[[email protected] ~]# pcs cluster node remove pacemaker3
Error: Removing the node will cause a loss of the quorum, use --force to override
[[email protected] ~]#

[[email protected] ~]# pcs cluster node remove pacemaker3 --force
pacemaker3: Stopping Cluster (pacemaker)...
pacemaker3: Successfully destroyed cluster
pacemaker1: Corosync updated
pacemaker2: Corosync updated
[[email protected] ~]# pcs status
Cluster name: ClusterTest
Stack: corosync
Current DC: pacemaker1 (version 1.1.19-8.el7_6.4-c3c624ea3d) - partition with quorum
Last updated: Mon Jun 17 06:19:55 2019
Last change: Mon Jun 17 06:19:51 2019 by root via crm_node on pacemaker1

2 nodes configured
2 resources configured

Online: [ pacemaker1 ]
OFFLINE: [ pacemaker2 ]

Full list of resources:

 Resource Group: GrupoRecursosTest
     VirtualIP  (ocf::heartbeat:IPaddr2):       Started pacemaker1
     ScriptDavidTest    (ocf::heartbeat:ScriptDavidTest):       Stopped

Failed Actions:
* ScriptDavidTest_monitor_0 on pacemaker1 'unimplemented feature' (3): call=11, status=complete, exitreason='',
    last-rc-change='Mon Jun 17 06:18:26 2019', queued=0ms, exec=12ms


Daemon Status:
  corosync: active/enabled
  pacemaker: active/enabled
  pcsd: active/enabled
[[email protected] ~]#

[[email protected] ~]# pcs status |grep -i quorum
Current DC: pacemaker1 (version 1.1.19-8.el7_6.4-c3c624ea3d) - partition with quorum
[[email protected] ~]#

Configurar un servidor de Quorum o Stonith de Pacemaker

Ahora vamos construir un cluster de dos nodos de servicio más otro nodo de servidor de Quorum con las siguientes IPs:

10.0.1.58 pacemaker1
10.0.1.138 pacemaker2
10.0.1.130 pacemaker-stonith

El servidor de Quorum o Stonith, que así se llama en Pacemaker, se encarga de revisar el estado de salud del cluster. Si uno de los nodos pierde comunicación con el resto de nodos del cluster, éste necesita saber si es un problema suyo o del resto de nodos. Es ahí donde interviene el servidor de Quorum para poner orden en el estado del cluster.

En todos los nodos del cluster instalaremos el siguiente paquete:

[[email protected]:~]# yum install corosync-qdevice
[[email protected]:~]# yum install corosync-qdevice

En el servidor de quorum instalaremos el paquete:

[[email protected] ~]# yum install pcs corosync-qnetd

Y habilitaremos el servicio:

[[email protected] ~]# systemctl start pcsd.service
[[email protected] ~]# systemctl enable pcsd.service

[[email protected] ~]# pcs qdevice setup model net --enable --start
Quorum device 'net' initialized
quorum device enabled
Starting quorum device...
quorum device started
[[email protected] ~]#

[[email protected] ~]# pcs qdevice start net
Starting quorum device...
quorum device started
[[email protected] ~]# pcs qdevice enable net
quorum device enabled
[[email protected] ~]#

[[email protected] ~]# pcs qdevice status net --full
QNetd address:                  *:5403
TLS:                            Supported (client certificate required)
Connected clients:              0
Connected clusters:             0
Maximum send/receive size:      32768/32768 bytes

[[email protected] ~]#

Desde cualquiera de los nodos del cluster autorizamos al servidor de Stonith:

[[email protected] ~]# pcs cluster auth pacemaker-stonith
Username: hacluster
Password:
pacemaker-stonith: Authorized
[[email protected] ~]#

[[email protected] ~]# pcs quorum config
Options:
[[email protected] ~]# pcs quorum status
Quorum information
------------------
Date:             Mon Jun 17 14:36:53 2019
Quorum provider:  corosync_votequorum
Nodes:            2
Node ID:          1
Ring ID:          1/68
Quorate:          Yes

Votequorum information
----------------------
Expected votes:   2
Highest expected: 2
Total votes:      2
Quorum:           1
Flags:            2Node Quorate WaitForAll

Membership information
----------------------
    Nodeid      Votes    Qdevice Name
         1          1         NR pacemaker1 (local)
         2          1         NR pacemaker2

[[email protected] ~]#

Por último, activamos el servicio del servidor de Stonith:

[[email protected] ~]# pcs quorum device add model net host=pacemaker-stonith  algorithm=ffsplit
Setting up qdevice certificates on nodes...
pacemaker1: Succeeded
pacemaker2: Succeeded
Enabling corosync-qdevice...
pacemaker2: not enabling corosync-qdevice: corosync is not enabled
pacemaker1: corosync-qdevice enabled
Sending updated corosync.conf to nodes...
pacemaker1: Succeeded
pacemaker2: Succeeded
Corosync configuration reloaded
Starting corosync-qdevice...
pacemaker1: corosync-qdevice started
pacemaker2: corosync-qdevice started
[[email protected] ~]#


[[email protected] ~]# pcs quorum config
Options:
Device:
  votes: 1
  Model: net
    algorithm: ffsplit
    host: pacemaker-stonith
[[email protected] ~]#


[[email protected] ~]# pcs quorum status
Quorum information
------------------
Date:             Mon Jun 17 14:39:22 2019
Quorum provider:  corosync_votequorum
Nodes:            2
Node ID:          1
Ring ID:          1/68
Quorate:          Yes

Votequorum information
----------------------
Expected votes:   3
Highest expected: 3
Total votes:      3
Quorum:           2
Flags:            Quorate WaitForAll Qdevice

Membership information
----------------------
    Nodeid      Votes    Qdevice Name
         1          1    A,V,NMW pacemaker1 (local)
         2          1    A,V,NMW pacemaker2
         0          1            Qdevice

[[email protected] ~]#


[[email protected] ~]# pcs quorum device status
Qdevice information
-------------------
Model:                  Net
Node ID:                1
Configured node list:
    0   Node ID = 1
    1   Node ID = 2
Membership node list:   1, 2

Qdevice-net information
----------------------
Cluster name:           ClusterTest
QNetd host:             pacemaker-stonith:5403
Algorithm:              Fifty-Fifty split
Tie-breaker:            Node with lowest node ID
State:                  Connected

[[email protected] ~]#

Añadir políticas o propiedades a Stonith

Si queremos que el nodo que está teniendo problemas se rebote automáticamente si no se ha recuperado tras 60 segundos, configuraremos las propiedades de Stonith de la siguiente manera:

[[email protected] ~]# pcs -f stonith_cfg property set stonith-timeout=60s
[[email protected] ~]# pcs -f stonith_cfg property set stonith-action=reboot
[[email protected] ~]# pcs -f stonith_cfg property
Cluster Properties:
 stonith-action: reboot
 stonith-enabled: true
 stonith-timeout: 60s
[[email protected] ~]#

Crear recursos del estado de salud del nodo con Stonith

Para comprobar que el nodo pacemaker1 está en un buen estado de salud, vamos a crear una política para que se autentifique por SSH hacia el nodo pacemaker2, de manera periódica, con un recurso de Stonith:

[[email protected] ~]# pcs stonith create pacemaker1-fencing fence_apc pcmk_host_list="pacemaker1" ipaddr=10.0.1.138 login=hacluster passwd=Martinez8 secure=true ssh_path="/usr/bin/ssh" ssh_options="-F /dev/null" shell_timeout=30
[[email protected] ~]#

Sin embargo, el recurso de stonith aparece como parado:

[[email protected] ~]# pcs status
Cluster name: ClusterTest
Stack: corosync
Current DC: pacemaker1 (version 1.1.19-8.el7_6.4-c3c624ea3d) - partition with quorum
Last updated: Thu Jun 20 04:48:29 2019
Last change: Thu Jun 20 04:47:13 2019 by root via cibadmin on pacemaker1

2 nodes configured
2 resources configured

Online: [ pacemaker1 pacemaker2 ]

Full list of resources:

 Resource Group: MySQLGroup
     VirtualIP  (ocf::heartbeat:IPaddr2):       Started pacemaker1
 pacemaker1-fencing     (stonith:fence_apc):    Stopped

Failed Actions:
* pacemaker1-fencing_start_0 on pacemaker2 'unknown error' (1): call=17, status=Error, exitreason='',
    last-rc-change='Thu Jun 20 04:47:13 2019', queued=0ms, exec=12268ms
* pacemaker1-fencing_start_0 on pacemaker1 'unknown error' (1): call=19, status=Error, exitreason='',
    last-rc-change='Thu Jun 20 04:47:25 2019', queued=0ms, exec=12639ms


Daemon Status:
  corosync: active/enabled
  pacemaker: active/enabled
  pcsd: active/enabled
[[email protected] ~]#

No obstante, el cluster funciona correctamente mientras no se pierda la comunicación entre los nodos ni con el servidor de Quorum al mismo tiempo.

Problemas encontrados con Stonith

El recurso que hemos creado con Stonith también lo podemos comprobar ejecutando el script en pyhon manualmente. Si lo hacemos, el resultado es el siguiente:


[[email protected] ~]# fence_apc --ip=10.0.1.138 --username=hacluster --password=Martinez8 --ssh --ssh-options="-F /dev/null" --shell-timeout=30 --plug=pacemaker21 --verbose
2019-06-20 04:52:50,303 INFO: Running command: /usr/bin/ssh  [email protected] -p 22 -o PubkeyAuthentication=no -F /dev/null
2019-06-20 04:52:50,377 DEBUG: Received: [email protected]'s password:
2019-06-20 04:52:50,377 DEBUG: Sent: Martinez8
2019-06-20 04:52:50,427 DEBUG: Sent:

2019-06-20 04:52:55,483 DEBUG: Timeout exceeded in read_nonblocking().
<fencing.fspawn object at 0x7f6258636b50>
version: 2.3 ($Revision: 399 $)
command: /usr/bin/ssh
args: ['/usr/bin/ssh', '[email protected]', '-p', '22', '-o', 'PubkeyAuthentication=no', '-F', '/dev/null']
searcher: searcher_re:
    0: re.compile("
>")
    1: re.compile("
apc>")
buffer (last 100 chars): Jun 20 04:52:41 2019 from pacemaker1
[[email protected] ~]$
before (last 100 chars): Jun 20 04:52:41 2019 from pacemaker1
[[email protected] ~]$
after: <class 'pexpect.TIMEOUT'>
match: None
match_index: None
exitstatus: None
flag_eof: False
pid: 6033
child_fd: 4
closed: False
timeout: 30
delimiter: <class 'pexpect.EOF'>
logfile: None
logfile_read: None
logfile_send: None
maxread: 2000
ignorecase: False
searchwindowsize: None
delaybeforesend: 0.05
delayafterclose: 0.1
delayafterterminate: 0.1
2019-06-20 04:52:55,483 ERROR: Unable to connect/login to fencing device


[[email protected] ~]#

Aunque el script de error, el comando que ejecuta el propio script sí funciona, por lo que no entiendo el motivo del error. Fijaos en la línea que lanza:

2019-06-20 04:52:50,303 INFO: Running command: /usr/bin/ssh  h[email protected] -p 22 -o PubkeyAuthentication=no -F /dev/null

Si la ejecuto manualmente funciona:

[[email protected] ~]#  /usr/bin/ssh  [email protected] -p 22 -o PubkeyAuthentication=no -F /dev/null
[email protected]'s password:
Last login: Thu Jun 20 04:52:50 2019 from pacemaker1
[[email protected] ~]$

Me he estado volviendo loco con este error y, por lo que he leído por Internet, se trata de un bug del script fence_apc. Pareces ser que envía la contraseña demasiado rápido, es decir, antes de que la pida SSH.

Solución – Crear el recurso de Stonith con el agente de SNMP en vez de con el de SSH

Lo que he hecho ha sido instalar SNMP en el mismo servidor donde tengo instalado el servidor de Quorum aunque, lo idea, es tener otro servidor diferente. En este caso, ya nos sirve para hacer la prueba. Si nos sabes instalar SNMP, lo explico en el Crear un usuario y contraseña de SNMP.

A continuación, creo el recurso de Stonith de SNMP para que todos los nodos del cluster se validen contra este servicio:

[[email protected] ~]# pcs stonith create pcmkrrh2-snmp-fencing fence_apc_snmp ipaddr="pacemaker-stonith" pcmk_host_map="pacemaker1:1;pacemaker2:2" pcmk_host_check="static-list" pcmk_host_list="pacemaker1;pacemaker2" login="david" passwd="Martinez8" community=public
[[email protected] ~]#

[[email protected] ~]# pcs status
Cluster name: ha_cluster
Stack: corosync
Current DC: pacemaker1 (version 1.1.19-8.el7_6.4-c3c624ea3d) - partition with quorum
Last updated: Sat Jun 22 05:53:24 2019
Last change: Sat Jun 22 05:44:34 2019 by root via cibadmin on pacemaker1

2 nodes configured
2 resources configured

Online: [ pacemaker1 pacemaker2 ]

Full list of resources:

 Resource Group: MySQLGroup
     VirtualIP  (ocf::heartbeat:IPaddr2):       Started pacemaker1
 pcmkrrh2-snmp-fencing  (stonith:fence_apc_snmp):       Started pacemaker2

Daemon Status:
  corosync: active/disabled
  pacemaker: active/disabled
  pcsd: active/enabled
[[email protected] ~]#

La palabra Stonith significa pegarle un tiro al otro nodo. Es decir, si alguno de los nodos se queda colgado, los otros que quedan vivos lo desconectan del cluster mediante la política que hemos definido en el recurso de stonith. Por ejemplo, desconectarle del switch de la cabina de discos.

Los recursos de Stonith se definen a nivel de cluster.

¿Qué pasa si cae el servidor de Quorum?

Mientras los dos nodos de servicio del cluster tengan conectividad entre ellos, no tiene por qué pasar nada. Vamos a comprobarlo:

  • Apagamos el servidor Stonith
[[email protected] ~]# reboot
  • Comprobamos que los nodos ya no tienen visibilidad del Quorum
[[email protected] ~]# pcs status
Cluster name: ClusterTest
Stack: corosync
Current DC: pacemaker1 (version 1.1.19-8.el7_6.4-c3c624ea3d) - partition with quorum
Last updated: Tue Jun 18 06:56:41 2019
Last change: Mon Jun 17 20:52:20 2019 by root via cibadmin on pacemaker1

2 nodes configured
3 resources configured

Online: [ pacemaker1 pacemaker2 ]

Full list of resources:

 pacemaker1-fencing     (stonith:fence_virt):   Stopped
 pacemaker2-fencing     (stonith:fence_virt):   Stopped
 Resource Group: MySQLGroup
     VirtualIP  (ocf::heartbeat:IPaddr2):       Started pacemaker1

Failed Actions:
* pacemaker2-fencing_start_0 on pacemaker1 'unknown error' (1): call=16, status=Error, exitreason='',
    last-rc-change='Tue Jun 18 06:43:19 2019', queued=0ms, exec=1060ms
* pacemaker1-fencing_start_0 on pacemaker1 'unknown error' (1): call=14, status=Error, exitreason='',
    last-rc-change='Tue Jun 18 06:43:18 2019', queued=0ms, exec=1066ms
* pacemaker1-fencing_start_0 on pacemaker2 'unknown error' (1): call=12, status=Error, exitreason='',
    last-rc-change='Tue Jun 18 06:43:19 2019', queued=0ms, exec=1060ms
* pacemaker2-fencing_start_0 on pacemaker2 'unknown error' (1): call=10, status=Error, exitreason='',
    last-rc-change='Tue Jun 18 06:43:18 2019', queued=0ms, exec=1060ms


Daemon Status:
  corosync: active/enabled
  pacemaker: active/enabled
  pcsd: active/enabled
[[email protected] ~]#



[[email protected] ~]#  pcs quorum device status
Qdevice information
-------------------
Model:                  Net
Node ID:                2
Configured node list:
    0   Node ID = 1
    1   Node ID = 2
Membership node list:   1, 2

Qdevice-net information
----------------------
Cluster name:           ClusterTest
QNetd host:             pacemaker-stonith:5403
Algorithm:              Fifty-Fifty split
Tie-breaker:            Node with lowest node ID
State:                  Connected

[[email protected] ~]#  pcs quorum device status
Qdevice information
-------------------
Model:                  Net
Node ID:                2
Configured node list:
    0   Node ID = 1
    1   Node ID = 2
Membership node list:   1, 2

Qdevice-net information
----------------------
Cluster name:           ClusterTest
QNetd host:             pacemaker-stonith:5403
Algorithm:              Fifty-Fifty split
Tie-breaker:            Node with lowest node ID
State:                  Connect failed

[[email protected] ~]#

Como hemos podido comprobar, la IP de servicio, que es el recurso del cluster que tenemos configurado, ha seguido disponible en todo momento.

Al recuperarse el servidor de Quorum, ambos nodos han reconectado con él automáticamente.

[[email protected] ~]#  pcs quorum device status |grep State
State:                  Connected
[[email protected] ~]#

[[email protected] ~]# pcs quorum device status |grep State
State:                  Connected
[[email protected] ~]#

Acceso a la interfaz WEB de Pacemaker

Podemos configurar el cluster desde la interfaz WEB. Para ello tenemos que levantar el servicio pcs que ya habíamos instalado previamente, tal y como puedes comprobar en este post.

[[email protected] ~]# systemctl status pcsd
● pcsd.service - PCS GUI and remote configuration interface
   Loaded: loaded (/usr/lib/systemd/system/pcsd.service; enabled; vendor preset: disabled)
   Active: active (running) since Tue 2019-06-18 17:29:08 UTC; 6min ago
     Docs: man:pcsd(8)
           man:pcs(8)
 Main PID: 3453 (pcsd)
   CGroup: /system.slice/pcsd.service
           └─3453 /usr/bin/ruby /usr/lib/pcsd/pcsd

Jun 18 17:29:03 pacemaker1 systemd[1]: Starting PCS GUI and remote configuration interface...
Jun 18 17:29:08 pacemaker1 systemd[1]: Started PCS GUI and remote configuration interface.
[[email protected] ~]#

Cuando este servicio está arrancado, veremos que el proceso está escuchando por el puerto 2224:

[[email protected] ~]# netstat -anp |grep 2224 |grep LISTEN
tcp6       0      0 :::2224                 :::*                    LISTEN      3453/ruby
[[email protected] ~]# 

[[email protected] ~]# ps -ef |grep 3453
root      3453     1  0 17:29 ?        00:00:00 /usr/bin/ruby /usr/lib/pcsd/pcsd
root      5914  4174  0 17:36 pts/0    00:00:00 grep --color=auto 3453
[[email protected] ~]#

Lo que tenemos que hacer es acceder a la IP y puerto mediante https y entrar con el usuario de administración del cluster. En nuestro caso, habíamos configurado el usuario hacluster.

Administracion WEB de Pacemaker
Pacemaker WEB GUI - Administrar cluster

Te puede interesar

¿Te ha gustado? ¡Compártelo!

Share on facebook
Share on twitter
Share on linkedin
Share on whatsapp
Share on telegram
Share on email

SUSCRÍBETE A PUERTO53

Recibe un email periódico con los artículos más interesantes de Puerto53.com

Antes de suscribirte lee los términos y condiciones. Gracias.

Contenido Relacionado

Artículos Recientes

Deja un comentario

About Author