Equilibreur de charge en local
Il est très facile de créer des équilibreurs de charge lorsqu'on travaille sur des clouds publics. Mais cette facilité n'est souvent pas disponible lorsque vous êtes sur un cloud privé, à moins que vous n'ayez des équipements spécifiques comme un F5 par exemple.
Voici un exemple de solution d'équilibrage de charge hautement disponible construite avec HAProxy Community Edition et Keepalived.
Création du lab
On commence par provisionner le lab. J'utilise ici Multipass pour créer les machines virtuelles, mais vous pouvez utilisez n'importe quelle autre solution si vous préférez.
1# Machines virtuelles pour l'équilibreur de charge
2multipass launch --name lb1 --mem 512M --cpus 1
3multipass launch --name lb2 --mem 512M --cpus 1
4# Machines virtuelles pour l'application
5multipass launch --name app1 --mem 512M --cpus 1
6multipass launch --name app2 --mem 512M --cpus 1
7
8# Aperçu de notre lab
9$ multipass list
10Name State IPv4 Image
11app1 Running 192.168.205.6 Ubuntu 20.04 LTS
12app2 Running 192.168.205.7 Ubuntu 20.04 LTS
13lb1 Running 192.168.205.4 Ubuntu 20.04 LTS
14lb2 Running 192.168.205.5 Ubuntu 20.04 LTS
L'application est une application web de démo déployée sur une machine virtuelle, mais elle pourrait être tout autre chose : une application conteneurisée, le contrôleur d'API Kubernetes, etc. HAProxy est capable de gérer n'importe quel flux TCP.
Installation de l'application de démo
D'abord, nous devons installer une application web sur les deux nœuds d'application. La solution d'équilibrage de charge distribuera les requêtes à ces serveurs. Nous nous appuierons sur la page d'accueil de NGINX pour l'application de démonstration. Dans la pratique, cela pourrait être n'importe quelle application ou API.
Installer Nginx sur les deux serveurs applicatifs pour héberger notre application de démo. Cela facilitera nos tests d'équilibrage de charge/
1# Ouvre un shell sur la première instance
2multipass shell app1
3
4# Installe Nginx
5sudo apt update
6sudo apt install nginx -y
7
8# Ouvre un shell sur la seconde instance
9multipass shell app2
10
11# Installe Nginx
12sudo apt update
13sudo apt install nginx -y
Customiser la page d'accueil par défaut sur chacun des serveurs pour ajouter le nom de la machine virtuelle dans le message d'accueil.
1<!-- Adapter le message pour afficher le nom su serveur -->
2<title>Welcome to app1!</title>
Installation de HAProxy
Maintenant nous pouvons installer le premier composant de notre solution d'équilibrage de charge: HAProxy.
Installer HAProxy sur chaque machine virtuelle lb
avecv la commande suivante:
1sudo apt install haproxy -y
Modifier le fichier de configuration /etc/haproxy/haproxy.cfg
sur chacun des serveurs avec la configuration suivante. Laisser la section globale dans l'état.
1defaults
2 log global
3 mode http
4 option httplog
5 option dontlognull
6 timeout connect 5000
7 timeout client 50000
8 timeout server 50000
9 errorfile 400 /etc/haproxy/errors/400.http
10 errorfile 403 /etc/haproxy/errors/403.http
11 errorfile 408 /etc/haproxy/errors/408.http
12 errorfile 500 /etc/haproxy/errors/500.http
13 errorfile 502 /etc/haproxy/errors/502.http
14 errorfile 503 /etc/haproxy/errors/503.http
15 errorfile 504 /etc/haproxy/errors/504.http
16
17frontend app
18 bind :::80
19 mode http
20 default_backend app
21
22backend app
23 balance roundrobin
24 mode http
25 option tcp-check
26 server app1 192.168.205.6:80 check
27 server app2 192.168.205.7:80 check
Notez l'usage de l'option tcp-check
qui permet de bénéficier de la fonctionnalité de health check.
Redémarrer HAProxy sur chaque serveur lb
:
1sudo service haproxy restart
A ce stade, si vous envoyez plusieurs requêtes sur l'un des serveurs lb
, vous devriez voir que HAProxy les répartit sur les serveurs app
.
Installation de Keepalived
Nous allons maintenant utiliser Keepalived pour créer une IP virtuelle qui représentera le point d'entrée unique de notre équilibreur de charge.
Installer Keepalived sur chaque serveur lb
:
1sudo apt install keepalived -y
Avant de le configurer, nous avons besoin de collecter des informations sur les interfaces réseau. On installe le package net-tools
pour avoir la commande ifconfig
, elle nous permettra de trouver le nom de l'interface qui correspond à l'IP:
1$ sudo apt install net-tools -y
2$ ifconfig
3enp0s2: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
4 inet 192.168.205.4 netmask 255.255.255.0 broadcast 192.168.205.255
5 inet6 fe80::cfe:19ff:fea2:c7f6 prefixlen 64 scopeid 0x20<link>
6 inet6 fdb2:f63f:a0b:91f4:cfe:19ff:fea2:c7f6 prefixlen 64 scopeid 0x0<global>
7 ether 0e:fe:19:a2:c7:f6 txqueuelen 1000 (Ethernet)
8 RX packets 67904 bytes 92365027 (92.3 MB)
9 RX errors 0 dropped 0 overruns 0 frame 0
10 TX packets 9319 bytes 1457132 (1.4 MB)
11 TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
12
13lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
14 inet 127.0.0.1 netmask 255.0.0.0
15 inet6 ::1 prefixlen 128 scopeid 0x10<host>
16 loop txqueuelen 1000 (Local Loopback)
17 RX packets 285 bytes 32750 (32.7 KB)
18 RX errors 0 dropped 0 overruns 0 frame 0
19 TX packets 285 bytes 32750 (32.7 KB)
20 TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
Dans notre cas il s'agit de enp02
. Nous allons la déclarer comme interface dans Keepalived (par défaut c'est eth0). Modifier la configuration en conséquence dans le fichier /etc/keepalived/keepalived.conf
:
1global_defs {
2 notification_email {
3 myemail@email.server.com
4 }
5 notification_email_from myemail@email.server.com
6 smtp_server mail.server.com
7 smtp_connect_timeout 30
8}
9vrrp_script chk_haproxy {
10 script "killall -0 haproxy"
11 interval 2
12 weight 2
13}
14vrrp_instance VI_1 {
15 interface enp0s2
16 state MASTER
17 virtual_router_id 51
18 priority 101
19 virtual_ipaddress {
20 192.168.205.100
21 }
22 track_script {
23 chk_haproxy
24 }
25}
Appliquer la même configuration sur le second noeud lb
mais en changeant:
- state:
BACKUP
à la place deMASTER
- priority:
100
au lieu de101
Démarrer Keepalived sur les deux noeuds lb
:
1sudo service keepalived start
Maintenant, vous devriez être capable de pinger l'IP virtuelle représentant le point d'entrée de l'équilibreurs de charge. Toutes les requêtes envoyées à cette IP virtuelle sont par défaut envoyées au nœud maître de l'équilibreurs de charge, qui distribue ensuite le trafic sur les deux nœuds applicatifs.
Vérifions en faisant un ping sur l'IP virtuelle:
1# Ping sur l'IP virtuelle de Keepalived
2$ ping 192.168.205.100
3PING 192.168.205.100 (192.168.205.100): 56 data bytes
464 bytes from 192.168.205.100: icmp_seq=0 ttl=64 time=0.506 ms
564 bytes from 192.168.205.100: icmp_seq=1 ttl=64 time=0.610 ms
6^C
7--- 192.168.205.100 ping statistics ---
82 packets transmitted, 2 packets received, 0.0% packet loss
9round-trip min/avg/max/stddev = 0.506/0.558/0.610/0.052 ms
Tests
Requêtes HTTP
Essayons maintenant d'envoyer des requêtes HTTP dessus pour voir ce qu'il se passe:
1# Première requête -> app1
2$ curl 192.168.205.100:80
3<!DOCTYPE html>
4<html>
5<head>
6<title>Welcome to nginx!</title>
7<style>
8 body {
9 width: 35em;
10 margin: 0 auto;
11 font-family: Tahoma, Verdana, Arial, sans-serif;
12 }
13</style>
14</head>
15<body>
16<h1>Welcome to app1 !</h1>
17<p>If you see this page, the nginx web server is successfully installed and
18working. Further configuration is required.</p>
19
20<p>For online documentation and support please refer to
21<a href="http://nginx.org/">nginx.org</a>.<br/>
22Commercial support is available at
23<a href="http://nginx.com/">nginx.com</a>.</p>
24
25<p><em>Thank you for using nginx.</em></p>
26</body>
27</html>
28
29# Seconde requête -> app2
30$ curl 192.168.205.100:80
31<!DOCTYPE html>
32<html>
33<head>
34<title>Welcome to nginx!</title>
35<style>
36 body {
37 width: 35em;
38 margin: 0 auto;
39 font-family: Tahoma, Verdana, Arial, sans-serif;
40 }
41</style>
42</head>
43<body>
44<h1>Welcome to app2 !</h1>
45<p>If you see this page, the nginx web server is successfully installed and
46working. Further configuration is required.</p>
47
48<p>For online documentation and support please refer to
49<a href="http://nginx.org/">nginx.org</a>.<br/>
50Commercial support is available at
51<a href="http://nginx.com/">nginx.com</a>.</p>
52
53<p><em>Thank you for using nginx.</em></p>
54</body>
55</html>
Nous avons pu constater que l'équilibreur de charge répartissait bien les requêtes sur nos serveurs applicatifs.
Panne d'un noeud lb
On peut tester la résilience de notre équilibreur de charge, voyons se qui se passe si le noeud MASTER
rencontre un problème :
1# Stop de lb1 (MASTER)
2$ multipass stop lb1
3
4# L'IP virtuelle a été associée à lb2 (BACKUP)
5$ multipass list
6Name State IPv4 Image
7app1 Running 192.168.205.6 Ubuntu 20.04 LTS
8app2 Running 192.168.205.7 Ubuntu 20.04 LTS
9lb1 Stopped -- Ubuntu 20.04 LTS
10lb2 Running 192.168.205.5 Ubuntu 20.04 LTS
11 192.168.205.100
12
13# Redémarrage de lb1 (MASTER)
14$ multipass start lb1
15
16# L'IP virtuelle est de nouveau associée au noeud lb1 (MASTER)
17$ multipass list
18Name State IPv4 Image
19app1 Running 192.168.205.6 Ubuntu 20.04 LTS
20app2 Running 192.168.205.7 Ubuntu 20.04 LTS
21lb1 Running 192.168.205.4 Ubuntu 20.04 LTS
22 192.168.205.100
23lb2 Running 192.168.205.5 Ubuntu 20.04 LTS
L'IP virtuelle est associée au noeud MASTER
par défaut, elle bascule sur le noeud BACKUP
uniquement en cas de défaillance de MASTER
.
Panne sur un noeud applicatif
Nous allons simuler une panne sur l'un des deux noeuds applicatifs et vérifier que HAProxy arrête de lui envoyer des requêtes pour éviter que l'utilisateur n'ait des erreurs.
On arrête le noeud app1:
1multipass stop app1
Envoyez plusieurs requêtes HTTP, vous verrez que toutes les requêtes sont bien envoyées sur le seul noeud restant: app2. C'est grâce à la fonctionnalité de health check que HAProxy a détecté la défaillance et modifié dynamiquement la liste des serveurs cibles pour retirer app1.
Rédémarrons le noeud app1:
1multipass start app1
En envoyant des requêtes, on constate que HAProxy utilise de nouveau les deux serveurs applicatifs.
Test de charge
Nous allons générer de la charge pour voir comment notre solution d'équilibrage de charge se comporte. Pour cela, nous utiliserons la solution ab avec la configuration suivante:
- Concurrency: 50
- Requests: 300 000
Voici les résultats obtenus:
- Notre équilibreur de charge fonctionne !
- It fonctionne même bien malgré l'utilisation de machines virtuelles avec peu de ressources (1 coeur, 512 Mb de RAM)
- La courbe des deux serveurs applicatifs est pratiquement identique, la solution a bien réparti la charge
- Le noeud lb MASTER a encaissé la charge sans sourciller, le noeud lb BACKUP est resté tranquille
Conclusion
Nous avons construit une solution d'équilibrage de charge opérationnelle et hautement disponible pour notre application.
- On peut augmenter la capacité de traitement en ajoutant de nouveaux nœuds applicatifs, il suffira alors d'adapter la configuration de HAProxy.
- On peut également augmenter la capacité de traitement de l'équilibreurs de charge lui-même en ajoutant de nouveaux nœuds lb avec la même configuration Keepalived.
Il pourra être nécessaire de créer plusieurs instances de la solution si :
- Vous souhaitez avoir différentes expositions
- Vous voulez utiliser les mêmes ports plusieurs fois
- Il y a beaucoup d'autres fonctionnalités supplémentaires dans HAProxy et Keepalived qui peuvent vous intéresser, consultez leur documentation pour plus de détails.
N'hésitez pas à m'envoyer vos retours ou suggestions éventuelles pour améliorer cet article. Merci.