Laboratoire infra Linux HA #5 – Load balancing avec HAProxy et Keepalived

Laboratoire infra Linux HA #5 – Load balancing avec HAProxy et Keepalived

lab07-front-02, lab07-lb-01 et lab07-lb-02

Cet article est le cinquième opus de la suite d’articles sur la mise en œuvre d’une infrastructure Linux visant à servir le blog « lab07.lab » en haute dispo.

Dans le précédent article, nous avons enfin mis en œuvre de la haute-disponibilité pour le stockage du code de notre blog.

Dans cet article on va d’abord ajouter un nouveau serveur FRONT et comme ça devrait aller vite, on ajoutera deux rĂ©partiteurs de charge (load balancers ou encore LB) Ă  l’aide de HAProxy qui partageront une VIP gĂ©rĂ©e par Keepalived.

HAProxy va nous permettre de faire de jolies choses tu vas voir : il va bien entendu rĂ©partir les requĂŞtes HTTP entre les serveurs ce qui sera dĂ©jĂ  pratique mais, il va Ă©galement nous permettre de rediriger le trafic sur un seul nĹ“ud si l’autre est en maintenance afin d’Ă©viter que de nombreux visiteurs (krrkrrkrr) de « lab07.lab » ne reçoivent un timeout.

On s’y met ?

Ajouter un nouveau serveur FRONT lab07-front-02

DĂ©sormais tu devrais savoir comment prĂ©parer la machine sinon tu relis ce qu’on a fait dans les articles prĂ©cĂ©dents ou bien tu vĂ©rifie avec history les commandes sur les autres machines, quand c’est bon tu reviens sur l’article.

On va installer les outils nĂ©cessaires Ă  l’usage du dĂ©pĂ´t Sury puis installer Apache, PHP8.3 et son module de connexion MySQL.

ShellSession
root@lab07-front-02:~# apt install curl lsb-release ca-certificates gnupg2
root@lab07-front-02:~# sh -c 'echo "deb [signed-by=/usr/share/keyrings/deb.sury.org-php.gpg] https://packages.sury.org/php/ $(lsb_release -sc) main" > /etc/apt/sources.list.d/php.list'
root@lab07-front-02:~# curl -sSLo /tmp/debsuryorg-archive-keyring.deb https://packages.sury.org/debsuryorg-archive-keyring.deb
root@lab07-front-02:~# dpkg -i /tmp/debsuryorg-archive-keyring.deb
root@lab07-front-02:~# apt install apache2 php8.3 php8.3-mysql
root@lab07-front-02:~# a2enmod php8.3
root@lab07-front-02:~# systemctl restart apache2

# Bon PHP8.3 était déjà autorisé mais ça mange pas de pain

On va installer nfs-common, paramĂ©trer la connexion Ă  la VIP de nos serveurs NFS en recopiant la dernière ligne du fstab de lab07-front-01 (parce que je sais que c’est ma dernière ligne, fais pas n’imp non plus) et lancer la connexion .

ShellSession
root@lab07-front-02:~# apt install nfs-common
root@lab07-front-02:~# ssh lab07-front-01 'tail -n1 /etc/fstab' >> /etc/fstab
root@lab07-front-01's password:
root@lab07-front-02:~# mount /var/www

lab07-front-02 a dĂ©sormais un Apache d’installĂ©, capable de servir du PHP et accès au code. Il ne reste plus qu’Ă  paramĂ©trer et activer son vhost. Il va ĂŞtre identique Ă  celui de lab07-front-01 alors pourquoi se casser la tĂŞte ? On va le dupliquer depuis le premier FRONT.

ShellSession
root@lab07-front-02:~# scp lab07-front-01:/etc/apache2/sites-available/lab07.lab.conf /etc/apache2/sites-available/
root@lab07-front-01's password: 
lab07.lab.conf                                                                                                                                                                                             100%  294   148.7KB/s   00:00    
root@lab07-front-02:~# a2ensite lab07.lab
Enabling site lab07.lab.
To activate the new configuration, you need to run:
  systemctl reload apache2
root@lab07-front-02:~# systemctl reload apache2

On va modifier le fichier /etc/hosts de notre machine locale et dĂ©placer “lab07.lab” sur lab07-front-02 puis on tentera de surfer sur http://lab07.lab. On s’assurera de bien surfer sur le bon serveur – ce serait vraiment balo que tu sois en train de surfer sur lab07-front-01 nan ?

Encore une bonne excuse bidon pour prĂ©senter l’usage d’un outil basique. Tu vas faire un tail -f /var/log/apache2/access_lab07.lab_log, appuyer sur EntrĂ©e quelques fois pour bien diffĂ©rencier ce qui est dĂ©jĂ  prĂ©sent dans le journal et ce qui va venir. Ensuite tu ouvres http://lab07.lab.

On a bien deux serveurs FRONT capable de servir notre site mais que ce soit modifier notre /etc/hosts, une zone DNS ou encore, une ouverture de port, ça ne sera pas super amusant et encore moins automatique. Pour cette raison notamment, on va mettre des load balancers en amont de nos serveurs FRONT.

Les reverse proxy

Tu commences à connaître le job, on va préparer directement les deux load balancers lab07-lb-01 et lab07-lb-02. Une fois prêtes, on va pouvoir installer HAProxy sur les deux et le configurer.
Sur le principe pour notre usage HAProxy est simple, on lui donne une VIP en frontend et nos serveurs FRONT en backend.

ShellSession
root@lab07-lb-01:~# apt install haproxy

Le fichier de configuration vient en partie remplie. Mais surtout, le manuel de HAProxy, man haproxy nous informe qu’une documentation de configuration a Ă©tĂ© dĂ©posĂ©e dans /usr/share/doc/haproxy/configuration.txt.gz.

Options par défaut

On va déjà modifier un peu les contraintes temporelles timeout pour commencer.

ShellSession
root@lab07-lb-01:~# vi /etc/haproxy/haproxy.cfg
/etc/haproxy/haproxy.cfg
#[...]
defaults
        log     global
        mode    http
        option  httplog
        option  dontlognull
        timeout connect 5s
        timeout client  50s
        timeout server  100s
        errorfile 400 /etc/haproxy/errors/400.http
        errorfile 403 /etc/haproxy/errors/403.http
        errorfile 408 /etc/haproxy/errors/408.http
        errorfile 500 /etc/haproxy/errors/500.http
        errorfile 502 /etc/haproxy/errors/502.http
        errorfile 503 /etc/haproxy/errors/503.http
        errorfile 504 /etc/haproxy/errors/504.http

Nos serveurs LB ne vont gérer que du HTTP, on aurai pu paramétrer http directement en face de log.

Les timeout sont très hauts, il faudra les abaisser petit Ă  petit. Perso je viens de perdre plus d’1h30 parce que j’avais paramĂ©trĂ© 1s/2s/2s et j’ai cherchĂ© dans tous les sens (le vhost d’Apache, les droits sur les fichiers de WordPress sur le NFS, ajout du no_root_squash) avant de capter que c’Ă©tait trop bas.

L’interface d’administration

A la suite, dans le mĂŞme fichier de configuration, on va configurer l’interface web de HAProxy stats pour pouvoir gĂ©rer nos serveur FRONT en ajoutant ce paragraphe.

/etc/haproxy/haproxy.cfg
#[...]
listen stats
	bind            0.0.0.0:12345     # on Ă©coute sur toutes les IP de l'hote sur le port 12345
	mode            http              # en HTTP
	maxconn         10                # tolérer 10 clients ce sera déjà pas mal
	stats           enable            # on autorise
	stats           refresh 20s       # avec un rafraîchissement de 20s
	stats           show-legends      # pour rendre la page de stats plus bavarde
	stats           show-node         # afficher les nodes
	stats           hide-version      # pour rendre la page de stats moins bavarde
	stats           uri /             # sur quelle adresse sera servie notre page de stats
	acl is_auth     http_auth(stats)  # et puis un peu de sécurité et des contraintes temporelles...
	acl is_admin    http_auth_group(stats) stats-admin
	stats           http-request auth unless is_auth
	stats           admin if is_admin
	timeout         client 100s
	timeout         server 100s
	timeout         connect 100s
	timeout         queue 100s

L’administrateur

T’as vu on a parlĂ© d’admin, d’is_admin sans que je ne dĂ©taille. Tu te demandes comment on va accĂ©der ou comment dĂ©finir qu’on est admin ? On va ajouter un nouveau paragraphe au fichier de configuration pour le dĂ©finir.

/etc/haproxy/haproxy.cfg
#[...]
userlist stats
	user haproxy insecure-password haproxy groups stats-admin # la 2nde occurence de haproxy sur cette ligne représente le mot de passe, déconne pas ne laisse pas comme ça
	group stats-admin

De mĂŞme, la documentation en ligne de HAProxy est très claire pour l’usage d’un hash plutĂ´t qu’une chaĂ®ne. Bon tu vas pas recommencer Ă  me casser les pieds non ? Puisque je te dis que c’est un lab, on peut laisser une chaĂ®ne Ă  la con!
Mais c’est pas vrai, faut toujours que t’insiste…

ShellSession
root@lab07-lb-01:~# apt install pwgen whois
root@lab07-lb-01:~# pwgen -sBc 14 1
XbgdvdecR4FtTc
root@lab07-lb-01:~# mkpasswd -m sha-256 XbgdvdecR4FtTc
$5$J1SG0OvQzflKD.H/$UxRuSEbQiaS3vcg6ivqGk4ZVe7R0VoPDO0uv4CaIPV.
root@lab07-lb-01:~# mkpasswd -m sha-256 haproxy
$5$n4v2tmh4SG2foaBg$4GiE28c4h0zwdnn1YTxE5U7eu2wdib/E6CBqLeXthkD

Depuis le temps que tu lis, j’espère que tu as compris d’utiliser tes mots de passe perso ou, de lancer toi-mĂŞme la commande pwgen (avec la paramètres qui te conviennent d’ailleurs) et que tu rĂ©utilise pas les mots de passe que je gĂ©nère dans mon lab pour ta prod ?!

On remplace alors le paragraphe précédent par le suivant.

/etc/haproxy/haproxy.cfg
#[...]
userlist stats
	user haproxy password $5$n4v2tmh4SG2foaBg$4GiE28c4h0zwdnn1YTxE5U7eu2wdib/E6CBqLeXthkD groups stats-admin
	group stats-admin

Ça va t’es heureux lĂ  ? T’façon c’est pas mon problème, je vais garder l’embrouillamini de haproxy moi.

La VIP et les FRONT

Je t’avoue qu’on vient de finir la partie la moins passionnante de la configuration de HAProxy. On peut enfin s’attaquer Ă  ce qui nous intĂ©resse le plus : la rĂ©partition de charge et la tolĂ©rance de panne de nos serveurs FRONT Ă  l’aide de l’adresse IP virtuelle.

/etc/haproxy/haproxy.cfg
#[...]
frontend lab07
	bind	192.168.50.30:80		# Donner l'IP virtuelle du keepalived sinon "Cannot assign requested address"
	mode http                 # On paramètre le proxy en http (couche 7 du modèle OSI, Application) pour inspecter les messages HTTP (traduction éhontée de la doc officielle, tu vas faire quoi ?)
	default_backend	frontservers    # Vers qui on redirige ?
	option	httplog           # Journalisation des requĂŞtes HTTP, des sessions et timers (c'est quoi un timer ?)

backend frontservers
	balance		roundrobin
	option          httpchk    # Les backends devront retourner un code HTTP 2xx ou 3xx
	http-check      connect    # Ouvre une nouvelle connexion pour vérifier l'état de santé HTTP
	mode		http
	server		lab07-front-01	192.168.50.23:80	check
	server		lab07-front-02	192.168.50.24:80	check

Tu peux dupliquer le fichier haproxy.cfg de lab07-lb-01 vers lab07-lb-02 via scp, rsync ou comme moi, Ă  la pogne (clic molette for the win).

On va quand mĂŞme demander Ă  HAProxy ce qu’il pense de tout ça.

ShellSession
root@lab07-lb-01:~# haproxy -c -f /etc/haproxy/haproxy.cfg
Configuration file is valid

La gestion de l’IP virtuelle par Keepalived

Dans notre configuration d’HAProxy on a renseignĂ© la VIP sur laquelle il va rĂ©pondre mais elle n’est paramĂ©trĂ©e nulle part. Ce n’est pas le taf d’HAProxy d’attribuer la VIP Ă  l’un ou l’autre des serveurs LB ; c’est le travail de Keepalived.

Par dĂ©faut, l’OS ne laissera pas Keepalived attribuer la VIP parce qu’elle n’existe pas dans la configuration des interfaces. On n’a pas le droit ? On prend le gauche ! Pour la session en cours et de manière persistante.

ShellSession
root@lab07-lb-01:~# sysctl --write net.ipv4.ip_nonlocal_bind=1
root@lab07-lb-01:~# vi /etc/sysctl.conf
/etc/sysctl.conf
#[...]
net.ipv4.ip_nonlocal_bind=1

Sur le premier serveur, on a utiliser l’approche de modifier le fonctionnement du système et de reporter la configuration dans le fichier de configuration par dĂ©faut. On peut tout Ă  fait fonctionner de manière inverse, amender le fichier de configuration puis recharger le fichier de configuration.

ShellSession
root@lab07-lb-02:~# vi /etc/sysctl.conf
/etc/sysctl.conf
#[...]
net.ipv4.ip_nonlocal_bind=1
ShellSession
root@lab07-lb-02:~# sysctl -p
net.ipv4.ip_nonlocal_bind = 1

J’ai pas spĂ©cifiĂ© le fichier de configuration Ă  utiliser parce que je suis fainĂ©ant mais sur un système en production j’aurai peut-ĂŞtre pas fait le malin et j’aurai ajoutĂ© le chemin sysctl -p /etc/sysctl.conf.

Quelle que soit ta méthode préférée, fais le sur les deux serveurs LB et on est prêt pour installer Keepalived.

ShellSession
root@lab07-lb-01:~# apt install keepalived

Toi tu sais pas parce que tu vois que le travail (Ă  peu près) abouti mais, moi je relis les notes que j’avais prises lorsque j’ai fait le laboratoire la première fois et je comprenais pas pourquoi j’avais conservĂ© aucune note de la configuration de Keepalived.

OuĂ© je sais je perds un peu de ma superbe quand je t’Ă©cris que je lis mes notes, mais je suis pas un barbu ; je suis probablement Ă  peine au dessus de la poule qui a trouvĂ© un couteau.

Une fois le paquet installĂ©, lĂ  j’ai compris pourquoi j’avais pas de notes. Parce que Keepalived est livrĂ© avec un magnifique fichier d’exemple : /etc/keepalived/keepalived.conf.sample !

Guy Roux (les Guignols de l'info) - "Faut pas gâcher."
ShellSession
root@lab07-lb-01:~# cp /etc/keepalived/keepalived.conf.sample /etc/keepalived/keepalived.conf
root@lab07-lb-01:~# vi /etc/keepalived/keepalived.conf

Bon je te confie que je vais pas juste Ă©purer et adapter le fichier de configuration mais je vais le commenter en paraphrasant la documentation ; comme d’hab quoi.

root@lab07-lb-01:/etc/keepalived/keepalived.conf
! Configuration File for keepalived

global_defs {
   vrrp_no_swap                 # Le processus VRRP enfant reste en RAM, pas de swap
   vrrp_garp_master_delay 10    # Délais en secondes de grace ARP après une transition en MASTER
   vrrp_garp_master_refresh 60  # DĂ©lais minimum de rafraichissement de la grace ARP tant que le noeud est MASTER
   vrrp_garp_interval 0.001     # Délais entre les messages ARP gratuits envoyés a une interface
}

vrrp_instance lab07-lb-vip {    # Nom de l'instance VRRP
    state MASTER                # Etat par défaut
    interface enp0s3            # Interface sur laquelle repose la VIP
    virtual_router_id 1         # ID du routeur pour s'entendre avec le second noeud
    priority 100                # Priorité du présent noeud (le plus haut gagne - max 255)
    advert_int 1                # DĂ©lais de l'envoi de trames
    authentication {
        auth_type PASS
        auth_pass 8_Caract      # eres_max
    }
    virtual_ipaddress {
        192.168.50.30           # Notre VIP
    }
    unicast_src_ip 192.168.50.21 # IP du présent noeud
    unicast_peer {
        192.168.50.22           # IP du second noeud
    }
}

Et je garde la mĂŞme configuration sur lab07-lb-02, je vais juste inverser les adresses source et pair.

root@lab07-lb-02:/etc/keepalived/keepalived.conf
! Configuration File for keepalived

global_defs {
   vrrp_no_swap                 # Le processus VRRP enfant reste en RAM, pas de swap
   vrrp_garp_master_delay 10    # Délais en secondes de grace ARP après une transition en MASTER
   vrrp_garp_master_refresh 60  # DĂ©lais minimum de rafraichissement de la grace ARP tant que le noeud est MASTER
   vrrp_garp_interval 0.001     # Délais entre les messages ARP gratuits envoyés a une interface
}

vrrp_instance lab07-lb-vip {    # Nom de l'instance VRRP
    state BACKUP                # Etat par défaut
    interface enp0s3            # Interface sur laquelle repose la VIP
    virtual_router_id 1         # ID du routeur pour s'entendre avec le second noeud
    priority 100                # Priorité du présent noeud (le plus haut gagne - max 255)
    advert_int 1                # DĂ©lais de l'envoi de trames
    authentication {
        auth_type PASS
        auth_pass 8_Caract      # eres_max
    }
    virtual_ipaddress {
        192.168.50.30           # Notre VIP
    }
    unicast_src_ip 192.168.50.22 # IP du présent noeud
    unicast_peer {
        192.168.50.21           # IP du second noeud
    }
}

Un petit restart des Keepalived sur chaque serveur LB. Tu adaptes le hosts de ta machine pour que lab07.lab soit sur la même IP que la lab07-lb.vip et ça devrait surfer.

Qui c’est qui sert le blog ?

Génial, tout fonctionne mais on peux avoir besoin de savoir vers quel backend la requête HTTP à été redirigée, non ? On peut par exemple déposer un cookie en reconfigurant HAProxy.

ShellSession
root@lab07-lb-01:~# vi /etc/haproxy/haproxy.cfg
/etc/haproxy/haproxy.cfg
#[...]
backend frontservers
        cookie          SERVERID insert  # Je déclare mon cookie au niveau du backend
        balance         roundrobin
        option          httpchk
        http-check      connect
        mode            http
        server          lab07-front-01  192.168.50.23:80        check   cookie lab07-front-01  # Je l'ajoute au niveau de chaque serveur
        server          lab07-front-02  192.168.50.24:80        check   cookie lab07-front-02  # Je l'ajoute au niveau de chaque serveur

On a changĂ© la conf donc on doit redĂ©marrer l’outil.

ShellSession
root@lab07-lb-01:~# systemctl restart haproxy

Maintenant on peut s’assurer depuis un poste client que le cookie est bien dĂ©posĂ©. Pour ça on va faire 10 curls successifs et regarder la tronche du cookie.

ShellSession
antoine@dressing:~$ for i in {1..10}; do curl -c - http://lab07.lab 2>/dev/null| tail -1; done
lab07.lab       FALSE   /       FALSE   0       SERVERID        lab07-front-01
lab07.lab       FALSE   /       FALSE   0       SERVERID        lab07-front-02
lab07.lab       FALSE   /       FALSE   0       SERVERID        lab07-front-01
lab07.lab       FALSE   /       FALSE   0       SERVERID        lab07-front-02
lab07.lab       FALSE   /       FALSE   0       SERVERID        lab07-front-01
lab07.lab       FALSE   /       FALSE   0       SERVERID        lab07-front-02
lab07.lab       FALSE   /       FALSE   0       SERVERID        lab07-front-01
lab07.lab       FALSE   /       FALSE   0       SERVERID        lab07-front-02
lab07.lab       FALSE   /       FALSE   0       SERVERID        lab07-front-01
lab07.lab       FALSE   /       FALSE   0       SERVERID        lab07-front-02

Non seulement notre cookie est bien déposé mais en même temps on constate que le roundrobbin fait bien son boulot.

Bon le roundrobbin c’est bien mais il faudra quand mĂŞme penser Ă  partager les sessions entre les serveurs.
Je ne suis pas encore assez calĂ© sur le sujet mais on pourrait imaginer qu’un de nos serveurs hĂ©berge un Redis ou un Ă©tage supplĂ©mentaire avec un cluster Redis.

La page de stats de HAProxy

On en a parlĂ© très sommairement plus haut mais la page de statistiques est vraiment importante. On y accède par l’IP des LB ou directement par la VIP.

Elle va avoir un Ă©norme intĂ©rĂŞt pour pouvoir passer un de nos backends “frontservers” en maintenance lorsque nĂ©cessaire et HAProxy ne redirigera plus que sur le FRONT qui est fonctionnel. Ça se passe dans le menu dĂ©roulant tout en bas de la page et s’applique au(x) backend(s) dont la case est(sont) cochĂ©e(s). Ok… je te lâche la main.

Dans la vraie vie, tu préféreras passer ton serveur en DRAIN avant de le passer en MAINT pour ne pas fermer la porte au nez de tes clients.

ShellSession
antoine@dressing:~$ for i in {1..10}; do curl -c - http://lab07.lab 2>/dev/null| tail -1; done
lab07.lab       FALSE   /       FALSE   0       SERVERID        lab07-front-02
lab07.lab       FALSE   /       FALSE   0       SERVERID        lab07-front-02
lab07.lab       FALSE   /       FALSE   0       SERVERID        lab07-front-02
lab07.lab       FALSE   /       FALSE   0       SERVERID        lab07-front-02
lab07.lab       FALSE   /       FALSE   0       SERVERID        lab07-front-02
lab07.lab       FALSE   /       FALSE   0       SERVERID        lab07-front-02
lab07.lab       FALSE   /       FALSE   0       SERVERID        lab07-front-02
lab07.lab       FALSE   /       FALSE   0       SERVERID        lab07-front-02
lab07.lab       FALSE   /       FALSE   0       SERVERID        lab07-front-02
lab07.lab       FALSE   /       FALSE   0       SERVERID        lab07-front-02

T’as vu ? HAProxy a tout redirigĂ© sur lab07-front-02.

On a un peu modifié notre lab depuis le dernier schéma : on a ajouté un FRONT et les deux LB. Voici ce à quoi il ressemble.

La fritte sur l’macdo

On peut mĂŞme regarder notre Keepalived taper la causette.

ShellSession
root@lab07-lb-01:~# tcpdump -i enp0s3 -nn 'host 192.168.50.21 and vrrp'
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on enp0s3, link-type EN10MB (Ethernet), snapshot length 262144 bytes
15:03:28.385511 IP 192.168.50.21 > 192.168.50.22: VRRPv2, Advertisement, vrid 1, prio 100, authtype simple, intvl 1s, length 20
15:03:29.385837 IP 192.168.50.21 > 192.168.50.22: VRRPv2, Advertisement, vrid 1, prio 100, authtype simple, intvl 1s, length 20
15:03:30.386244 IP 192.168.50.21 > 192.168.50.22: VRRPv2, Advertisement, 
vrid 1, prio 100, authtype simple, intvl 1s, length 20
[...]
root@lab07-lb-01:~# tcpdump -i enp0s3 -nn 'host 192.168.50.22 and vrrp'
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on enp0s3, link-type EN10MB (Ethernet), snapshot length 262144 bytes
15:03:46.396094 IP 192.168.50.21 > 192.168.50.22: VRRPv2, Advertisement, vrid 1, prio 100, authtype simple, intvl 1s, length 20
15:03:47.396626 IP 192.168.50.21 > 192.168.50.22: VRRPv2, Advertisement, vrid 1, prio 100, authtype simple, intvl 1s, length 20
15:03:48.400254 IP 192.168.50.21 > 192.168.50.22: VRRPv2, Advertisement, vrid 1, prio 100, authtype simple, intvl 1s, length 20
fin de la cassette

Fin de la bande

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *