LVS et haute-disponibilité sous Linux avec Keepalived

On poursuit nos tests et nos expériences en matière de répartition de charge et de haute-disponibilité sous Linux. Souvenez-vous, après vous avoir brièvement présenté LVS, nous l’avions mis en pratique pour répartir un flux HTTP sur deux machines.

Schéma LVS DR

Nous avions donc un service web capable de supporter de forts trafics, celui-ci étant réparti sur deux serveurs. Sauf que si l’un de ces deux serveurs venait à tomber en panne, notre directeur LVS continuerait bêtement à répartir le trafic à la fois sur la machine en bonne santé, mais aussi sur celle tombée…

Nous allons donc voir comment mettre en place un mécanisme de vérification afin que LVS soit au courant de l’état des machines vers lesquelles il redirige le trafic, notamment grâce à Keepalived.

Configuration du LVS avec Keepalived

Dans mes précédents articles, nous avions manipulé LVS avec la commande ipvsadm.

ipvsadm -Ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
TCP  192.168.24.120:80 rr
  -> 192.168.24.121:80            Route   1      0          0         
  -> 192.168.24.122:80            Route   1      0          0         
TCP  192.168.24.120:443 rr
  -> 192.168.24.121:443           Route   1      0          0         
  -> 192.168.24.122:443           Route   1      0          0

Très pratique pour découvrir LVS, l’intérêt devient vite limité lorsque nous avons besoin de flexibilité. C’est pourquoi nous allons déléguer la configuration de LVS à Keepalived.

Keepalived est un daemon qui va nous permettre de répondre à deux problématiques : comment répartir des flux sur plusieurs machines ? Comment s’assurer de leur bon fonctionnement ?

Son installation est très simple sous Debian puisqu’il suffit simplement d’utiliser APT :

sudo apt-get install keepalived

À installer évidemment sur votre directeur. Pour rappel, je travaille sur l’architecture suivante (voir schéma d’introduction) :

Hôte Rôle Adresse IP
LVS-01 Directeur 192.168.24.131 (DIP)
LVS-01 Directeur 192.168.24.120 (VIP)
API-01 Serveur réel 192.168.24.121 (RIP1)
API-02 Serveur réel 192.168.24.122 (RIP2)

Configuration de l’IP virtuelle

Toutes les modifications suivantes sont à effectuer dans /etc/keepalived/keepalived.conf. La première étape consiste donc à déclarer l’adresse IP virtuelle à laquelle les clients pourront accéder au service, et à partir de laquelle LVS va répartir la charge.

static_ipaddress {
        192.168.24.120/24 dev eth0 scope global
}

Cette adresse est simplement déclarée sur eth0.

ip addr show eth0
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 00:50:56:21:b6:1a brd ff:ff:ff:ff:ff:ff
    inet 192.168.24.131/24 brd 192.168.24.255 scope global eth0
       valid_lft forever preferred_lft forever
    inet 192.168.24.120/24 scope global secondary eth0
       valid_lft forever preferred_lft forever

Déclaration du serveur virtuel

Ensuite, nous devons configurer le serveur virtuel qui va recevoir les requêtes adressées à 192.168.24.120. Comme dans les articles précédents, ce serveur virtuel est identifié par une adresse ip et un port. Il nous faut donc autant de serveurs virtuels que de ports utilisés. Deux par exemple dans mon cas : un pour HTTP (port 80) et un pour HTTPS (port 443).

virtual_server 192.168.24.120 80 {
        lb_algo rr
        lb_kind DR
        protocol TCP
        delay_loop 1
}

Si vous avez lu mes précédents tests, vous reconnaîtrez les options ci-dessus.

  • lb_algo rr : correspond à l’algorithme de répartition utilisé, ici round-robin.
  • lb_kind DR : au mode de répartition, ici DR pour Direct Rounting
  • delay_loop : indique la fréquence à laquelle Keepalived doit vérifier l’état du serveur, ici 1 seconde;

Déclaration des serveurs réels

Après la configuration du serveur virtuel vient logiquement la configuration des serveurs réels vers lesquels répartir la charge. Cette déclaration se fait comme suit :

virtual_server 192.168.24.120 80 {
        [...]
        real_server 192.168.24.121 80 {
                weight 1
                inhibit_on_failure
        }
}

Ici aussi les options restent explicites :

  • weight : spécifie le poids de la machine dans le cluster, à affiner si vous avez des machines hétérogènes;
  • inhibit_on_failure : permet, vous vous en doutez, d’arrêter la répartition de la charge sur le serveur si le test de vérification a échoué.

Déclarez autant de serveurs réels que vous en avez, pour mon projet j’en ai deux. Pour appliquer les paramètres :

sudo service keepalived restart

Et pour vérifier que tout s’est bien passé, la sortie de ipvsadm -Ln devrait ressembler à ce que j’ai mis en introduction.

Mise en place des tests Keepalived – Serveurs réels

À ce stade, nous ne sommes pas plus loin que là ou nous nous étions arrêté dans l’article précédent, hormis le fait qu’ici tout est configuré via Keepalived. Je vous l’ai dit l’intérêt d’utiliser Keepalived c’est que nous allons pouvoir définir des tests pour que notre directeur surveille l’état de santé des serveurs réels afin d’adapter automatiquement son comportement.

Dans notre cas, un service web, c’est très simple (encore) puisque Keepalived est fourni avec un test spécialement adapté à ce type de service…

HTTP_GET

C’est le petit nom que porte ce test, et il se place dans la déclaration de votre serveur réel.

virtual_server 192.168.24.120 80 {
        [...]
        real_server 192.168.24.121 80 {
                [...]
                HTTP_GET {
                        url {
                                path /service.txt
                                digest 3954c19e625161dbee151413cb552f6a
                        }
                        connect_port 80
                        connect_timeout 2
                        nb_get_retry 1
                        delay_before_retry 1
                }
        }
}

Que se passe-t-il par ici ?!
Nous fournissons à Keepalived une URL sur laquelle il va envoyer des requêtes à intervalle de temps régulier (définit par delay_loop et en calculer un hash. Personnellement je ne me suis pas pris la tête, j’ai simplement définit un fichier texte avec un contenu bidon mais l’intérêt est double ! Non seulement le fait de tenter d’accéder à l’url permet à Keepalived de vérifier que le service fonctionne, mais le calcul du hash lui permet de vérifier que le contenu de la page n’a pas été compromis ou modifié. À vous d’adapter votre test pour qu’il corresponde à vos besoins !

Pour calculer le hash, l’outil genhash est disponible. L’option -v vous apporte un peu de verbosité :

genhash -s 192.168.24.121 -p 80 -u /service.txt -v
-----------------------[    HTTP Header Buffer    ]-----------------------
0000  48 54 54 50 2f 31 2e 31 - 20 32 30 30 20 4f 4b 0d   HTTP/1.1 200 OK.
0010  0a 53 65 72 76 65 72 3a - 20 6e 67 69 6e 78 2f 31   .Server: nginx/1
0020  2e 36 2e 30 0d 0a 44 61 - 74 65 3a 20 4d 6f 6e 2c   .6.0..Date: Mon,
0030  20 30 35 20 4d 61 79 20 - 32 30 31 34 20 31 34 3a    05 May 2014 14:
0040  34 36 3a 33 32 20 47 4d - 54 0d 0a 43 6f 6e 74 65   46:32 GMT..Conte
0050  6e 74 2d 54 79 70 65 3a - 20 74 65 78 74 2f 70 6c   nt-Type: text/pl
0060  61 69 6e 0d 0a 43 6f 6e - 74 65 6e 74 2d 4c 65 6e   ain..Content-Len
0070  67 74 68 3a 20 31 32 35 - 0d 0a 4c 61 73 74 2d 4d   gth: 125..Last-M
0080  6f 64 69 66 69 65 64 3a - 20 4d 6f 6e 2c 20 30 35   odified: Mon, 05
0090  20 4d 61 79 20 32 30 31 - 34 20 31 30 3a 31 33 3a    May 2014 10:13:
00a0  34 36 20 47 4d 54 0d 0a - 43 6f 6e 6e 65 63 74 69   46 GMT..Connecti
00b0  6f 6e 3a 20 63 6c 6f 73 - 65 0d 0a 45 54 61 67 3a   on: close..ETag:
00c0  20 22 35 33 36 37 36 34 - 35 61 2d 37 64 22 0d 0a    "5367645a-7d"..
00d0  41 63 63 65 70 74 2d 52 - 61 6e 67 65 73 3a 20 62   Accept-Ranges: b
00e0  79 74 65 73 0d 0a 0d 0a -                           ytes....        
-----------------------[ HTTP Header Ascii Buffer ]-----------------------
HTTP/1.1 200 OK
Server: nginx/1.6.0
Date: Mon, 05 May 2014 14:46:32 GMT
Content-Type: text/plain
Content-Length: 125
Last-Modified: Mon, 05 May 2014 10:13:46 GMT
Connection: close
ETag: "5367645a-7d"
Accept-Ranges: bytes
 
 
-----------------------[       HTML Buffer        ]-----------------------
0000  7c 20 2d 2d 2d 2d 2d 2d - 2d 20 2f 21 5c 20 44 4f   | ------- /!\ DO
0010  20 4e 4f 54 20 44 45 4c - 45 54 45 20 2f 21 5c 20    NOT DELETE /!\ 
0020  2d 2d 2d 2d 2d 2d 2d 20 - 2b 0a 7c 0a 7c 20 54 68   ------- +.|.| Th
0030  69 73 20 69 73 20 61 20 - 4b 65 65 70 61 6c 69 76   is is a Keepaliv
0040  65 64 20 73 65 72 76 69 - 63 65 20 70 61 67 65 2e   ed service page.
0050  0a 7c 0a 7c 20 2d 2d 2d - 2d 2d 2d 2d 20 2f 21 5c   .|.| ------- /!\
0060  20 44 4f 20 4e 4f 54 20 - 44 45 4c 45 54 45 20 2f    DO NOT DELETE /
0070  21 5c 20 2d 2d 2d 2d 2d - 2d 2d 20 2b 0a            !\ ------- +.   
 
-----------------------[    HTML hash resulting    ]-----------------------
0000  39 54 c1 9e 62 51 61 db - ee 15 14 13 cb 55 2f 6a   9T..bQa......U/j
-----------------------[ HTML hash final resulting ]-----------------------
MD5SUM = 3954c19e625161dbee151413cb552f6a
 
Global response time for [/service.txt] =13105

Je vous avais dit que j’y avais mis un contenu bidon… Le MD5 est tout en bas. C’est cette chaîne de caractère que vous placez dans le fichier de configuration de Keepalived.

Ensuite, je demande à Keepalived d’effectuer son test sur le port 80 de ma machine réelle grâce à l’option port. connect_timeout le temps de réponse maximum dont dispose le serveur réel pour répondre, nb_get_retry le nombre de tentatives et delay_before_retry le délai entre chaque tentative. Notez que j’ai mis des valeurs particulièrement basses… À adapter à votre configuration 🙂

À noter que si vous souhaitez que Keepalived envoie une requête sur une page en HTTPS, vous disposez du test SSL_GET reprenant la même syntaxe.

Démonstration

Je vous l’avais montré dans une précédente vidéo, vous pouvez surveiller l’activité de la répartition de charge avec la commande ipvsadm -Ln.

On voit bien ici que la répartition fonctionne...

On voit bien ici que la répartition fonctionne…

L’animation suivante combine watch et wget pour tester la répartition (2 requêtes / seconde). Je vais couper le serveur réel n°1 et voir si je continue d’être redirigé vers celui-ci.

C'est plutôt concluant !

C’est plutôt concluant !

Si on jette un œil à Syslog sur le directeur, on se rend compte que Keepalived a bien fonctionné !

Syslog Failover LVS

Et qu’il ne redirige le trafic que sur la machine en bonne santé :

Monitoring failover LVS

Et enfin, si je remets en marche la machine tombée en panne, Keepalived la replace correctement 🙂

Syslog Enabling Server LVS

Pour conclure

Voici donc quelques pistes pour la configuration de Keepalived. Sachez que son manuel est très bien documenté et qu’il existe d’autres tests possibles alors n’hésitez pas à fouiller ou poser vos questions dans les commentaires !

Cet article vous a plu ? Partagez-le sur les réseaux sociaux !

Twitter Facebook Google Plus email