tag:linuxfr.org,2005:/tags/r%C3%A9partiteur/publicLinuxFr.org : les contenus étiquetés avec « répartiteur »2017-11-04T14:09:42+01:00/favicon.pngtag:linuxfr.org,2005:Post/384972017-09-20T22:46:43+02:002017-11-04T13:35:11+01:00[Tuto/HowTo] [Ubuntu/Debian] Load Balancing - redirection vers plusieurs vhost avec HaProxy<h2 class="sommaire">Sommaire</h2>
<ul class="toc">
<li><a href="#mise-en-place-haproxy-load-balancing">Mise en place HaProxy (load balancing)</a></li>
<li>
<a href="#configurer-apache2">Configurer apache2</a><ul>
<li><a href="#obligatoire">Obligatoire</a></li>
<li>
<a href="#optionnel">Optionnel</a><ul>
<li><a href="#supprimer-les-checks-de-haproxy-des-fichiers-logs-dapache2">Supprimer les checks de HaProxy des fichiers logs d'apache2</a></li>
</ul>
</li>
</ul>
</li>
<li>
<a href="#bonus">Bonus</a><ul>
<li>
<a href="#transmettre-les-ip-des-clients-de-haproxy-frontend-vers-apache2-backend">Transmettre les IP des clients de HaProxy (frontend) vers apache2 (backend)</a><ul>
<li><a href="#pr%C3%A9ambule">Préambule</a></li>
<li><a href="#c%C3%B4t%C3%A9-haproxy">Côté HaProxy</a></li>
<li><a href="#c%C3%B4t%C3%A9-apache2">Côté Apache2</a></li>
</ul>
</li>
<li><a href="#activer-les-statistiques-de-haproxy">Activer les statistiques de HaProxy</a></li>
</ul>
</li>
<li><a href="#farm-link">Farm Link</a></li>
</ul><p>musique d'ambiance : <a href="https://www.youtube.com/watch?v=IOMPquxgMCo">Les Choristes - Vois Sur Ton Chemin (Paraphonics Remix)</a> <a href="https://www.youtube.com/watch?v=yCIOlZgV_ZA">LES RAMONEURS DE MENHIRS - Dans An Diaoul</a><br>
Testé avec succès sur : Ubuntu Minimal 16.04 (ARM)<br>
Difficulté : moyen</p>
<p><img src="//img.linuxfr.org/img/68747470733a2f2f6672616d617069632e6f72672f6466326642514270734f45632f773977537933764c693473302e706e67/w9wSy3vLi4s0.png" alt="image schema repartiteur de charge HaProxy + serveur web" title="Source : https://framapic.org/df2fBQBpsOEc/w9wSy3vLi4s0.png"></p>
<h2 id="mise-en-place-haproxy-load-balancing">Mise en place HaProxy (load balancing)</h2>
<p><strong>Installez les pré-requis</strong></p>
<pre><code>apt-get update
apt-get install -y haproxy
</code></pre>
<p><strong>Activez HaProxy</strong></p>
<pre><code>sed -i "s/ENABLED=0/ENABLED=1/g" /etc/default/haproxy
sed -i "s/ENABLED=0/ENABLED=1/g" /etc/init.d/haproxy
</code></pre>
<p><strong>Créez le dossier qui va accueillir les certificats TLS (exSSL)</strong></p>
<pre><code>mkdir -p /etc/haproxy/certs/
</code></pre>
<p><strong>Concaténez chaque certificat (clés publique) et sa clés privé (recommencez pour chaque certificat)</strong></p>
<pre><code>DOMAIN='cloud.linuxfr.org' sudo -E bash -c 'cat /etc/letsencrypt/live/$DOMAIN/fullchain.pem /etc/letsencrypt/live/$DOMAIN/privkey.pem > /etc/haproxy/certs/$DOMAIN.pem'
</code></pre>
<ul>
<li>
<strong><em>DOMAIN='cloud.linuxfr.org'</em></strong> => remplacez par votre nom de domaine</li>
<li>
<strong><em>/etc/letsencrypt/live/</em></strong> => le chemin d'accès (<a href="https://fr.wikipedia.org/wiki/Chemin_d%27acc%C3%A8s">PATH</a>) vers vos fichiers, ici c'est le dossier par défaut de Let's Encrypt.
<ul>
<li>
<strong>Note :</strong> pas la peine de concaténer tout vos certificats/clés privé dans un seul gros fichiers, cela ne fonctionne pas.</li>
</ul>
</li>
</ul><p><strong>Éditez <em>/etc/haproxy/haproxy.cfg</em></strong></p>
<pre><code>sudo nano /etc/haproxy/haproxy.cfg
</code></pre>
<p><strong>Ajoutez la partie traitant de l'écoute (frontend)</strong><br><strong>Note :</strong> dans cet exemple on défini deux noms de domaines (cloud.linuxfr.org et forum.linuxfr.org) </p>
<pre><code>frontend https
bind *:80
bind *:443 ssl crt /etc/haproxy/certs/cloud.linuxfr.org.pem crt /etc/haproxy/certs/forum.linuxfr.org.pem
mode http
option httpclose
option forwardfor
reqadd X-Forwarded-Proto:\ https
# gestion des logs
log /dev/log local0 info
http-request add-header X-CLIENT-IP %[src]
#on force https (pas obligatoire)
acl http ssl_fc,not
http-request redirect scheme https if http
# si le visiteurs tentent de joindre depuis un hostname inconnu, on renvoie vers cette config serveur
default_backend serveur_web
# On défini les hostnames
acl host_cloud.linuxfr.org hdr(host) -i cloud.linuxfr.org
acl host_forum.linuxfr.org hdr(host) -i forum.linuxfr.org
## On associe quelle config serveur (backend) va avec quel hostname
use_backend serveur_cloud if host_cloud.linuxfr.org
use_backend serveur_web if host_forum.linuxfr.org
</code></pre>
<ul>
<li>
<em><strong>frontend https</strong></em> => On défini le bloc de configuration frontend. Format <em>frontend nomUnique</em>.</li>
<li>
<strong><em>bind *:80</em></strong> => on écoute sur le port 80 (utile ici afin de rediriger vers https)</li>
<li>
<strong><em>bind *:443 ssl crt /etc/haproxy/certs/cloud.linuxfr.org.pem crt /etc/haproxy/certs/forum.linuxfr.org.pem</em></strong> => on écoute sur le port 443 et on lui associe deux certificats</li>
<li>
<strong><em>default_backend serveur_web</em></strong> => on défini "<em>serveur_web</em>" comme config backend par défaut (en cas de visite via un hostname inconnu)</li>
<li>
<strong><em>acl host_cloud.linuxfr.org hdr(host) -i cloud.linuxfr.org</em></strong> => on défini nos hostnames et l'identifiant qui y est lié. format acl nomUnique hdr(host) -i <a href="http://www.monHostname.com">www.monHostname.com</a>
</li>
<li>
<strong><em>use_backend serveur_cloud if host_cloud.linuxfr.org</em></strong> => on défini quelle config serveur est associé à l'identifiant unique créé précédemment.</li>
</ul><p><strong>Ajoutez la partie traitant des différents serveurs (backend)</strong><br><strong>Note :</strong> dans cet exemple on défini les serveurs pour les deux noms de domaines. </p>
<pre><code>backend serveur_cloud
mode http
balance leastconn
option forwardfor
option httpchk HEAD /haproxytest.txt HTTP/1.0
cookie SERVERID insert indirect nocache
server serveurCloud serveurCloud:80 check cookie serveurCloud
backend serveur_web
mode http
balance roundrobin
option forwardfor
option httpchk HEAD /haproxytest.txt HTTP/1.0
cookie SERVERID insert indirect nocache
server superRaspberry superRaspberry:443 check cookie superRaspberry ssl verify none
</code></pre>
<ul>
<li>
<strong><em>backend serveur_web</em></strong> => On défini le bloc de configuration backend. Format backend nomUnique.</li>
<li>
<strong><em>mode http</em></strong> => écoute en http</li>
<li>
<strong><em>balance leastconn</em></strong> => on défini quel algorithme de sélection des serveurs à utiliser. Accepte : roundrobin , leastconn, source. (<a href="https://www.digitalocean.com/community/tutorials/an-introduction-to-haproxy-and-load-balancing-concepts">infos</a>)</li>
<li>
<strong><em>option forwardfor</em></strong> => on active la transmission des IPs des clients via l'header HTTP "<a href="https://en.wikipedia.org/wiki/X-Forwarded-For">X-Forwarded-For</a>"</li>
<li>
<strong><em>option httpchk HEAD /haproxytest.txt HTTP/1.0</em></strong> => on défini un fichier sur les serveurs backend, HaProxy vérifiera l'existence de ce fichier sur chaque serveur toutes les deux secondes. Si le fichier n'est pas présent sur un serveur, HaProxy * considérera ce serveur comme inactif. Pour les applications PHP et les CMS, je vous conseil fortement de pointer le fichier <em>index.php</em>.</li>
<li>
<strong><em>cookie SERVERID insert indirect nocache</em></strong> => option concernant les cookies</li>
<li>
<strong><em>server superRaspberry superRaspberry:443 check cookie superRaspberry ssl verify none</em></strong> => Une ligne par serveur. <em><strong>server superRaspberry superRaspberry:443</strong></em> on défini notre serveur (son nom puis sont hostname:port). <strong><em>check</em></strong> signifie qu'il faut tester l'existence du fichier de test (haproxytest.txt), <strong><em>cookie superRaspberry</em></strong> qu'il faut transférer les cookies valide pour <em>superRaspberry</em> et <strong><em>ssl verify none</em></strong> qu'il ne faut pas vérifier le certificat TLS du serveur backend.</li>
</ul><h2 id="configurer-apache2">Configurer apache2</h2>
<p><strong>Note :</strong> n'oubliez pas de redémarrer apache2 après avoir apporté une ou plusieurs modifications</p>
<h3 id="obligatoire">Obligatoire</h3>
<p><strong>Créer le fichier vide sur tout vos serveurs apache2, il va servir à HaProxy pour vérifier la disponibilité des serveurs.</strong></p>
<pre><code>touch /var/www/html/haproxytest.txt
</code></pre>
<ul>
<li>Adaptez éventuellement le <a href="https://fr.wikipedia.org/wiki/Chemin_d%27acc%C3%A8s">PATH</a> à votre configuration. Vous pouvez tout à fait vérifier l'existence d'un autre fichier (par exemple index.html, robot.txt, etc). Sachez toute fois que plus ce fichiers est gros et plus sa vérification va consommer de ressources/électricité.</li>
</ul><h3 id="optionnel">Optionnel</h3>
<h4 id="supprimer-les-checks-de-haproxy-des-fichiers-logs-dapache2">Supprimer les checks de HaProxy des fichiers logs d'apache2</h4>
<p><strong>Éditez votre fichier vhost (<em>/etc/apache2/sites-available/</em>) Et ajoutez les lignes suivantes en adaptant éventuellement le <a href="https://fr.wikipedia.org/wiki/Chemin_d%27acc%C3%A8s">PATH</a> des fichiers logs à votre config</strong></p>
<pre><code>SetEnvIf Request_URI haproxytest.txt dontlog
#SetEnvIf Remote_Addr "10\.8\.0\.1" dontlog # si vous voulez aussi ban une ip
CustomLog /var/log/apache2/access.log combined env=!dontlog
</code></pre>
<ul>
<li>Il va de soit que si votre HaProxy check un autre fichier que <em><strong>haproxytest.txt</strong></em> vous devez le mentionner.</li>
</ul><h2 id="bonus">Bonus</h2>
<h3 id="transmettre-les-ip-des-clients-de-haproxy-frontend-vers-apache2-backend">Transmettre les IP des clients de HaProxy (frontend) vers apache2 (backend)</h3>
<h4 id="préambule">Préambule</h4>
<p>Avec ça les fichiers logs d'apache2 retrouvent une tronche normale mais par contre <a href="http://php.net/manual/fr/reserved.variables.server.php">$_SERVER[’REMOTE_ADDR’]</a> continue de renvoyer l'IP du frontend. Pour récupérer l'IP du client vous devez passer par <em>$_SERVER["HTTP_X_FORWARDED_FOR"]</em>.<br>
Toutes ces commandes sont à exécuter en admin (root).</p>
<h4 id="côté-haproxy">Côté HaProxy</h4>
<p><strong>Éditez le fichier de configuration de HaProxy</strong></p>
<pre><code>nano /etc/haproxy/haproxy.cfg
</code></pre>
<p><strong>Ajoutez <em>option forwardfor</em> dans les blocs de commandes dédié au frontend et au backend</strong></p>
<h4 id="côté-apache2">Côté Apache2</h4>
<p><strong>Lancez les commandes suivantes</strong></p>
<pre><code>apt-get install libapache2-mod-rpaf
a2enmod rpaf
nano /etc/apache2/mods-enabled/rpaf.conf
</code></pre>
<p><strong>Collez les lignes suivantes</strong></p>
<pre><code></IfModule rpaf_module>
RPAFenable On
RPAFsethostname On
# list your proxies IP address below
RPAFproxy_ips 10.0.0.1 10.0.0.2
RPAFheader X-Real-IP
</IfModule>
</code></pre>
<ul>
<li>
<strong><em>RPAFproxy_ips 10.0.0.1 10.0.0.2</em></strong> => adaptez cette ligne pour indiquer la ou les IP de vos frontends</li>
</ul><p><strong><em>CTRL+X</em> pour sauver et quitter</strong></p>
<p><strong>Redémarrez le serveur web</strong></p>
<pre><code>service apache2 restart
</code></pre>
<h3 id="activer-les-statistiques-de-haproxy">Activer les statistiques de HaProxy</h3>
<p><strong>Adaptez puis ajoutez les lignes suivantes dans <em>/etc/haproxy/haproxy.cfg</em></strong></p>
<pre><code>
listen stats
bind *:1936
mode http
stats enable
stats uri /
stats hide-version
stats auth login:password
</code></pre>
<ul>
<li>
<em><strong>bind *:1936</strong></em> => le port sur lequel écouter pour joindre la WEBUI des statistiques de HaProxy</li>
<li>
<em><strong>stats auth login:password</strong></em> => le couple login et password. Une ligne par couple login:password, vous pouvez ajouter autant de ligne que vous le souhaitez.</li>
</ul><h2 id="farm-link">Farm Link</h2>
<ul>
<li>
<a href="https://www.0rion.netlib.re/forum4/viewtopic.php?f=79&t=684">[Tuto/HowTo] [GNU/Linux] Load Balancing - redirection vers plusieurs vhost avec HaProxy</a> (tutoriel d'origine)</li>
<li><a href="https://www.digitalocean.com/community/tutorials/how-to-use-haproxy-to-set-up-http-load-balancing-on-an-ubuntu-vps">How To Use HAProxy to Set Up HTTP Load Balancing on an Ubuntu VPS</a></li>
<li><a href="https://webdevwonders.com/haproxy-load-balancer-setup-including-logging-on-debian/">HAProxy Load Balancer setup including logging on Debian</a></li>
<li><a href="https://www.0rion.netlib.re/forum4/viewtopic.php?f=68&t=663&p=1530#p1527">[Tuto/HowTo] [GNU/Linux] Installation d'un répartiteur de charge HaProxy pour Galera Cluster</a></li>
</ul><div><a href="https://linuxfr.org/forums/linux-general/posts/tuto-howto-ubuntu-debian-load-balancing-redirection-vers-plusieurs-vhost-avec-haproxy.epub">Télécharger ce contenu au format EPUB</a></div> <p>
<strong>Commentaires :</strong>
<a href="//linuxfr.org/nodes/112707/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/forums/linux-general/posts/tuto-howto-ubuntu-debian-load-balancing-redirection-vers-plusieurs-vhost-avec-haproxy#comments">ouvrir dans le navigateur</a>
</p>
TutoMakerhttps://linuxfr.org/nodes/112707/comments.atomtag:linuxfr.org,2005:News/355052014-08-26T17:01:24+02:002014-08-31T13:43:18+02:00HAProxy 1.5Licence CC By‑SA http://creativecommons.org/licenses/by-sa/4.0/deed.fr<div><p>Après quatre ans et trois mois, et pas moins de 26 versions de développement, la version réputée stable de HAProxy devient la 1.5. Même si HAProxy est avant tout un <a href="https://fr.wikipedia.org/wiki/r%C3%A9partiteur%20de%20charge" title="Définition Wikipédia">répartiteur de charge</a> HTTP et TCP, les possibilités offertes par la version 1.5 en font le véritable couteau suisse du Web à haute charge.</p>
<p><img src="//img.linuxfr.org/img/687474703a2f2f7777772e686170726f78792e6f72672f696d672f6c6f676f2d6d65642e706e67/logo-med.png" alt="HAProxy" title="Source : http://www.haproxy.org/img/logo-med.png"></p>
<p>Il est utilisé, entre autres, par de <a href="http://www.haproxy.org/they-use-it.html">nombreux sites d’audience mondiale</a>, tels que Twitter, Instagram, GitHub, Reddit… Cette version apporte de nombreuses nouveautés, dont la très attendue prise en charge de l’<a href="http://en.wikipedia.org/wiki/SSL_acceleration"><em>offloading SSL</em></a>.</p>
<p>La version 1.5.0 a été rapidement suivie de quelques versions correctives. Nous en sommes à la 1.5.3, disponible depuis le 25 juillet dernier.</p></div><ul><li>lien nᵒ 1 : <a title="http://www.haproxy.org/" hreflang="en" href="https://linuxfr.org/redirect/90940">Site officiel</a></li><li>lien nᵒ 2 : <a title="http://www.haproxy.org/download/1.5/src/CHANGELOG" hreflang="en" href="https://linuxfr.org/redirect/90941">Changements</a></li><li>lien nᵒ 3 : <a title="http://git.haproxy.org/?p=haproxy-1.5.git" hreflang="en" href="https://linuxfr.org/redirect/90942">Dépot Git</a></li><li>lien nᵒ 4 : <a title="http://cbonte.github.io/haproxy-dconv/configuration-1.5.html" hreflang="en" href="https://linuxfr.org/redirect/90943">Guide de configuration</a></li></ul><div><h2 class="sommaire">Sommaire</h2>
<ul class="toc">
<li>
<a href="#listes-des-nouveaut%C3%A9s">Listes des nouveautés</a><ul>
<li><a href="#inspection-du-contenu">Inspection du contenu</a></li>
<li><a href="#prise-en-charge-du-chiffrement-ssl-">Prise en charge du chiffrement (SSL) </a></li>
<li><a href="#gestion-%C3%A9tendue-de-lipv6-et-des-sockets-unix">Gestion étendue de l’IPv6 et des sockets UNIX</a></li>
<li><a href="#http-keepalive-de-bout-en-bout">HTTP keep‐alive de bout en bout</a></li>
<li><a href="#compression-des-r%C3%A9ponses-http">Compression des réponses HTTP</a></li>
<li><a href="#am%C3%A9lioration-des-acl">Amélioration des ACL</a></li>
<li><a href="#les-maps">Les maps</a></li>
<li><a href="#compteurs-dactivit%C3%A9-et-tables">Compteurs d’activité et tables</a></li>
<li><a href="#v%C3%A9rification-de-la-sant%C3%A9-des-serveurs-am%C3%A9lior%C3%A9e">Vérification de la santé des serveurs améliorée</a></li>
<li><a href="#version-2-du-proxy-protocol">Version 2 du proxy protocol</a></li>
<li><a href="#prise-en-charge-de-systemd">Prise en charge de systemd</a></li>
</ul>
</li>
<li><a href="#nouveau-cycle-de-d%C3%A9veloppement">Nouveau cycle de développement</a></li>
<li>
<a href="#exemple-dutilisation">Exemple d’utilisation</a><ul>
<li><a href="#param%C3%A8tres-globaux">Paramètres globaux</a></li>
<li><a href="#param%C3%A8tres-par-d%C3%A9faut">Paramètres par défaut</a></li>
<li><a href="#le-proxymandataire">Le proxy/mandataire</a></li>
<li><a href="#savoir-ce-quil-se-passe">Savoir ce qu’il se passe</a></li>
<li><a href="#routage-plus-complexe">Routage plus complexe</a></li>
<li><a href="#coller-au-serveur-et-g%C3%A9rer-les-pannes">Coller au serveur et gérer les pannes</a></li>
<li><a href="#et-ainsi-de-suite">Et ainsi de suite</a></li>
</ul>
</li>
</ul><h2 id="listes-des-nouveautés">Listes des nouveautés</h2>
<h3 id="inspection-du-contenu">Inspection du contenu</h3>
<p>HAProxy 1.5 sait désormais capturer n’importe quelle partie d’une requête ou d’une réponse, y compris le contenu (<em>payload</em>) et les arguments passés dans l’URL (<code>url_param</code>). Cette fonctionnalité est essentielle car elle est à la base de beaucoup d’autres nouveautés.</p>
<p>Pour l’administrateur système, le bénéfice est énorme : il peut désormais intervenir à n’importe quel moment de la transaction.</p>
<h3 id="prise-en-charge-du-chiffrement-ssl-">Prise en charge du chiffrement (SSL) </h3>
<p>Jusqu’à présent, pour utiliser du chiffrement TLS avec HAProxy, il fallait soit utiliser le mode TCP, soit utiliser une version modifiée de <a href="https://www.stunnel.org/index.html">STunnel</a>. Désormais, HAProxy prend en charge le chiffrement SSL côté client comme côté serveur.</p>
<pre><code>listen https_proxy
bind :443 ssl crt /etc/haproxy/site.pem
mode http
server web1 10.0.0.1:443 ssl verify check
server web2 10.0.0.2:443 ssl verify check
</code></pre>
<p>Il gère de nombreuses extensions au protocole TLS, telles que <a href="http://fr.wikipedia.org/wiki/Server_Name_Indication">SNI</a>, <a href="http://en.wikipedia.org/wiki/Next_Protocol_Negotiation">NPN/ALPN</a> et <a href="https://fr.wikipedia.org/wiki/OCSP" title="Définition Wikipédia">OCSP</a>, la validation des certificats côté serveur, les certificats clients.</p>
<pre><code>bind 192.168.10.1:443 ssl crt ./server.pem ca-file ./ca.crt verify required
</code></pre>
<h3 id="gestion-étendue-de-lipv6-et-des-sockets-unix">Gestion étendue de l’IPv6 et des sockets UNIX</h3>
<p>Il est désormais possible d’utiliser indifféremment l’IPv4, l’IPv6 ou encore les <em>sockets</em> UNIX, côté client comme côté serveur.</p>
<pre><code>listen mysql_proxy
bind /var/tmp/mysql.sock user mysql mode 666
mode tcp
option mysql-check user haproxy post-41
server mysql 192.168.10.100:3306 check maxconn 200
server mysql_slave fe80:482:cafe::a200:e8ff:fe65:a:3306 check backup
</code></pre>
<h3 id="http-keepalive-de-bout-en-bout">HTTP keep‐alive de bout en bout</h3>
<p>Le <em>keep‐alive</em> consiste à faire passer successivement plusieurs requêtes HTTP dans la même requête TCP. En général, dans une architecture Web un peu complète, on dispose de plusieurs services ayant des rôles particuliers. Par exemple, un service d’authentification, un service pour les contenus dynamiques, un autre pour les ressources statiques, etc. HAProxy doit alors inspecter chaque requête pour déterminer vers quel service l’envoyer. Jusqu’à présent, le <em>keep‐alive</em> de bout en bout n’autorisait que l’inspection de la première requête. Et l’administrateur passait des heures à se demander pourquoi telle requête n’arrivait pas au bon endroit.</p>
<p>C’est pourquoi l’option <code>http-server-close</code>, permettant du <em>keep‐alive</em> côté client uniquement, était souvent utilisée.</p>
<p>Ce problème est désormais résolu. </p>
<p>Outre l’<em>overhead</em> réseau, le <em>keep‐alive</em> côté serveur est important car certains serveurs Web n’utilisent pas de <em>chunk</em> si celui‐ci est désactivé (ce problème est toutefois géré par l’option <code>http-pretend-keepalive</code>).</p>
<h3 id="compression-des-réponses-http">Compression des réponses HTTP</h3>
<p>Il est désormais possible d’utiliser HAProxy pour la compression des réponses HTTP. Les algorithmes <a href="http://fr.wikipedia.org/wiki/Gzip"><em>gzip</em></a> et <a href="http://fr.wikipedia.org/wiki/Deflate"><em>deflate</em></a> sont pris en charge. Elle peut être activée globalement ou localement.</p>
<pre><code>compression gzip
compression type text/html text/plain
</code></pre>
<p>HAProxy gère toute une série de cas pour lesquels la compression n’est pas pertinente, notamment les réponses déjà compressées. Toutefois, il est possible, via l’option <code>compression offload</code>, de demander aux serveurs de ne jamais compresser. Dans ce cas, l’entête <code>Accept-Encoding</code> est réécrit à la volée.</p>
<h3 id="amélioration-des-acl">Amélioration des ACL</h3>
<p>Une conséquence directe de l’amélioration des possibilités de capture est qu’il est désormais possible de créer des listes de contrôle d’accès (ACL) sur l’ensemble des données capturables.</p>
<pre><code>acl hello payload(0,6) -m bin 48656c6c6f0a
</code></pre>
<p>Il est également possible d’utiliser des variables :</p>
<pre><code>http-request redirect code 301 location www.%[hdr(host)]%[req.uri] \
unless { hdr_beg(host) -i www }
</code></pre>
<h3 id="les-maps">Les maps</h3>
<p>On pouvait déjà passer à HAProxy un fichier contenant une série de valeurs (par exemple une liste d’IP à autoriser). Il est désormais possible d’utiliser des fichiers clés‐valeurs avec les mots clés <code>map_*</code>.</p>
<p>Par exemple, pour faire de la géolocalisation, il fallait jusqu’à présent écrire une série d’ACL :</p>
<pre><code>acl src A1 -f A1.subnets
acl src A2 -f A2.subnets
acl src AD -f AD.subnets
acl src AE -f AE.subnets
acl src AF -f AF.subnets
acl src AG -f AG.subnets
acl src AI -f AI.subnets
acl src AL -f AL.subnets
acl src AM -f AM.subnets
acl src AN -f AN.subnets
</code></pre>
<p>ACL pour lesquelles chaque fichier contenait l’ensemble des sous‐réseaux d’un pays. Désormais, il est possible de faire un seul fichier sous la forme <em>range pays</em> :</p>
<pre><code>223.228.0.0/14 IN
223.232.0.0/13 IN
223.240.0.0/13 CN
223.248.0.0/14 CN
223.252.0.0/17 AU
223.252.128.0/19 CN
223.252.160.0/24 CN
223.252.161.0/26 CN
223.252.161.64/26 HK
223.252.161.128/25 CN
223.252.162.0/23 CN
223.252.164.0/22 CN
223.252.168.0/21 CN
223.252.176.0/20 CN
223.252.192.0/18 CN
</code></pre>
<p>Puis, il suffit d’écrire :</p>
<pre><code>http-request set-header X-Country %[src,map_ip(geoip.lst)]
</code></pre>
<h3 id="compteurs-dactivité-et-tables">Compteurs d’activité et tables</h3>
<p>Il est désormais possible d’utiliser des tables pour comptabiliser l’activité d’un client pour des besoins aussi divers que de se souvenir d’une décision de routage ou bannir les indélicats.</p>
<p>Par exemple, pour éviter qu’un serveur se fasse bombarder de requêtes toujours identiques (<em>brute force</em>, <em>spam</em>) :</p>
<pre><code class="bash"><span class="c"># Si on a une requête POST, on stocke dans la table un hash créé à partir de l'IP source et de l'url</span>
stick-table <span class="nb">type </span>binary len <span class="m">20</span> size 5m expire 1h store http_req_rate<span class="o">(</span>10s<span class="o">)</span>
tcp-request content track-sc1 base32+src <span class="k">if</span> METH_POST
<span class="c"># Si on a un ratio supérieur à 10 requêtes en 10 secondes alors on bannit le client</span>
acl bruteforce_detection sc1_http_req_rate gt 10
http-request deny <span class="k">if</span> bruteforce_detection</code></pre>
<p>Ces tables peuvent être contrôlées et vidées par le <em>socket</em> de contrôle :</p>
<pre><code class="bash"><span class="nb">echo </span>show table <span class="p">|</span>nc -U /tmp/haproxy.sock
<span class="c"># table: monserveur, type: binary, size:5242880, used:468</span>
<span class="nb">echo </span>show table monserveur <span class="p">|</span>nc -U /tmp/haproxy.sock <span class="p">|</span>tail
0x8019d9f4c: <span class="nv">key</span><span class="o">=</span>FD0D68C950F7E432000000000000000000000000 <span class="nv">use</span><span class="o">=</span><span class="m">0</span> <span class="nv">exp</span><span class="o">=</span><span class="m">2956851</span> http_req_rate<span class="o">(</span>10000<span class="o">)=</span>0
0x8017f8e0c: <span class="nv">key</span><span class="o">=</span>FD19C86D50F7E432000000000000000000000000 <span class="nv">use</span><span class="o">=</span><span class="m">0</span> <span class="nv">exp</span><span class="o">=</span><span class="m">2206531</span> http_req_rate<span class="o">(</span>10000<span class="o">)=</span>0
0x8019d970c: <span class="nv">key</span><span class="o">=</span>FE3651B30209AF8C000000000000000000000000 <span class="nv">use</span><span class="o">=</span><span class="m">0</span> <span class="nv">exp</span><span class="o">=</span><span class="m">820386</span> http_req_rate<span class="o">(</span>10000<span class="o">)=</span>0
0x801bcbccc: <span class="nv">key</span><span class="o">=</span>FE3651B356D4F7D1000000000000000000000000 <span class="nv">use</span><span class="o">=</span><span class="m">0</span> <span class="nv">exp</span><span class="o">=</span><span class="m">2985182</span> http_req_rate<span class="o">(</span>10000<span class="o">)=</span>0
0x8017fed4c: <span class="nv">key</span><span class="o">=</span>FE3651B35A08E3FA000000000000000000000000 <span class="nv">use</span><span class="o">=</span><span class="m">0</span> <span class="nv">exp</span><span class="o">=</span><span class="m">1701016</span> http_req_rate<span class="o">(</span>10000<span class="o">)=</span>0
0x801be15cc: <span class="nv">key</span><span class="o">=</span>FE3651B36DDCDC20000000000000000000000000 <span class="nv">use</span><span class="o">=</span><span class="m">0</span> <span class="nv">exp</span><span class="o">=</span><span class="m">363622</span> http_req_rate<span class="o">(</span>10000<span class="o">)=</span>0
0x801bfba8c: <span class="nv">key</span><span class="o">=</span>FE3651B3973CC657000000000000000000000000 <span class="nv">use</span><span class="o">=</span><span class="m">0</span> <span class="nv">exp</span><span class="o">=</span><span class="m">1302278</span> http_req_rate<span class="o">(</span>10000<span class="o">)=</span>0
0x8017f8ecc: <span class="nv">key</span><span class="o">=</span>FEE742DC8D6942B3000000000000000000000000 <span class="nv">use</span><span class="o">=</span><span class="m">0</span> <span class="nv">exp</span><span class="o">=</span><span class="m">693453</span> http_req_rate<span class="o">(</span>10000<span class="o">)=</span>0
0x801bdff4c: <span class="nv">key</span><span class="o">=</span>FEE742DC9200499B000000000000000000000000 <span class="nv">use</span><span class="o">=</span><span class="m">0</span> <span class="nv">exp</span><span class="o">=</span><span class="m">3415931</span> http_req_rate<span class="o">(</span>10000<span class="o">)=</span>0
<span class="nb">echo </span>clear table monserveur <span class="p">|</span>nc -U /tmp/haproxy.sock
<span class="nb">echo </span>show table <span class="p">|</span>nc -U /tmp/haproxy.sock
sock
<span class="c"># table: monserveur, type: binary, size:5242880, used:1</span></code></pre>
<h3 id="vérification-de-la-santé-des-serveurs-améliorée">Vérification de la santé des serveurs améliorée</h3>
<p>Pour prendre des décisions de routage des requêtes, il est important de savoir quels serveurs sont en bonne santé. Outre les <em>checks</em> HTTP, largement paramétrables, HAProxy dispose en natif de tests de vie pour les protocoles <code>mysql</code>, <code>pgsql</code>, <code>redis</code>, <code>ssl</code> et <code>smtp</code>. Il est toutefois désormais possible d’écrire des tests de vie personnalisés. Voici un exemple utilisant <a href="http://blog.haproxy.com/2014/06/06/binary-health-check-with-haproxy-1-5-php-fpmfastcgi-probe-example/"><code>php-fpm</code></a> :</p>
<pre><code class="bash">option tcp-check
<span class="c"># FCGI_BEGIN_REQUEST</span>
tcp-check send-binary <span class="m">01</span> <span class="c"># version</span>
tcp-check send-binary <span class="m">01</span> <span class="c"># FCGI_BEGIN_REQUEST</span>
tcp-check send-binary <span class="m">0001</span> <span class="c"># request id</span>
tcp-check send-binary <span class="m">0008</span> <span class="c"># content length</span>
tcp-check send-binary <span class="m">00</span> <span class="c"># padding length</span>
tcp-check send-binary <span class="m">00</span> <span class="c">#</span>
tcp-check send-binary <span class="m">0001</span> <span class="c"># FCGI responder</span>
tcp-check send-binary <span class="m">0000</span> <span class="c"># flags</span>
tcp-check send-binary <span class="m">0000</span> <span class="c">#</span>
tcp-check send-binary <span class="m">0000</span> <span class="c">#</span>
<span class="c"># FCGI_PARAMS</span>
tcp-check send-binary <span class="m">01</span> <span class="c"># version</span>
tcp-check send-binary <span class="m">04</span> <span class="c"># FCGI_PARAMS</span>
tcp-check send-binary <span class="m">0001</span> <span class="c"># request id</span>
tcp-check send-binary <span class="m">0045</span> <span class="c"># content length</span>
tcp-check send-binary <span class="m">03</span> <span class="c"># padding length: padding for content % 8 = 0</span>
tcp-check send-binary <span class="m">00</span> <span class="c">#</span>
tcp-check send-binary 0e03524551554553545f4d4554484f44474554 <span class="c"># REQUEST_METHOD = GET</span>
tcp-check send-binary 0b055343524950545f4e414d452f70696e67 <span class="c"># SCRIPT_NAME = /ping</span>
tcp-check send-binary 0f055343524950545f46494c454e414d452f70696e67 <span class="c"># SCRIPT_FILENAME = /ping</span>
tcp-check send-binary 040455534552524F4F54 <span class="c"># USER = ROOT</span>
tcp-check send-binary <span class="m">000000</span> <span class="c"># padding</span>
<span class="c"># FCGI_PARAMS</span>
tcp-check send-binary <span class="m">01</span> <span class="c"># version</span>
tcp-check send-binary <span class="m">04</span> <span class="c"># FCGI_PARAMS</span>
tcp-check send-binary <span class="m">0001</span> <span class="c"># request id</span>
tcp-check send-binary <span class="m">0000</span> <span class="c"># content length</span>
tcp-check send-binary <span class="m">00</span> <span class="c"># padding length: padding for content % 8 = 0</span>
tcp-check send-binary <span class="m">00</span> <span class="c">#</span>
tcp-check expect binary 706f6e67 <span class="c"># pong</span></code></pre>
<p>Par ailleurs, les vérifications peuvent être déléguées à un agent externe. Cela permet de configurer dynamiquement le poids du serveur dans le <em>pool</em>.</p>
<p>L’agent doit retourner soit une valeur entre 0 % et 100 % représentant le poids relatif au poids initialement donné au serveur, soit un mot clé <em>ready</em> (prêt), <em>drain</em> (n’accepte plus de nouvelles connexions mais traite celles en cours), <em>maint</em> (passe en maintenance), <em>down</em>, <em>up</em>… Pour mettre cela en place, il faut utiliser le mot clé <em>agent-check</em>.</p>
<p>Typiquement, cela peut être un script lancé par <code>inetd</code>. Par exemple, pour adapter le poids du serveur en fonction de la charge :</p>
<pre><code class="bash"><span class="c">#!/bin/sh</span>
<span class="nv">SYSCTL</span><span class="o">=</span><span class="s2">"/sbin/sysctl -n"</span>
<span class="nv">NCPU</span><span class="o">=</span><span class="k">$(${</span><span class="nv">SYSCTL</span><span class="k">}</span> hw.ncpu<span class="k">)</span>
<span class="nv">LOAD</span><span class="o">=</span><span class="k">$(${</span><span class="nv">SYSCTL</span><span class="k">}</span> vm.loadavg <span class="p">|</span> awk <span class="s1">'{print $2}'</span><span class="k">)</span>
<span class="nv">LOAD</span><span class="o">=</span><span class="k">${</span><span class="nv">LOAD</span><span class="p">%.*</span><span class="k">}</span>
<span class="k">if</span> <span class="o">[</span> <span class="k">${</span><span class="nv">LOAD</span><span class="k">}</span> -ge <span class="k">${</span><span class="nv">NCPU</span><span class="k">}</span> <span class="o">]</span><span class="p">;</span> <span class="k">then</span>
<span class="nv">PERCENT</span><span class="o">=</span><span class="s2">"100"</span>
<span class="k">else</span>
<span class="nv">PERCENT</span><span class="o">=</span><span class="k">$((${</span><span class="nv">LOAD</span><span class="k">}</span><span class="o">*</span><span class="m">100</span><span class="o">/</span><span class="k">${</span><span class="nv">NCPU</span><span class="k">}))</span>
<span class="k">fi</span>
<span class="nb">echo</span> <span class="s2">"$PERCENT%"</span></code></pre>
<p>On paramètre ensuite <code>inetd.conf</code> de la façon suivante :</p>
<pre><code>dec-notes stream tcp nowait nobody /usr/local/bin/agent-check
</code></pre>
<p>Enfin, la configuration pour HAProxy est :</p>
<pre><code>server server1 192.168.64.50:3389 weight 100 check agent-check agent-port 3333
</code></pre>
<h3 id="version-2-du-proxy-protocol">Version 2 du proxy protocol</h3>
<p>Le <a href="http://www.haproxy.org/download/1.5/doc/proxy-protocol.txt"><em>proxy protocol</em></a> est un protocole simple qui permet à l’adresse IP d’un client d’être conservée lorsqu’une requête passe de serveurs en serveurs. Si en HTTP, l’en‐tête <code>X-Forwarded-For</code> est largement utilisée à cette fin, il fallait un mécanisme plus universel, utilisable notamment en mode TCP. Initialement, ce protocole a été conçu pour utiliser HAProxy conjointement avec STunnel. Il est désormais pris en charge par Elastic Load Balancing, ExaProxy, Exim, Gunicorn, HAProxy, NGINX, Postfix, stud et stunnel.</p>
<p>La version 2 modifie profondément la nature du protocole, puisqu’on passe d’une version humainement lisible à une version binaire.</p>
<p>Par exemple, avec Postfix, il faudra dans HAProxy utiliser la configuration ci‐après :</p>
<pre><code>mode tcp
option smtpchk
server postfix 127.0.0.1:10024 send-proxy check
</code></pre>
<p>Une configuration Postfix (<code>master.cf</code>) sera aussi nécessaire :</p>
<pre><code>postscreen_upstream_proxy_protocol = haproxy
</code></pre>
<h3 id="prise-en-charge-de-systemd">Prise en charge de systemd</h3>
<p>HAProxy ne peut pas recharger sa configuration. Pour le redémarrer, on doit tuer l’ancien processus et en lancer un nouveau. Toutefois, afin de ne pas fermer les sessions brutalement, il existe l’option <code>-st</code> qui permet au nouveau processus de remplacer l’ancien proprement.</p>
<p>Ce comportement ne convenant pas à <em>systemd</em>, qui ne sait pas remplacer un processus par un autre, l’option <code>-Ds</code> et le démon <code>haproxy-systemd-wrapper</code> permettent désormais de fonctionner avec ce système d’initialisation.</p>
<h2 id="nouveau-cycle-de-développement">Nouveau cycle de développement</h2>
<p>Willy Tarreau explique dans un <a href="http://marc.info/?l=haproxy&m=140630935820775&w=1">long courriel</a> ses plans pour les prochaines versions de HAProxy, ainsi que les leçons à tirer de la version 1.5, dont le développement a été particulièrement long.</p>
<p>Selon lui, il faut arrêter de promettre telle ou telle fonctionnalité pour telle version, et fonctionner en périodes, à la mode Linux. Ainsi le développement de la version 1.6 s’arrêtera en mars 2015, pour une sortie en mai ou juin de la même année.</p>
<p>Il indique toutefois les directions qu’il souhaite prendre :</p>
<ul>
<li>
<p>multi‐processus : meilleure synchronisation des états et des vérifications. Vue l’arrivée de ces <em>monstres de latence</em> que sont SSL et la compression, une architecture gérant la concurrence serait sans doute bénéfique. Il est toutefois exclu d’ajouter des <em>mutex</em> partout dans le code.</p>
<ul>
<li>reconfiguration à chaud : dans les environnements dynamiques, on est souvent contraint de relancer HAProxy. Même si de nombreuses possibilités sont désormais offertes par le <em>socket</em> de contrôle, il serait intéressant d’aller plus loin dans ce sens.</li>
<li>DNS : actuellement HAProxy ne résout les noms d’hôte qu’au démarrage. Il serait intéressant, en particulier pour les utilisateurs de EC2, que cela puisse être fait dynamiquement.</li>
<li>cache d’objets en mémoire : il ne s’agit pas de concurrencer Varnish, mais d’implémenter un petit cache afin de réduire le trafic entre HAProxy et les serveurs d’origine des objets. Plutôt un cache avec un ratio de <em>hits</em> de 50 % sans maintenance, qu’un cache efficace à 90 % mais demandant beaucoup d’attention.</li>
<li>amélioration de la réutilisation des connexions : dans certains cas, il est particulièrement intéressant de conserver les connexions réseau en vie, même si cela ouvre de nouvelles problématiques comme la supervision des connexions.</li>
<li>HTTP/2 : Willy Tarreau étant particulièrement investi dans le groupe de travail <em>http-bis</em> qui spécifie entre autres HTTP/2, c’est donc sans surprise qu’il place l’implémentation de cette nouvelle version du protocole en tête de ses priorités.</li>
</ul>
</li>
</ul><h2 id="exemple-dutilisation">Exemple d’utilisation</h2>
<p>Imaginons un site Web servi par un parc de serveurs sur lesquels nous voulons mettre en place de l’équilibrage de charge (<em>load balancing</em>) et de la tolérance de panne. Une bonne idée est alors de créer un <em>cluster</em> de HAProxy actif/actif avec au moins deux machines en utilisant le <em>round‐robin</em> DNS et un mécanisme de <em>failover</em> tel que CARP ou <em>keepalived</em>.</p>
<p>Nous allons commencer par une configuration basique à laquelle nous ajouterons peu à peu des fonctionnalités.</p>
<h3 id="paramètres-globaux">Paramètres globaux</h3>
<p>On commence par définir quelques généralités comme les journaux (<em>logs</em>), le maximum de connexions, le comportement du démon. </p>
<pre><code>global
log /var/run/log local0 notice
maxconn 4096
uid 99
gid 99
daemon
chroot /var/empty
</code></pre>
<h3 id="paramètres-par-défaut">Paramètres par défaut</h3>
<p>On ajoute ensuite, une section par défaut qui contiendra l’ensemble des paramètres qui, s’ils ne sont pas surchargés, s’appliqueront à nos <em>proxys</em>/mandataires.</p>
<pre><code class="bash">defaults
<span class="c"># par défaut on logue avec ce qui est défini </span>
<span class="c"># dans la section globale</span>
log global
<span class="c"># on peut définir très finement les différents timeout</span>
<span class="c"># le temps qu'une connexion client peut rester idle</span>
timeout client 40s
<span class="c"># le temps entre une réponse et le début de la requête</span>
<span class="c"># suivante dans une connexion keepalive</span>
timeout http-keep-alive 30s
<span class="c"># Le temps entre le début d'une requête et la fin des entêtes</span>
timeout http-request 10s
<span class="c"># Workaround pour certains navigateurs </span>
<span class="c"># bogués avec le timeout http-request</span>
errorfile <span class="m">408</span> /dev/null
<span class="c"># Le temps durant lequel on attend une réponse du serveur</span>
timeout server 60s
<span class="c"># Le temps qu'une connexion peut rester en attente </span>
<span class="c"># d'un slot disponible</span>
<span class="c"># timeout queue 1500 </span>
<span class="c"># le temps que met un client a établir une connexion tcp</span>
timeout connect 5s
<span class="c"># Combien de fois on réessaye de se connecter à un serveur</span>
retries <span class="m">3</span>
<span class="c"># On redistribue les sessions en cas d'échec de </span>
<span class="c"># connexion avec un serveur</span>
option redispatch
<span class="c"># Par défaut on fait du http</span>
mode http
<span class="c"># Par défaut le mot check signifie check http</span>
option httpchk
<span class="c"># On ajoute l'entête X-Forwarded-Forr</span>
option forwardfor
<span class="c"># On utilise l'algorithme roundrobin</span>
balance roundrobin
<span class="c"># On logue des sessions http</span>
option httplog
<span class="c"># On ne logue pas les connexions sur lesquelles </span>
<span class="c"># il ne se passe rien</span>
option dontlognull
<span class="c"># Aucun proxy ne pourra avoir plus de 2048 connexions ouvertes</span>
<span class="c"># Soit la moitié des connexions acceptables </span>
maxconn 2048</code></pre>
<h3 id="le-proxymandataire">Le proxy/mandataire</h3>
<p>On déclare ensuite notre proxy de la façon la plus simple possible, on ajoutera les fioritures après :</p>
<pre><code class="bash">listen http_proxy
<span class="nb">bind</span> :80
server web1 192.168.42.11:80
server web2 192.168.42.12:80
server web3 192.168.42.13:80</code></pre>
<p>Il est nommé <em>http_proxy</em>, écoute sur le port 80. Il équilibre les connexions suivant l’algorithme <em>round‐robin</em> vers trois serveurs nommés <em>web1</em>, <em>web2</em> et <em>web3</em>. D’autres algorithmes de répartition sont bien évidement disponibles :</p>
<ul>
<li>
<strong><em>static-rr</em></strong> est une variante de <em>round‐robin</em> sans limitation du nombre de serveurs (4 095 pour <em>round‐robin</em>), mais sans prise en compte du poids ;</li>
<li>
<strong><em>leastconn</em></strong>, adapté aux sessions longues (LDAP, TSE…), c’est le serveur qui a le moins de connexions actives (pondéré par son poids) qui est choisi ;</li>
<li>
<strong><em>first</em></strong>, le premier serveur est utilisé jusqu’à <code>maxconn</code>, puis on passe au suivant, ce qui est idéal pour pouvoir éteindre des serveurs aux heures creuses ;</li>
<li>d’autres algorithmes basés sur un <em>hash</em> de l’IP, l’URL, un paramètre de la requête, un en‐tête HTTP, ou le <em>cookie</em> RDP.</li>
</ul><p>Le paramètre <code>balance</code> défini dans la section globale, pourrait être surchargé ici.</p>
<h3 id="savoir-ce-quil-se-passe">Savoir ce qu’il se passe</h3>
<p>Il y a plusieurs défauts sur notre configuration :</p>
<ul>
<li>les <em>logs</em> ne fonctionnent pas car HAProxy étant « chrooté », il ne peut pas accéder au <em>socket</em> UNIX ;</li>
<li>si un serveur Web tombe, HAProxy n’est pas au courant et nous non plus.</li>
</ul><p>Concernant les <em>logs</em>, il suffit de modifier la section globale :</p>
<pre><code class="bash">log localhost local0 notice</code></pre>
<p>Il faudra ensuite configurer son serveur de <em>log</em> préféré pour pouvoir récupérer les <em>logs</em> en UDP sur l’interface <em>loopback</em>.</p>
<p>Pour vérifier l’état de santé des serveurs il suffit d’ajouter le mot clé <em>check</em> à la fin de la déclaration des serveurs :</p>
<pre><code class="bash">server web1 192.168.42.11:80 check</code></pre>
<p>Dans ce cas, HAProxy lancera une requête <code>OPTIONS /</code> sur le serveur toutes les 2 secondes. On peut chercher à faire plus fin, comme, par exemple, une requête vers une URL applicative se connectant à une base de données. En bref, ne pas vérifier simplement l’état de santé du serveur mais également celui de l’application. Dans ce cas, il faut compléter l’option <code>httpchk</code> :</p>
<pre><code class="bash">listen http_proxy
<span class="nb">bind</span> :80
option httpchk GET /ping HTTP/1.1<span class="se">\r\n</span>Host:<span class="se">\ </span>www.example.com
http-check expect string pong
server web1 192.168.42.11:80 check inter 30s
server web2 192.168.42.12:80 check inter 30s
server web3 192.168.42.13:80 check inter 30s</code></pre>
<p>Du coup, on va aller chercher sur chaque serveur l’URL <code>/ping</code> de l’hôte <em><a href="http://www.example.com">www.example.com</a></em> toutes les 30 secondes et l’on attendra que le serveur nous réponde avec une page contenant le mot « pong ».</p>
<p>Nos serveurs sont donc bien surveillés par HAProxy, mais pour notre part — exception faite des <em>logs</em> — nous sommes aveugles. Pour remédier à cela, nous allons activer le <em>socket</em> de contrôle ainsi que l’interface d’administration. La première s’active dans la section globale :</p>
<pre><code class="bash">stats socket /tmp/haproxy_prod_admin.sock user root group nagios mode <span class="m">660</span> level admin</code></pre>
<p>On peut ensuite l’utiliser avec un programme comme <code>socat</code> par exemple. Elle est également utilisée par des utilitaires comme <a href="http://feurix.org/projects/hatop">HAtop</a> ou <a href="https://github.com/polymorf/check_haproxy/blob/master/check_haproxy.pl">l’excellente sonde Nagios de Polymorf</a> :</p>
<pre><code>socat /tmp/haproxy.sock readline
prompt
> help
Unknown command. Please enter one of the following commands only :
clear counters : clear max statistics counters (add 'all' for all counters)
clear table : remove an entry from a table
help : this message
prompt : toggle interactive mode with prompt
quit : disconnect
show info : report information about the running process
show stat : report counters for each proxy and server
show errors : report last request and response errors for each proxy
show sess [id] : report the list of current sessions or dump this session
show table [id]: report table usage stats or dump this table's contents
get weight : report a server's current weight
set weight : change a server's weight
set table [id] : update or create a table entry's data
set timeout : change a timeout setting
set maxconn : change a maxconn setting
set rate-limit : change a rate limiting value
disable : put a server or frontend in maintenance mode
enable : re-enable a server or frontend which is in maintenance mode
shutdown : kill a session or a frontend (eg:to release listening ports)
</code></pre>
<p>Quant à la seconde, elle s’active soit dans un <em>proxy</em> à part, soit dans un <em>proxy</em> existant. Celle‐ci donne l’état actuel des <em>proxies</em>, ainsi qu’un certain nombre de statistiques.</p>
<pre><code class="bash">listen http_proxy
<span class="nb">bind</span> :80
option httpchk GET /ping HTTP/1.1<span class="se">\r\n</span>Host:<span class="se">\ </span>www.example.com
http-check expect string pong
server web1 192.168.42.11:80 check inter 30s
server web2 192.168.42.12:80 check inter 30s
server web3 192.168.42.13:80 check inter 30s
stats <span class="nb">enable</span>
<span class="nb"> </span>stats uri /admin?stats
stats realm Haproxy<span class="se">\ </span>Statistics
stats auth admin:s3cR3T</code></pre>
<p><img src="//img.linuxfr.org/img/687474703a2f2f726d6469722e66722f686170726f78792e706e67/haproxy.png" alt="Stats HAProxy" title="Source : http://rmdir.fr/haproxy.png"></p>
<h3 id="routage-plus-complexe">Routage plus complexe</h3>
<p>Pour l’instant notre schéma de fonctionnement est très simple. S’il doit se complexifier, il deviendra utile de séparer les blocs <code>listen</code> en <code>frontend</code> et <code>backend</code>.</p>
<p>Cela nous donne :</p>
<pre><code class="bash">frontend http_proxy
<span class="nb">bind</span> :80
stats <span class="nb">enable</span>
<span class="nb"> </span>stats uri /haproxy
stats realm Haproxy<span class="se">\ </span>Statistics
stats auth admin:s3cR3T
default_backend web_servers
backend web_servers
option httpchk GET /ping HTTP/1.1<span class="se">\r\n</span>Host:<span class="se">\ </span>www.example.com
http-check expect string pong
server web1 192.168.42.11:80 check inter 30s
server web2 192.168.42.12:80 check inter 30s
server web3 192.168.42.13:80 check inter 30s</code></pre>
<p>Ainsi, si nous souhaitons offrir la possibilité d’utiliser le site en version HTTPS, il nous suffit d’ajouter un second frontal :</p>
<pre><code class="bash">frontend https_proxy
<span class="nb">bind</span> :443 ssl crt /etc/certificates/website.pem
reqadd X-Forwarded-proto:<span class="se">\ </span>https
default_backend web_servers</code></pre>
<p>Si derrière on utilise Apache, ajoutons dans sa configuration la ligne suivante :</p>
<pre><code class="apache"><span class="nb">SetEnvIfNoCase</span> X-Forwarded-Proto HTTPS HTTPS=on</code></pre>
<p>Cela permettra à nos utilisateurs de retrouver les bonnes variables d’environnement (en PHP par exemple : <code>$_SERVER["HTTPS"]</code>).</p>
<p>Si l’on veut reconnaître un utilisateur authentifié grâce au <em>cookie</em> MYSSO, il est alors facile de le rediriger systématiquement vers la version chiffrée du site :</p>
<pre><code class="bash">frontend http_proxy
<span class="nb">bind</span> :80
stats <span class="nb">enable</span>
<span class="nb"> </span>stats uri /haproxy
stats realm Haproxy<span class="se">\ </span>Statistics
stats auth admin:s3cR3T
acl is_logged cook MYSSO -m found
redirect scheme https <span class="k">if</span> is_logged
default_backend web_servers</code></pre>
<p>Bien évidemment, on peut souhaiter qu’ils s’identifient sur une page chiffrée, voire sur des serveurs séparés :</p>
<pre><code class="bash">frontend http_proxy
<span class="nb">bind</span> :80
stats <span class="nb">enable</span>
<span class="nb"> </span>stats uri /haproxy
stats realm Haproxy<span class="se">\ </span>Statistics
stats auth admin:s3cR3T
acl is_logged cook MYSSO -m found
acl to_login url_beg /login
redirect scheme https <span class="k">if</span> is_logged or to_login
default_backend web_servers</code></pre>
<p>À noter que pour former la condition, le <code>or</code> doit être spécifié alors qu’un <code>and</code> aurait été implicite.</p>
<p>Enfin, nous voulons que l’accès aux statistiques et au backoffice du site soit sécurisé par une vérification du certificat client. Nous allons commencer par créer un <em>back‐end</em> particulier donnant accès au serveur de <em>back office</em>. Il contiendra en plus l’accès aux statistiques que nous supprimons du coup du <em>front‐end</em> public :</p>
<pre><code class="bash">backend very_secure
stats <span class="nb">enable</span>
<span class="nb"> </span>stats uri /haproxy
stats realm Haproxy<span class="se">\ </span>Statistics
stats auth admin:s3cR3T
server admin 192.168.9.42:80</code></pre>
<p>Le <em>front‐end</em> public devient :</p>
<pre><code class="bash">frontend http_proxy
<span class="nb">bind</span> :80
acl is_logged cook MYSSO -m found
acl to_login url_beg /login
redirect scheme https <span class="k">if</span> is_logged or to_login
default_backend web_servers</code></pre>
<p>Sur la partie HTTPS, nous allons donc vérifier la présence d’un certificat client et, s’il est présent et valable, donner l’accès au <em>back office</em> et aux statistiques HAProxy. Pour cela, il faut fournir à HAProxy l’autorité de certification (<code>ca-file</code>) et éventuellement une liste de révocation (<code>crl-file</code>) :</p>
<pre><code class="bash">frontend https_proxy
<span class="nb">bind</span> :443 ssl crt /etc/certificates/website.pem ca-file /etc/certificates/website.ca verify optional crl-file /etc/certificates/website.crl
reqadd X-Forwarded-proto:<span class="se">\ </span>https
acl client_ok ssl_fc_has_crt
acl want_admin <span class="k">if</span> url_beg /admin
acl want_admin <span class="k">if</span> url_beg /haproxy
use_backend very_secure <span class="k">if</span> want_admin and client_ok
default_backend web_servers</code></pre>
<p>La négociation SSL échouera si le certificat présenté est invalide ou révoqué, mais pas s’il est absent (mot‐clé <code>optional</code>).</p>
<h3 id="coller-au-serveur-et-gérer-les-pannes">Coller au serveur et gérer les pannes</h3>
<p>Pour diverses raisons, on peut vouloir que le client ne change pas de serveur durant la durée de sa session. La plus mauvaise de ces raisons est que les sessions applicatives ne sont pas partagées, la meilleure étant que cela permet d’effectuer des trucs sympathiques, comme des mises à jour applicatives sans interruption de service ou encore de faciliter le débogage.</p>
<p>La façon la plus simple de faire est d’insérer un <em>cookie</em>. Si celui‐ci est présent, HAProxy essayera d’utiliser le serveur visé :</p>
<pre><code class="bash">backend web_servers
option httpchk GET /ping HTTP/1.1<span class="se">\r\n</span>Host:<span class="se">\ </span>www.example.com
http-check expect string pong
cookie SRV insert
server web1 192.168.42.11:80 check inter 30s cookie web1
server web2 192.168.42.12:80 check inter 30s cookie web2
server web3 192.168.42.13:80 check inter 30s cookie web3</code></pre>
<p>Ainsi, pour savoir sur quel serveur vous êtes, il suffit de regarder la valeur du <em>cookie</em> SRV.</p>
<p>C’est aussi le moment d’introduire la notion de poids. On peut en effet moduler l’importance de chaque serveur au sein du répartiteur de charge (<em>load‐balancer</em>) :</p>
<pre><code class="bash">backend web_servers
option httpchk GET /ping HTTP/1.1<span class="se">\r\n</span>Host:<span class="se">\ </span>www.example.com
http-check expect string pong
cookie SRV insert
server web1 192.168.42.11:80 check inter 30s cookie web1 weight <span class="m">10</span>
server web2 192.168.42.12:80 check inter 30s cookie web2 weight <span class="m">10</span>
server web3 192.168.42.13:80 check inter 30s cookie web3 weight 20</code></pre>
<p>Le poids peut être piloté par le <em>socket</em> de contrôle. Par exemple, pour passer le poids du serveur <em>web2</em> à zéro :</p>
<pre><code class="bash"><span class="nb">echo</span> <span class="s2">"set weight web_servers/web2 0"</span> <span class="p">|</span> nc -U /tmp/haproxy_prod_admin.sock</code></pre>
<p>Un poids de 0 ne signifie pas que le serveur est tombé, mais qu’il n’accepte plus de nouvelle session (laissant ainsi finir tranquillement celles en cours).</p>
<p>On peut également spécifier un serveur de secours (<em>backup</em>) :</p>
<pre><code class="bash">backend web_servers
option httpchk GET /ping HTTP/1.1<span class="se">\r\n</span>Host:<span class="se">\ </span>www.example.com
option allbackup
http-check expect string pong
cookie SRV insert
server web1 192.168.42.11:80 check inter 30s cookie web1 weight <span class="m">10</span>
server web2 192.168.42.12:80 check inter 30s cookie web2 weight <span class="m">10</span>
server web3 192.168.42.13:80 check inter 30s cookie web3 weight <span class="m">20</span>
server maintenance1 192.168.42.21:80 backup check inter 30s
server maintenance2 192.168.42.22:80 backup check inter 30s</code></pre>
<p>L’option <code>allbackup</code> spécifie que lorsque tous les serveurs sont tombés, tous les serveurs de secours (et pas seulement le premier disponible) doivent être utilisés.</p>
<p>Bien sûr, le <em>backup</em> est utile pour servir les pages de maintenance, mais également pour se replier en cas de problème logiciel. Ainsi, par exemple, si nous souhaitons utiliser Varnish pour servir les fichiers statiques, nous pouvons faire quelque chose comme :</p>
<pre><code class="bash">acl url_static url_reg -i ^<span class="se">\/</span><span class="o">(</span>.*<span class="o">)</span><span class="se">\.</span><span class="o">(</span>js<span class="p">|</span>jpg<span class="p">|</span>JPG<span class="p">|</span>jpeg<span class="p">|</span>gif<span class="p">|</span>png<span class="p">|</span>ico<span class="p">|</span>txt<span class="p">|</span>css<span class="p">|</span>pdf<span class="o">)(</span><span class="se">\?</span>.*<span class="o">)</span>?
use_backend varnish <span class="k">if</span> url_static</code></pre>
<p>dans les <em>front‐ends</em>, puis :</p>
<pre><code class="bash">backend varnish
option httpchk GET /ping HTTP/1.1<span class="se">\r\n</span>Host:<span class="se">\ </span>www.example.com
option allbackup
http-check expect string pong
server varnish 127.0.0.1:8080 check inter 30s
server web1 192.168.42.11:80 check inter 30s backup
server web2 192.168.42.12:80 check inter 30s backup
server web3 192.168.42.13:80 check inter 30s backup</code></pre>
<p>Ainsi, en cas d’indisponibilité du serveur Varnish, les fichiers sont servis par les serveurs principaux.</p>
<h3 id="et-ainsi-de-suite">Et ainsi de suite</h3>
<p>Lorsqu’on en prend l’habitude, HAProxy devient vite un outil indispensable. Il offre une telle souplesse, que ce soit en mode TCP ou HTTP, qu’il est difficile de rencontrer des situations pour lesquelles on ne puisse pas imaginer de solutions l’utilisant. D’autant plus qu’il excelle en termes de performance. Autrement dit : c’est bon, mangez‐en !</p></div><div><a href="https://linuxfr.org/news/haproxy-1-5.epub">Télécharger ce contenu au format EPUB</a></div> <p>
<strong>Commentaires :</strong>
<a href="//linuxfr.org/nodes/102609/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/news/haproxy-1-5#comments">ouvrir dans le navigateur</a>
</p>
d-joDavy DefaudBAudNils RatusznikBenoît Sibaudpalm123Nÿcojcr83azerttyuNeoXvaxvmshttps://linuxfr.org/nodes/102609/comments.atomtag:linuxfr.org,2005:News/355392014-07-23T13:11:08+02:002016-05-06T17:38:32+02:00Améliorer la disponibilité de ses servicesLicence CC By‑SA http://creativecommons.org/licenses/by-sa/4.0/deed.fr<div><p>Votre aventure d'hébergeur amateur prend de l'ampleur. Depuis quelques mois, vous avez réussi à <a href="//linuxfr.org/news/gerer-plusieurs-services-de-facon-transparente">gérer plusieurs services de façon transparente</a>, mais maintenant que vous avez de plus en plus d'utilisateurs de vos services, vous vous rendez compte que votre unique serveur web est surchargé et que chaque maintenance provoque des coupures de service que ne comprennent pas vos visiteurs.</p>
<p>Afin de répondre à cette problématique, le plus simple est de multiplier les serveurs : la charge sera répartie entre les différents serveurs et vous pourrez couper un serveur pour une maintenance, sans couper le service associé.</p></div><ul></ul><div><h2 class="sommaire">Sommaire</h2>
<ul class="toc">
<li>
<a href="#%C3%89tape-1--dig%C3%A9rer-quelques-concepts">Étape 1 : digérer quelques concepts</a><ul>
<li><a href="#r%C3%A9partition-de-charge">Répartition de charge</a></li>
<li><a href="#adresse-ip-virtuelle">Adresse IP virtuelle</a></li>
<li><a href="#test-de-vie">Test de vie</a></li>
<li><a href="#ordonnanceur-de-r%C3%A9partition">Ordonnanceur de répartition</a></li>
<li>
<a href="#un-peu-de-routage">Un peu de routage</a><ul>
<li><a href="#m%C3%A9thode-1--tout-passe-par-le-r%C3%A9partiteur-de-charge">Méthode 1 : tout passe par le répartiteur de charge</a></li>
<li><a href="#m%C3%A9thode-2--faisons-travailler-le-serveur">Méthode 2 : faisons travailler le serveur</a></li>
</ul>
</li>
</ul>
</li>
<li>
<a href="#%C3%89tape-2--multiplier-les-serveurs">Étape 2 : multiplier les serveurs</a><ul>
<li><a href="#mon-service-est-il-multipliable">Mon service est-il multipliable ?</a></li>
<li><a href="#mes-ressources-sont-elles-accessibles-de-partout">Mes ressources sont-elles accessibles de partout ?</a></li>
<li>
<a href="#comment-g%C3%A9rer-mon-routage">Comment gérer mon routage ?</a><ul>
<li><a href="#d%C3%A9finition-dun-routage-statique">Définition d'un routage statique</a></li>
<li><a href="#g%C3%A9rer-le-routage-direct">Gérer le routage direct</a></li>
</ul>
</li>
</ul>
</li>
<li>
<a href="#%C3%89tape-3--mon-premier-r%C3%A9partiteur-de-charge">Étape 3 : mon premier répartiteur de charge</a><ul>
<li>
<a href="#installation">installation</a><ul>
<li><a href="#machines">Machines</a></li>
<li><a href="#paquets">Paquets</a></li>
<li><a href="#param%C3%A8tres-syst%C3%A8me">Paramètres système</a></li>
<li><a href="#configuration-de-base">Configuration de base</a></li>
<li><a href="#configuration-de-linstance">Configuration de l'instance</a></li>
</ul>
</li>
<li>
<a href="#ma-premi%C3%A8re-adresse-ip-virtuelle">Ma première adresse IP virtuelle</a><ul>
<li><a href="#rappel-des-pr%C3%A9-requis-pour-le-routage-direct">Rappel des pré-requis pour le routage direct</a></li>
<li><a href="#d%C3%A9claration-dans-keepalivedconf">Déclaration dans keepalived.conf</a></li>
</ul>
</li>
<li>
<a href="#on-sen-fait-une-deuxi%C3%A8me">On s'en fait une deuxième ?</a><ul>
<li><a href="#choix-de-ladresse-ip">Choix de l'adresse IP</a></li>
<li><a href="#ajout-de-quelques-options">Ajout de quelques options</a></li>
<li>
<a href="#choix-du-test-de-vie">Choix du test de vie</a><ul>
<li><a href="#get-dune-url">GET d'une URL</a></li>
<li><a href="#test-personnalis%C3%A9">test personnalisé</a></li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
<li>
<a href="#%C3%89tape-4--exploitons-tout-%C3%A7a">Étape 4 : Exploitons tout ça</a><ul>
<li><a href="#extraire-des-statistiques">Extraire des statistiques</a></li>
<li><a href="#manipuler-vos-adresses-virtuelles-dynamiquement">Manipuler vos adresses virtuelles dynamiquement</a></li>
</ul>
</li>
</ul><h2 id="Étape-1--digérer-quelques-concepts">Étape 1 : digérer quelques concepts</h2>
<p>Afin de simplifier les explications et de coller à ce qui est probablement votre cas d'usage, nous considérerons dans ce tutoriel que nous travaillons dans une infrastructure totalement <a href="https://fr.wikipedia.org/wiki/IPv4" title="Définition Wikipédia">IPv4</a>.</p>
<h3 id="répartition-de-charge">Répartition de charge</h3>
<p>La <a href="https://fr.wikipedia.org/wiki/r%C3%A9partition%20de%20charge" title="Définition Wikipédia">répartition de charge</a> « <em>est un ensemble de techniques permettant de distribuer une charge de travail entre différents ordinateurs d'un groupe. Ces techniques permettent à la fois de répondre à une charge trop importante d'un service en la répartissant sur plusieurs serveurs, et de réduire l'indisponibilité potentielle de ce service que pourrait provoquer la panne logicielle ou matérielle d'un unique serveur</em> »<sup id="fnref1"><a href="#fn1">1</a></sup> . On distingue deux grands types de répartition de charge :</p>
<ul>
<li><p>la répartition parallèle (« actif / actif ») : plusieurs serveurs offrent de façon simultanée le service, le répartiteur de charge peut envoyer une requête indifféremment à chaque serveur ;</p></li>
<li><p>la répartition séquentielle (« actif / passif ») : plusieurs serveurs sont capables de rendre le service, mais le répartiteur de charge n'envoie des requêtes qu'à un seul d'entre eux ; l'envoi de requête à un autre serveur ne sera fait que si le serveur nominal n'est plus en mesure de prendre en compte les requêtes.</p></li>
</ul><p>Le mode séquentiel ne permet pas de répartir la charge de travail à proprement parler puisque seul un serveur rend le service à la fois, en revanche cela répond bien au besoin de ne pas interrompre le service en cas de coupure d'un serveur.</p>
<h3 id="adresse-ip-virtuelle">Adresse IP virtuelle</h3>
<p>Une adresse IP virtuelle (parfois appelée « vIP » ou « serveur virtuel », même si l'usage de ce dernier terme est tombé en désuétude suite à l'arrivée des « machines virtuelles » et le risque de confusion associé) est l'adresse IP d'un service faisant l'objet d'une répartition de charge : l'adresse est dite virtuelle parce qu'elle n'est portée par aucun serveur à proprement parler, mais par un groupe de serveurs, défini dans la configuration du répartiteur de charge. L'adresse IP virtuelle peut être utilisée comme n'importe quelle adresse IP, on doit notamment en autoriser l'accès depuis le pare-feu comme on le ferait pour l'adresse IP d'un serveur.</p>
<h3 id="test-de-vie">Test de vie</h3>
<p>Puisqu'on demande au répartiteur de charge de n'envoyer les requêtes qu'aux serveurs en état de les traiter, il faut lui donner les moyens de définir quels serveurs sont hors-service. Pour cela, on va configurer un ou plusieurs tests de vie par service, par exemple :</p>
<ul>
<li><p>un ping du serveur cible (test rarement pertinent, mais dans le cadre d'un réseau local non filtré et non routé, on peut considérer que si un serveur ne répond pas au ping c'est qu'il n'est plus en état de rendre le service)</p></li>
<li><p>une connexion TCP sur un port (si le serveur ne permet pas d'ouvrir une connexion sur le port 443, il ne rend à priori pas le service HTTPS)</p></li>
<li><p>un test applicatif (pour un serveur HTTP on peut vérifier qu'un « GET / » ne renvoie pas une erreur 500)</p></li>
<li><p>un test de service (pour un serveur HTTP hébergeant un wiki on peut aller jusqu'à tester qu'une modification de page réussit).</p></li>
</ul><p>Les tests de vie sont associés à une fréquence d'exécution, qui définira la durée maximale pendant laquelle on accepte qu'un serveur HS continue de recevoir des requêtes (par exemple, si on veut que le serveur ne reçoive plus de requêtes moins de 2 secondes après être tombé, il faut mettre en place un test de vie toutes les secondes), il faut donc veiller :</p>
<ul>
<li><p>à avoir un test de vie plus rapide que votre fréquence d'exécution (si vous lancez un test qui prend 5 secondes chaque seconde, ceux-ci vont s'empiler sur les serveurs) ;</p></li>
<li><p>à ne pas avoir des tests de vie qui deviennent une cause de surcharge des serveurs rendant le service (pour reprendre l'exemple du wiki, si vous avez 30 éditions par jour habituellement en faisant une édition par test de vie vous allez subitement en avoir des milliers).</p></li>
</ul><h3 id="ordonnanceur-de-répartition">Ordonnanceur de répartition</h3>
<p>Dans le cadre d'une répartition parallèle, chaque requête vers une adresse IP virtuelle est envoyée à un ordonnanceur qui se charge de définir par quel serveur la requête doit être traitée, parmi tous les serveurs détectés comme vivants. Il y a 3 grandes familles d'ordonnanceurs :</p>
<ul>
<li><p>les ordonnanceurs impartiaux : si on a 1000 requêtes réparties entre 4 serveurs, chaque serveur en traitera 250 ; pour cela l'algorithme généralement utilisé est le <a href="http://fr.wikipedia.org/wiki/Round-robin_%28informatique%29">round-robin</a> (les serveurs reçoivent une requête chacun leur tour), mais certains répartiteurs de charge proposent également des ordonnanceurs basés sur un algorithme <a href="http://fr.wikipedia.org/wiki/Pseudo-al%C3%A9atoire">aléatoire</a></p></li>
<li><p>les ordonnanceurs compensateurs : la requête est envoyée au serveur qui la traitera le plus vite (l'algorithme généralement utilisé est d'envoyer au serveur qui a le moins de connexions actives), l'ordonnanceur se charge donc de compenser l'éventuelle lenteur d'un serveur en lui envoyant moins de requêtes ; attention : même si cela n'est pas intuitif, un serveur défaillant traite souvent les requêtes plus rapidement qu'un serveur fonctionnel (un accès refusé à une base de données peut prendre quelques millisecondes quand le traitement d'une requête peut prendre plusieurs secondes), donc ce type d'ordonnanceur favorisera les serveurs défaillants si votre test de vie n'est pas suffisamment bien conçu pour que ceux-ci ne soient plus considérés comme vivants</p></li>
<li>
<p>les ordonnanceurs déterministes : une <a href="https://fr.wikipedia.org/wiki/fonction%20de%20hachage" title="Définition Wikipédia">fonction de hachage</a> appliquée à la requête reçue permet de définir le serveur qui traitera la requête ; il y a deux principaux types de déterminisme :</p>
<ul>
<li>déterminisme <a href="http://fr.wikipedia.org/wiki/Couche_r%C3%A9seau">réseau</a> : une même adresse IP source (ou un même couple adresse/port) enverra toujours au même serveur ; à noter que si vous avez de nombreux utilisateurs derrière un même proxy la répartition ne sera pas optimale ;</li>
<li>déterminisme <a href="http://fr.wikipedia.org/wiki/Couche_application">applicatif</a> : la même demande (par exemple "GET /login.php") enverra toujours au même serveur (en général la requête est analysée au niveau de la <a href="https://fr.wikipedia.org/wiki/couche%20application" title="Définition Wikipédia">couche application</a>, l'analyse du paquet TCP n'étant pas suffisante pour calculer un hash pertinent).</li>
</ul>
</li>
</ul><p>Les ordonnanceurs acceptent parfois des options :</p>
<ul>
<li><p>gestion des poids : on peut donner des poids différents aux serveurs pointés par une adresse virtuelle afin que ceux-ci soient privilégiés par l'algorithme de répartition (par exemple un ordonnanceur impartial enverra deux fois plus de connexions à un serveur de poids 10 qu'à un serveur de poids 5).</p></li>
<li><p>persistance de session : l'ordonnanceur n'est appelé que pour la première connexion d'un client, puis le répartiteur de charge conserve dans une table de sessions le serveur cible associé à ce client : tant que ce serveur sera vu vivant, toutes les requêtes du client lui seront envoyées.</p></li>
</ul><h3 id="un-peu-de-routage">Un peu de routage</h3>
<p>Vous allez donc avoir des connexions qui vont arriver depuis vos répartiteurs de charge vers vos serveurs ; maintenant, il faut se poser une question : comment répondre au client qui a fait la requête ? Il y a deux écoles, chacune ayant ses avantages et inconvénients. </p>
<h4 id="méthode-1--tout-passe-par-le-répartiteur-de-charge">Méthode 1 : tout passe par le répartiteur de charge</h4>
<p><img src="//img.linuxfr.org/img/687474703a2f2f7777772e64656e69732e696e66696e692e66722f2f646c66702f6d6574686f6465312e706e67/methode1.png" alt="Schéma montrant les connexions arrivant d'internet au répartiteur de charge, celui-ci les transférant aux serveurs, ceux-ci envoyant leurs réponses au répartiteur de charge qui les envoie lui-même vers internet" title="Source : http://www.denis.infini.fr//dlfp/methode1.png"><br>
Les connexions arrivent au répartiteur de charge ? Qu'elles y retournent ! Cette méthode qui est la plus utilisée consiste à répondre aux requêtes envoyées par le répartiteur de charge au répartiteur de charge lui-même, celui-ci s'occupant de les renvoyer sur Internet. Il y a deux façons de procéder :</p>
<ul>
<li>
<p>le NAT source : le repartiteur de charge se présente au serveur avec sa propre adresse IP, la réponse est faite naturellement à cette adresse</p>
<ul>
<li>avantages : cela fonctionne avec à peu près tous les services imaginables sans avoir à modifier le serveur cible, si on n'a pas que du logiciel libre côté serveur cela simplifiera grandement les choses ;</li>
<li>inconvénients : comme dans le cas d'un proxy, le serveur ne verra pas l'adresse IP d'origine, cela complique la gestion des traces que l'on doit conserver dans le cadre de la loi pour la confiance dans l'économie numérique, le diagnostic des problématiques rencontrées par certains utilisateurs et la mise en place de contrôles d'accès.</li>
</ul>
</li>
<li>
<p>le routage statique : le répartiteur de charge envoie les connexions telles quelles au serveur, mais celui-ci dispose d'un routage statique pour renvoyer toutes les requêtes provenant d'Internet au répartiteur de charge</p>
<ul>
<li>avantages : on n'a pas les inconvénients du NAT ;</li>
<li>inconvénients : il faut maintenir une table de routage pour chaque serveur en y listant l'ensemble des réseaux et services auxquels on est susceptible de devoir accéder sans passer par le répartiteur de charge.</li>
</ul>
</li>
</ul><h4 id="méthode-2--faisons-travailler-le-serveur">Méthode 2 : faisons travailler le serveur</h4>
<p><img src="//img.linuxfr.org/img/687474703a2f2f7777772e64656e69732e696e66696e692e66722f2f646c66702f6d6574686f6465322e706e67/methode2.png" alt="Schéma montrant les connexions arrivant d'internet au répartiteur de charge, celui-ci les transférant aux serveurs, ceux-ci envoyant leurs réponses directement à internet" title="Source : http://www.denis.infini.fr//dlfp/methode2.png"><br>
Cette méthode consiste à déléguer au serveur la réponse aux clients, sans repasser par le répartiteur de charge :</p>
<ul>
<li><p>avantage : le répartiteur de charge se comporte comme un simple routeur, il consomme donc peu de ressources système, une machine virtuelle minuscule est suffisante pour rendre ce service ;</p></li>
<li><p>inconvénient : cela nécessite de bidouiller les serveurs pour que ceux-ci acceptent de gérer des communications réseau peu orthodoxes et, en général, et dans ce cas hors système Linux cela s'avère complexe à mettre en œuvre.</p></li>
</ul><p>Il y a deux façons de gérer ces connexions :</p>
<ul>
<li><p>le routage direct : on fait croire à chaque serveur qu'il est porteur de l'adresse IP virtuelle afin qu'il traite les connexions concernant cette adresse IP comme une connexion à une adresse IP locale ;</p></li>
<li><p>le tunnel IP-IP : le répartiteur de charge envoie la connexion dans un tunnel et le serveur traite les connexions venant de son interface tunnel comme une connexion à une adresse IP locale (on préfère cette méthode au routage direct uniquement quand le répartiteur de charge n'est pas dans le même réseau que le serveur).</p></li>
</ul><h2 id="Étape-2--multiplier-les-serveurs">Étape 2 : multiplier les serveurs</h2>
<p>Maintenant que vous savez que vous pouvez repartir la charge entre plusieurs serveurs, vous allez pouvoir commencer à multiplier ceux-ci : attention cependant à vous poser les bonnes questions.</p>
<h3 id="mon-service-est-il-multipliable">Mon service est-il multipliable ?</h3>
<p>Certains services nécessitant une ressource locale ne peuvent pas faire l'objet d'une répartition de charge. Par exemple, une base SQLite ne garantit sa cohérence que si elle est capable de poser un verrou sur un fichier : un verrou de fichier étant local à un serveur, il n'est pas possible de partager une telle base de données entre différents serveurs. Dans ce type de cas, un répartiteur de charge séquentiel peut devenir intéressant : on peut installer plusieurs serveurs mais demander au répartiteur de charge de n'en adresser qu'un seul à la fois, ainsi toutes les requêtes accéderont à la même ressource locale.</p>
<h3 id="mes-ressources-sont-elles-accessibles-de-partout">Mes ressources sont-elles accessibles de partout ?</h3>
<p>Votre service utilise probablement des fichiers locaux et/ou des informations en mémoire pour fonctionner, il convient donc de s'assurer que celles-ci sont accessibles par tous les serveurs rendant le service. Il faut surtout se poser la question des informations de session que peut porter le service : celles-ci doivent être dans un espace partagé (il est commun de stocker des sessions php dans un montage NFS par exemple) ou dans un outil qui sait gérer la replication (une base de données en réseau par exemple). Si vous ne pouvez pas partager ou répliquer les informations de session entre vos différents serveurs, il conviendra de veiller à ce qu'un client ne change jamais de serveur pendant sa session, soit en utilisant la fonctionnalité de persistance de session de votre répartiteur de charge, soit en utilisant un ordonnanceur déterministe.</p>
<h3 id="comment-gérer-mon-routage">Comment gérer mon routage ?</h3>
<p>On peut se contenter de faire du NAT et ne pas se poser la question. C'est même la solution préconisée par de nombreux outils de répartition de charge. Cependant, si le NAT ne répond pas à votre besoin pour une des raisons indiquées précédemment (obligation légale, contrôle d'accès, besoin d'investigation) ou tout simplement parce que votre applicatif ou votre protocole ne le gère pas, la mise en place d'une infrastructure répartie peut affecter la configuration de votre serveur.</p>
<h4 id="définition-dun-routage-statique">Définition d'un routage statique</h4>
<p>Le plus simple lorsqu'on fait le choix d'un routage statique est de configurer le répartiteur de charge comme passerelle par défaut de votre serveur. Cependant, si votre serveur ne fait pas que répondre à des requêtes en utilisant des ressources locales (par exemple s'il s'agit d'un serveur mail, il doit aussi communiquer avec le reste du monde pour envoyer des mails), il va falloir gérer un routage différent pour ces autres besoins : si votre applicatif le permet vous pouvez envoyer ces connexions à une interface réseau spécifique qui ne passera pas par la passerelle par défaut, sinon il faudra envisager l'usage d'un <a href="https://en.m.wikipedia.org/wiki/Policy_based_routing">système de routage intelligent</a>.</p>
<h4 id="gérer-le-routage-direct">Gérer le routage direct</h4>
<p>Si vous avez une plate-forme 100% Linux, n'hésitez pas à faire ce choix, il faudra juste autoriser le trafic d'ARP en ajoutant cela dans votre sysctl.conf :</p>
<pre><code> net.ipv4.conf.all.arp_ignore=1
net.ipv4.conf.all.arp_announce=2
net.ipv4.conf.eth0.arp_ignore=1
net.ipv4.conf.eth0.arp_announce=2
</code></pre>
<p>(il faut le faire pour all et pour l'interface avec laquelle vous communiquez avec le répartiteur de charge) ; si vous n'avez pas prévu de redémarrer votre serveur, vous pouvez forcer la prise en compte de vos modifications :</p>
<pre><code> # sysctl -p
</code></pre>
<p>Ensuite, il convient de faire comprendre au serveur qu'il gère l'adresse IP virtuelle. Le plus propre pour faire cela est de déclarer celle-ci comme un alias de l'interface de loopback :</p>
<pre><code> # ifconfig lo:9
lo:4 Link encap:Boucle locale
inet adr:192.168.10.9 Masque:255.255.255.255
UP LOOPBACK RUNNING MTU:16436 Metric:1
</code></pre>
<h2 id="Étape-3--mon-premier-répartiteur-de-charge">Étape 3 : mon premier répartiteur de charge</h2>
<p><a href="https://fr.wikipedia.org/wiki/Linux%20Virtual%20Server" title="Définition Wikipédia">Linux Virtual Server</a>, abrégé en LVS, est un logiciel répartiteur de charge pour GNU/Linux. Il peut se configurer simplement en ligne de commande, mais afin de gérer simplement la configuration on utilise en général un logiciel spécialisé, dans ce tutoriel ce sera <em>keepalived</em>.</p>
<h3 id="installation">installation</h3>
<h4 id="machines">Machines</h4>
<p>Pour installer ce service, une simple machine virtuelle avec quelques centaines de Mo d'espace disque et quelques dizaines de Mo de mémoire suffira. Et puis comme on veut gérer la redondance en cas de panne, on va même en installer deux !</p>
<h4 id="paquets">Paquets</h4>
<p>Sur une Debian fraîchement installée avec le système de base, installer le paquet <strong>keepalived</strong> avec toutes ses dépendances mais sans les paquets recommandés :</p>
<pre><code># apt-get install keepalived
Lecture des listes de paquets... Fait
Construction de l'arbre des dépendances
Lecture des informations d'état... Fait
Les paquets supplémentaires suivants seront installés :
ipvsadm libnl1
Paquets suggérés :
heartbeat ldirectord
Les NOUVEAUX paquets suivants seront installés :
ipvsadm keepalived libnl1
0 mis à jour, 3 nouvellement installés, 0 à enlever et 0 non mis à jour.
Il est nécessaire de prendre 331 ko dans les archives.
Après cette opération, 995 ko d'espace disque supplémentaires seront utilisés.
</code></pre>
<p>Bien entendu ça fonctionne aussi bien avec d'autres distributions…</p>
<h4 id="paramètres-système">Paramètres système</h4>
<p>Ajouter le paramètre suivants dans <strong>/etc/sysctl.conf</strong>* :</p>
<pre><code># Parametres pour le LVS
net.ipv4.ip_forward=1
</code></pre>
<p>Charger la configuration :</p>
<pre><code> # sysctl -p
net.ipv4.ip_forward = 1
</code></pre>
<h4 id="configuration-de-base">Configuration de base</h4>
<p>Source : <a href="http://www.keepalived.org/documentation.html">http://www.keepalived.org/documentation.html</a></p>
<p>Debian ne génère aucune configuration à l'installation, il faut donc créer le fichier <strong>/etc/keepalived/keepalived.conf</strong> après l'installation. Pour commencer, il faut y mettre la section globaldefs qui permet de définir la configuration de base :</p>
<pre><code>global_defs {
notification_email {
georgette@example.com
}
notification_email_from lvs@example.com
smtp_server relayhost.example.com
smtp_connect_timeout 30
router_id LVS
}
vrrp_sync_group VG1 {
group {
linuxfr
}
}
</code></pre>
<p>Voici l'explication des paramètres :</p>
<ul>
<li><p><strong>notification_email</strong> : liste des adresses (séparées par des sauts de ligne) notifiées en cas de changement d'état d'une adresse IP virtuelle (enverra par exemple un e-mail lorsqu'un serveur ne répond plus) ; ne pas mettre cette ligne si on ne désire pas être notifié</p></li>
<li><p><strong>notification_email_from</strong>, <strong>smtp_server</strong>, <strong>smtp_connect_timeout</strong> : paramètres d'expédition des mails</p></li>
<li><p><strong>router_id</strong> : le petit nom donné au service LVS, comme on n'en a qu'un sur la plateforme, on va faire simple en mettant <em>LVS</em>, mais on peut faire plus intelligent</p></li>
<li><p><strong>group</strong> : liste des instances déclarées (voir ci-dessous)</p></li>
</ul><h4 id="configuration-de-linstance">Configuration de l'instance</h4>
<p>Toujours sans keepalived.conf, on peut créer plusieurs instances ayant chacune leur configuration (par exemple "prod" et "dev"), pour commencer on ne va en créer qu'une, nommée linuxfr :</p>
<pre><code>vrrp_instance linuxfr {
state MASTER
interface eth0
smtp_alert
virtual_router_id 51
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
192.168.2.9
}
}
</code></pre>
<p>Explication des paramètres :</p>
<ul>
<li><p><strong>vrrp_instance</strong> : début du bloc de paramètres de l'instance, doit être suivi du nom de l'instance (ici <em>linuxfr</em>)</p></li>
<li><p><strong>state</strong> : il s'agit de la seule différence entre la configuration du LVS primaire et du LVS secondaire : l'un d'entre eux doit être "MASTER", l'autre "SLAVE" (c'est pour cela qu'on peut se permettre de metre en place deux serveurs dès le début, la mise en place du second tient à un copier/coller suivi de cette seule modification)</p></li>
<li><p><strong>interface</strong> : nom de l'interface surveillée par le service</p></li>
<li><p><strong>smtp_alert</strong> : à positionner ou non selon que l'on souhaite avoir des notification par courriel des défaillances</p></li>
<li><p><strong>virtual_router_id</strong> : on peut mettre n'importe quel nombre entre 0 et 255, il faut juste qu'il soit différent entre les différentes instances</p></li>
<li><p><strong>authentication</strong>, <strong>auth_type</strong>, <strong>auth_pass</strong> : identifiants utilisés par les serveurs LVS pour communiquer entre eux, notez cependant que ces informations circulent en clair dans le réseau</p></li>
<li><p><strong>virtual_ipaddress</strong> : liste des adresses virtuelles portées par le LVS (une par ligne, 20 maximum) ; c'est la partie que vous oublierez systématiquement de remplir en ajoutant de nouvelles adresses IP virtuelles, et vous perdrez 5 minutes à chercher pourquoi ça ne marche pas</p></li>
</ul><h3 id="ma-première-adresse-ip-virtuelle">Ma première adresse IP virtuelle</h3>
<p>Dans cet exemple, nous déclarons une adresse virtuelle suivante 192.168.10.9 qui renvoie le port 80 vers le port 80 des serveurs 192.168.10.98 et 192.168.10.85.</p>
<h4 id="rappel-des-pré-requis-pour-le-routage-direct">Rappel des pré-requis pour le routage direct</h4>
<ul>
<li><p>vos répartiteurs de charge doivent être dans le même réseau que vos serveurs (sinon configurez votre LVS pour utiliser des tunnels)</p></li>
<li><p>vos serveurs doivent accepter le trafic ARP entre leurs interfaces (cf. paramètres systcl plus haut, si vous n'avez pas la main sur vos serveurs, configurez votre LVS pour faire du NAT source)</p></li>
<li><p>chaque serveur doit croire qu'il porte l'adresse IP du service (ici on déclarera un alias de l'interface de loopback avec l'adresse IP 192.168.10.9)</p></li>
<li><p>l'adresse doit être connue du bloc virtual_ipaddress de votre instance LVS (certes on vous l'a déjà précisé dans le paragraphe précédent, mais on sait que vous allez l'oublier)</p></li>
</ul><h4 id="déclaration-dans-keepalivedconf">Déclaration dans keepalived.conf</h4>
<pre><code>virtual_server 192.168.10.9 80 {
delay_loop 6
lb_algo rr
lb_kind DR
protocol TCP
real_server 192.168.10.98 80 {
weight 1
TCP_CHECK {
connect_port 80
connect_timeout 3
}
}
real_server 192.168.10.85 80 {
weight 1
TCP_CHECK {
connect_port 80
connect_timeout 3
}
}
}
}
</code></pre>
<ul>
<li><p><strong>virtual_server</strong> : doit être suivi de l'adresse IP virtuelle puis du port</p></li>
<li><p><strong>delay_loop</strong> : délai entre deux tests de vie (n'oubliez pas que vous avez deux serveurs LVS, donc vos serveurs se prendront deux fois la charge correspondante)</p></li>
<li><p><strong>lb_algo</strong> : l'algorithme utilisé par l'ordonnanceur ; les plus utilisés sont rr (round-robin) et lc (moins de connexions actives) avec leurs équivalents wrr et wlc prenant en compte les poids ; la liste complète des algorithmes est disponible dans <a href="http://www.linuxvirtualserver.org/docs/scheduling.html">http://www.linuxvirtualserver.org/docs/scheduling.html</a></p></li>
<li><p><strong>lb_kind</strong> : méthode d'accès aux serveurs, pour du routage direct on indique '''DR'''</p></li>
<li><p><strong>real_server</strong> : doit être suivi de l'adresse IP d'un serveur et du port du service. Il faut autant de blocs real_server qu'il y a de serveurs derrière l'adresse virtuelle</p></li>
<li><p><strong>weight</strong> : poids, notamment utilisé pour les algorithmes wlc et wrr ; par défaut, le poids est 1</p></li>
<li><p><strong>TCP_CHECK</strong> : test de vie de type ouverture de connexion TCP ; dans cette exemple si une connexion au port 80 prend plus de 3 secondes, le serveur n'est plus considéré comme vivant</p></li>
</ul><h3 id="on-sen-fait-une-deuxième">On s'en fait une deuxième ?</h3>
<p>Vous avez probablement plus d'un service à répartir, donc il faudra créer une adresse IP virtuelle par service.</p>
<h4 id="choix-de-ladresse-ip">Choix de l'adresse IP</h4>
<p>Pour votre deuxième service vous pouvez soit attribuer une nouvelle adresse IP, soit réutiliser celle d'une adresse de service existante, à condition évidemment que ce soit sur un port différent (et en plus comme ça elle est déjà dans le bloc virtual_servers, vous ne l'oublierez pas pour une fois). </p>
<h4 id="ajout-de-quelques-options">Ajout de quelques options</h4>
<pre><code>persistence_timeout 60
virtualhost supervision.fr.local
quorum 30
hysteresis 2
quorum_up "/usr/local/bin/notify.pl qourum up"
quorum_down "/usr/local/bin/start_spare_vm.pl"
sorry_server 192.168.10.55 80
</code></pre>
<ul>
<li><p>persistence_timeout : mettre un nombre de secondes si on veut activer la persistance de session ; pendant ce nombre de secondes, une même adresse IP source sera systématiquement envoyée au même serveur sans que l'ordonnanceur ne soit sollicité</p></li>
<li><p>quorum : poids total des serveurs actifs nécessaire pour considérer l'adresse virtuelle comme pleinement opérationnelle</p></li>
<li><p>quorum_down : commande à lancer quand le quorum n'est plus atteint, en général on met une commande qui envoie une alarme par sms ou dans l'outil de supervision, mais selon votre architecture vous pouvez aussi envisager de démarrer automatiquement des serveurs supplémentaires, d'activer une version allégée de vos services, etc.</p></li>
<li><p>quorum_up : commande à lancer une fois que le quorum est de nouveau atteint</p></li>
<li><p>hystérésis : différence de poids minimum entre deux appels de commande quorum_up/quorum_down ; par exemple dans notre cas si un quorum_down a été détecté à 29, le quorum_up ne sera pas appelé lors du passage à 30 mais seulement lors du passage à 31 ; cette fonctionnalité permet d'éviter d'appeler les commandes trop souvent lorsqu'on est proche des limites, c'est surtout utile si la commande appelée est particulièrement lourde</p></li>
<li><p>sorry_server : serveur auquel seront envoyées les requêtes si aucun des serveurs pointés par l'adresse virtuelle ne répond ; pour un service web ça pourrait être un mini serveut hébergeant une simple page html d'excuses</p></li>
<li><p>virtualhost : pour un service web, nom de domaine vers lequel seront envoyés les tests de vie HTTP ou HTTPS (cf. paragraphe suivant)</p></li>
</ul><h4 id="choix-du-test-de-vie">Choix du test de vie</h4>
<p>Pour notre première adresse IP virtuelle nous avons choisi un test de vie TCP, mais keepalived permet d'autres tests de vie.</p>
<h5 id="get-dune-url">GET d'une URL</h5>
<pre><code>HTTP_GET
{
url
{
path /test_vie.php
digest 5f1a4b7e269b7f5ddf6bbce06856c1e8
status_code 200
}
connect_port 80
connect_timeout 3
}
</code></pre>
<p>Si la page test_vie.php n'est pas dans le virtual host par défaut de votre serveur web, il faudra préciser le paramètre <em>virtualhost</em> dans la configuration de l'adresse IP virtuelle. Le paramètre <em>digest</em> correspond au hash MD5 de la réponse du serveur, on peut le récupérer avec la commande suivante :</p>
<pre><code> # genhash -s 192.168.10.85 -p 80 -u /test_vie.php
MD5SUM = 5f1a4b7e269b7f5ddf6bbce06856c1e8
</code></pre>
<p>Veuillez noter que :</p>
<ul>
<li><p>on peut ne mettre qu'une seule information entre <em>digest</em> et <em>status_code</em> (code retour HTTP, a priori ce sera 200) </p></li>
<li><p>on peut déclarer autant de blocs url{} que l'on veut dans un test, le serveur ne sera plus vu vivant si un seul d'entre eux échoue</p></li>
<li><p>si on veut faire un test en HTTPS, il faut nommer le bloc SSL_GET au lieu de HTTP_GET (et pour récupérer le digest ajouter l'option « -S » à la commande genhash)</p></li>
<li><p>le digest dépend du contenu de la page, n'ayez pas de contenu dynamique dedans ! Afficher l'heure ou la durée d'affichage par exemple ferait tomber systématiquement le test en erreur ; par contre c'est utile pour valider que tout va bien, par exemple on peut faire une page qui affiche « OK » quand elle arrive à accéder à la base de données, et « KO » sinon : le digest n'étant retrouvé que lorsque la page affiche OK, le répartiteur de charge n'enverra pas de trafic aux serveurs incapables d'accéder à la base de données</p></li>
</ul><h5 id="test-personnalisé">test personnalisé</h5>
<p>Il est possible d'écrire un script qui sera utilisé pour les checks, par exemple pour tester qu'un serveur LDAP est opérationnel, on fera un script qui fait une requête LDAP :</p>
<pre><code>MISC_CHECK
{
misc_path "/usr/local/bin/test_ldap.pl 192.168.10.72"
misc_timeout 15
# misc_dynamic
}
</code></pre>
<p>Le script doit simplement renvoyer 0 si le serveur est vivant, et une autre valeur si ce n'est pas le cas. Ici on n'a pas opté pour l'option misc_dynamic (elle est commentée), mais on peut l'activer si on utilise les algorithmes wrr ou wlc, dans ce cas le code retour du script sera interprété ainsi :</p>
<ul>
<li><p>0: le serveur est vivant, son poids doit rester celui configuré dans keepalived.conf</p></li>
<li><p>1 : le serveur n'est pas vivant, plus aucune requête ne doit lui être envoyé</p></li>
<li><p>de 2 à 255 : le serveur est vivant, mais son poids doit être changé par la valeur renvoyée moins deux (par exemple si le script a un code retour de 10 le nouveau poids du serveur sera 8)</p></li>
</ul><h2 id="Étape-4--exploitons-tout-ça">Étape 4 : Exploitons tout ça</h2>
<p>Votre service est configuré, il n'y a plus qu'à le lancer !</p>
<pre><code> # service keepalived start
</code></pre>
<p>Keepalived permet seulement de gérer une configuration pour LVS, sans donner d'outils d'exploitation supplémentaires. Pour ensuite suivre la vie de votre service LVS, il faut utiliser la commande <strong>ipvsadm</strong>.</p>
<h3 id="extraire-des-statistiques">Extraire des statistiques</h3>
<p>L'option <strong>--list</strong> (abréviations : -l ou -L) permet de lister toutes les adresses virtuelles portées par votre répartiteur de charge avec le nombre de connexions en cours pour chacun des serveurs qu'elles contiennent. En y ajoutant l'option <strong>--stats</strong>, vous aurez en plus des statistiques réseau :</p>
<pre><code> # ipvsadm -ln
-> RemoteAddress:Port Forward Weight ActiveConn InActConn
TCP 192.168.10.9:443 rr persistent 1
-> 192.168.10.70:443 Route 1 0 0
-> 192.168.10.85:443 Route 1 0 0
TCP 192.168.10.9:80 rr persistent 50
-> 192.168.10.70:80 Route 1 416 136
-> 192.168.10.85:80 Route 1 48 91
</code></pre>
<p>La plupart des outils de monitoring savent interpréter ces chiffres pour sortir des graphes qui peuvent vous être utiles, par exemple voici ce que donne un suivi de nombre de connexions en cours avec <a href="https://fr.wikipedia.org/wiki/munin" title="Définition Wikipédia">munin</a> :</p>
<p><img src="//img.linuxfr.org/img/687474703a2f2f6d756e696e2e696e66696e692e66722f766d5f706f72747a69632f6c767330332e696e66696e692e6d646c2f6370735f3139325f3136385f31305f395f38302d6461792e706e67/cps_192_168_10_9_80-day.png" alt="graphe de connexions" title="Source : http://munin.infini.fr/vm_portzic/lvs03.infini.mdl/cps_192_168_10_9_80-day.png"></p>
<h3 id="manipuler-vos-adresses-virtuelles-dynamiquement">Manipuler vos adresses virtuelles dynamiquement</h3>
<p>Si vous avez décidé d'utiliser le paramètre <em>quorum_down</em> pour adapter votre architecture dynamiquement, vous pouvez vouloir ajouter des serveurs dans la liste de ceux portés par une adresse virtuelle dynamiquement. Pour cela, il faut utiliser l'option <strong>--add-server</strong> (abrégeable en -a), il y a bien évidemment une option <strong>--delete-server</strong> pour faire l'inverse :</p>
<pre><code class="bash"><span class="c"># ajout du serveur 192.168.10.44</span>
<span class="c"># à l'adresse virtuelle 192.168.10.9:80</span>
ipvsadm -a -t 192.168.10.9:80 -r 192.168.10.75
<span class="c"># retrait du serveur 192.168.10.44</span>
<span class="c"># de l'adresse virtuelle 192.168.10.9:80</span>
ipvsadm -d -t 192.168.10.9:80 -r 192.168.10.75</code></pre>
<div class="footnotes">
<hr>
<ol>
<li id="fn1">
<p>Source : Article <a href="https://fr.wikipedia.org/wiki/R%C3%A9partition%20de%20charge" title="Définition Wikipédia">Répartition de charge</a> de Wikipédia en français - <a href="http://fr.wikipedia.org/w/index.php?title=R%C3%A9partition_de_charge&action=history">Liste des auteurs</a> <a href="#fnref1">↩</a></p>
</li>
</ol>
</div></div><div><a href="https://linuxfr.org/news/ameliorer-la-disponibilite-de-ses-services.epub">Télécharger ce contenu au format EPUB</a></div> <p>
<strong>Commentaires :</strong>
<a href="//linuxfr.org/nodes/102765/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/news/ameliorer-la-disponibilite-de-ses-services#comments">ouvrir dans le navigateur</a>
</p>
Denis DordoigneBAudNÿcopalm123Tonton ThBenoît SibaudNils RatusznikBruno Michelhttps://linuxfr.org/nodes/102765/comments.atom