KeepaliveD
Cette page est issue d'une série d'articles du site "Enable SysAdmin" de Red Hat, résumés et traduits. https://www.redhat.com/sysadmin/ha-cluster-linux https://www.redhat.com/sysadmin/keepalived-basics https://www.redhat.com/sysadmin/advanced-keepalived
Bases
VIP et élections
KeepaliveD est un daemon Linux mettant en place le protocole VRRP (Virtual Router Redundancy Protocol), version 2 (RFC 3768) et 3 (RFC 5798) (nous utiliseront ici la version 2). Le mot d'ordre est ici "Failover" ! VRRP, bien que conçu pour les routeurs, est ici utilisé sur nos serveurs pour mettre en place des VIPs: plusieurs serveurs participent à une élection (chaque serveur est configuré avec un poids) pour savoir qui sera chargé d'utiliser la VIP (et sera donc le master): quand le master tombe, VRRP met en place des mécanismes de détection et on choisit un nouveau master. Le master doit normalement avoir un poids de 255, mais ce n'est pas une obligation. Le master envoie des advertisements à intervalles réguliers, c'est ce qui permet aux autres de savoir quand celui-ci n'est pas disponible; un autre mécanisme appellé "preemption" permet à n'importe quel serveur se pointant avec une priorité plus élevée de devenir master.
Quand un master se met en place, il envoie un ARP annonçant son IP et sa MAC afin que le reste du réseau puisse l'adresser correctement au niveau de la couche 2.
VRRP permet aussi de faire du load balancing !
Un paquet, vu de près
On peut comprendre un certain nombre de choses en regardant un paquet d'advertisement VRRP avec Wireshark.
On voit que les adresses de destination (IP et MAC) sont des adresses multicast. Pour éviter les configurations complexes, le trafic multicast de VRRP deviendra simplement du trafic broadcast sur le segment local. On voit aussi que ce n'est pas de l'UDP ni du TCP; VRRP utilise le protocole IP numéro 112. Connaître ce numéro est important pour configurer les firewalls. Le paquet contient toutes les informations permettant d'élire un master et d'informer les slaves:
- Un Virtual Router ID (VRID), identifiant unique d'une instance VRRP et de ses adresses IP. Il faut éviter de les réutiliser sur un même LAN.
- La priorité est le poids de l'hôte qui envoie le paquet.
- Auth type et Auth String contiennent un password simple pour identifier les autres membres sur le réseau.
- Advertisement Interval indiquent à quelle intervalle les adv sont envoyés par le master (en secondes)
- IP Address : la / les adresses pour lesquelles le master est responsable.
Configuration Simple
Nous allons ici utiliser KeepaliveD pour avoir du failover entre deux serveurs.
Installation
KeepaliveD est dispo dans les dépôts et peut facilement être installé via yum / apt: <source lang="bash"> [root@server1 ~]# yum install -y keepalived
[root@server1 ~]# keepalived --version Keepalived v2.0.10 (11/12,2018)
[root@server1 ~]# systemctl status keepalived keepalived.service - LVS and VRRP High Availability Monitor Loaded: loaded (/usr/lib/systemd/system/keepalived.service; disabled; vendor preset: disab Active: inactive (dead) </source>
On peut vouloir le compiler à la main.
<source lang="bash">
- Install prerequisites
yum install -y gcc openssl-devel
- Download the latest version of the code. Be sure to check the downloads page for the most recent version:https://www.keepalived.org/download.html
[root@localhost ~]# wget https://www.keepalived.org/software/keepalived-2.0.20.tar.gz
- Extract the code
[root@localhost ~]# tar -xf keepalived-2.0.20.tar.gz
- Run the configure scripts
[root@localhost ~]# cd keepalived-2.0.20 [root@localhost keepalived-2.0.20]# ./configure
- Build and install keepalived
[root@localhost keepalived-2.0.20]# make [root@localhost keepalived-2.0.20]# make install
- Test your installation
[root@localhost keepalived-2.0.20]# keepalived --version Keepalived v2.0.20 (01/22,2020) </source>
Configuration basique
Le fichier de configuration de keepalived est situé dans /etc/keepalived/keepalived.conf. Puisque que keepalived permet de faire plus que du failover, le fichier de conf peut faire peur en regardant le man; cependant, une topologie telle que celle présentée au-dessus peut être achevée avec un fichier assez simple. La plus simple des confs donne une VIP. Ici Server1 est master.
Configuration de server1: <source lang="bash"> server1# cat /etc/keepalived/keepalived.conf vrrp_instance VI_1 {
state MASTER interface eth0 virtual_router_id 51 priority 255 advert_int 1 authentication { auth_type PASS auth_pass 12345 } virtual_ipaddress { 192.168.122.200/24 }
} </source>
Configuration de server2: <source lang="bash"> server2# cat /etc/keepalived/keepalived.conf vrrp_instance VI_1 {
state BACKUP interface eth0 virtual_router_id 51 priority 254 advert_int 1 authentication { auth_type PASS auth_pass 12345 } virtual_ipaddress { 192.168.122.200/24 }
} </source>
Pour résumer la conf:
- vrrp_instance VI_1 : Nom arbitraire d'une instance de VRRP tournant sur une interface.
- state MASTER : État initial dans lequel je veux que l'instance tourne.
- interface eth0 : Sur quelle interface on fait du VRRP
- virtual_router_id 51 : Le VRID dont on parlait plus tôt.
- priority 255 : Le poids.
- advert_int 1 : Adv envoyés toutes les secondes.
- auth_type PASS : type d'auth
- auth_pass 12345 : password
- virtual_ipaddress : IP virtuelle
Avec tout ça en place, on peut lancer le protocole sur les deux systèmes:
systemctl start keepalived
On peut ensuite observer les ips sur les machines. Server1: <source lang="bash"> server1# ip -brief address show lo UNKNOWN 127.0.0.1/8 ::1/128 eth0 UP 192.168.122.101/24 192.168.122.200/24 fe80::5054:ff:fe82:d66e/64 </source>
<source lang="bash"> server2# ip -br a lo UNKNOWN 127.0.0.1/8 ::1/128 eth0 UP 192.168.122.102/24 fe80::5054:ff:fe04:2c5d/64 </source>
Une fois que c'est en place, on peut essayer de stopper keepalived sur le master pour voir la bascule.
Monitoring
Un tcpdump peut réveler tout ce qu'il y a à savoir sur la conf: <source lang="bash"> server1# tcpdump proto 112 tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes
16:51:01.353224 IP 192.168.122.102 > 224.0.0.18: VRRPv2, Advertisement, vrid 51, prio 254, authtype simple, intvl 1s, length 20
16:51:02.353673 IP 192.168.122.102 > 224.0.0.18: VRRPv2, Advertisement, vrid 51, prio 254, authtype simple, intvl 1s, length 20
16:51:03.353753 IP 192.168.122.102 > 224.0.0.18: VRRPv2, Advertisement, vrid 51, prio 254, authtype simple, intvl 1s, length 20
^C
3 packets captured 3 packets received by filter 0 packets dropped by kernel </source>
Notions Avancées
Nous avons vu plus tôt le système d'élections basé sur des priorités; keepalived fournit plusieurs méthodes pour ajuster la priorité en fonction de l'état du système. Nous allons en voir plusieurs, ainsi que la capacité de keepalived à faire tourner des scripts lors d'un changement d'état. Nous ne verront ici que la configuration de server1, la configuration de server2 étant facilement déductible.
Keepalived s'en sort bien en termes de failover (quand le master est complètement down, n'as plus de réseau); mais on ne veut pas, par exemple, d'un master qui continue de répondre alors que son application est complètement corrompue. On pourrait utiliser les "health checks" de notre application.
Attention : certains bugs peuvent être présent si on utilise Keepalived depuis les dépôts. Il vaut mieux compiler.
Suivre des processus
Le plus courant est de suivre un processus en particulier : par exemple, si notre serveur Apache s'arrête, on provoque un failover. Keepalivedle permet par sa directive "track_process". Ici, on va suivre le processus httpd avec un poids de 10. Tant que httpd tourne, la priorité est de 254 (244 + 10); si httpd s'arrête, le poids tombe à 244 et cela provoque un failover (en supposant qu'on ait un server2 bien configuré). <source lang="bash"> server1# cat keepalived.conf vrrp_track_process track_apache {
process httpd weight 10
}
vrrp_instance VI_1 {
state MASTER interface eth0 virtual_router_id 51 priority 244 advert_int 1 authentication { auth_type PASS auth_pass 12345 } virtual_ipaddress { 192.168.122.200/24 } track_process { track_apache }
} </source>
Suivre des fichiers
Keepalived peut aussi prendre des décisions de priorité en fonction du contenu d'un fichier : on peut avoir une application qui écrit régulièrement dans un fichier pour rendre compte de son état de santé. Le manuel de Keepalived explique que le tracking de fichier est basé sur le poids configuré pour celui-ci: "value will be read as a number in text from the file. If the weight configured against the track_file is 0, a non-zero value in the file will be treated as a failure status, and a zero value will be treated as an OK status, otherwise the value will be multiplied by the weight configured in the track_file statement. If the result is less than -253 any VRRP instance or sync group monitoring the script will transition to the fault state (the weight can be 254 to allow for a negative value being read from the file)". Heu...
Pour simplifier, on va donner à notre track_file un poids de 1, ce qui multipliera toute valeur donnée dans le fichier par 1. <source lang="bash"> server1# cat keepalived.conf vrrp_track_file track_app_file {
file /var/run/my_app/vrrp_track_file
}
vrrp_instance VI_1 {
state MASTER interface eth0 virtual_router_id 51 priority 244 advert_int 1 authentication { auth_type PASS auth_pass 12345 } virtual_ipaddress { 192.168.122.200/24 } track_file { track_app_file weight 1 }
} </source>
On peut ensuite créer le fichier et checker avec TCPdump que ça fonctionne: <source> server1# mkdir /var/run/my_app server1# echo 5 > /var/run/my_app/vrrp_track_file server1# systemctl restart keepalived server1# tcpdump proto 112 tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes 16:19:32.191562 IP server1 > vrrp.mcast.net: VRRPv2, Advertisement, vrid 51, prio 249, authtype simple, intvl 1s, length 20 </source> On a bien 249, soit la valeur de base (244) plus (le fichier (5) * son poids (1)). On peut même modifier le fichier: <source> server1# echo 6 > /var/run/my_app/vrrp_track_file server1# tcpdump proto 112 tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes 16:20:43.214940 IP server1 > vrrp.mcast.net: VRRPv2, Advertisement, vrid 51, prio 250, authtype simple, intvl 1s, length 20 </source>
Suivre une interface
On peut baser notre failover sur l'état d'une (autre) interface de la machine. Par exemple, si j'ai un frontend en failover (avec une VIP), je peux me baser sur l'état de l'interface de backend et provoquer un failover si celle-ci ne marche plus ! Le principe est le même que pour les processus: <source> server1# cat keepalived.conf vrrp_instance VI_1 {
state MASTER interface eth0 virtual_router_id 51 priority 244 advert_int 1 authentication { auth_type PASS auth_pass 12345 } virtual_ipaddress { 192.168.122.200/24 } track_interface { ens9 weight 5 }
} </source>
Scripts de suivi
On peut vouloir faire ses propres scripts pour suivre l'état des interfaces. On peut donner un poids au script, mais ici, on va garder les choses simples. Un script qui retourne 0 indique un succès et n'importe quoi d'autre indique un échec. Exemple avec un script ultra simple qui se contente de faire un ping sur 8.8.8.8. <source lang="bash">
- !/bin/bash
/usr/bin/ping -c 1 -W 1 8.8.8.8 > /dev/null 2>&1
- le -W 1 donne un timeout d'une seconde; il faut qu'un script pour keepalived soit léger et rapide
- sans quoi le master peut se retrouver à bloquer sans rien dire pendant trop longtemps
</source>
La conf associée: <source>
interval 1 timeout 5 rise 3 fall 3
}
vrrp_instance VI_1 {
state MASTER interface eth0 virtual_router_id 51 priority 244 advert_int 1 authentication { auth_type PASS auth_pass 12345 } virtual_ipaddress { 192.168.122.200/24 } track_script { keepalived_check }
} </source> Le bloc "vrrp_script" a quelques directives bien à lui:
- interval (en secondes) : fréquence à laquelle on fait tourner le script
- timeout (en secondes) : Combien de temps on attend le retour du script
- rise : Combien de succès d'affilée on doit avoir pour être considéré 'healthy'. Permet d'éviter le flapping. Ici, le sciprt doit faire trois retours positifs d'affilée.
- fall : Pareil, mais avec les échecs. Ici, 5 échecs d'affilée et on failover.
Scripts de notification
On a parlé de scripts pour contrôler keepalived, mais pas de scripts permettant à keepalived de communiquer avec quatre chose. C'est le rôle des notify scripts. On a plusieurs directives pour appeller des scripts dans des états particuliers, mais ici on ne verra que notify qui est la plus flexible. Quand un script est appellé via notify, il reçoit quatre arguments :
- Groupe ou instance : indique si le notify est provoqué par un group (on a pas parlé des groupes) ou une instance
- Nom du groupe / instance
- Etat vers lequel le groupe / instance transitionne
- Priorité
Exemple de script + conf: <source> server1# cat /usr/local/bin/keepalived_notify.sh
- !/bin/bash
echo "$1 $2 has transitioned to the $3 state with a priority of $4" > /var/run/keepalived_status
server1# cat keepalived.conf vrrp_script keepalived_check {
script "/usr/local/bin/keepalived_check.sh" interval 1 timeout 5 rise 3 fall 3
}
vrrp_instance VI_1 {
state MASTER interface eth0 virtual_router_id 51 priority 244 advert_int 1 authentication { auth_type PASS auth_pass 12345 } virtual_ipaddress { 192.168.122.200/24 } track_script { keepalived_check } notify "/usr/local/bin/keepalived_notify.sh"
} </source>
On voit que le script va écrire dans /var/run/keepalived_status:
<source> server1# cat /var/run/keepalived_status INSTANCE VI_1 has transitioned to the MASTER state with a priority of 244
server1# iptables -A OUTPUT -d 8.8.8.8 -j DROP server1# cat /var/run/keepalived_status INSTANCE VI_1 has transitioned to the FAULT state with a priority of 244
server1# iptables -D OUTPUT -d 8.8.8.8 -j DROP server1# cat /var/run/keepalived_status INSTANCE VI_1 has transitioned to the MASTER state with a priority of 244 </source>
Ce genre de scripts peut faire beaucoup de choses différentes.