Reverse proxy Nginx : Load-balancing et Fail-Over
Sommaire
I. Présentation
Les serveurs et les architectures web actuelles se doivent d'avoir une performance est une disponibilité optimale pour répondre aux besoins des entreprises dont la survie dépend parfois (site d'e-commerce, site de commande en ligne ...) et pour le bien de l'expérience utilisateur également. Cela passe bien souvent par la mise en place d'un load-balancing et d'un fail-over avec des éléments qui ont pour rôle de gérer la charge des requêtes et de la répartir selon la disponibilité et l'occupation des ressources. C'est ce que nous allons voir ici en utilisant les serveurs web Nginx et Apache.
Version :
- Nginx 1.2.1
- Apache 2.2.22
- Debian 7
II. Reverse proxy, Load-Balancing & Fail-Over
J'ai déjà de nombreuses fois abordé ces notions sur IT-Connect mais je vais les rappeler ici.
Le Load-Balancing est le fait de répartir les requêtes qui arrivent sur un service entre plusieurs serveurs (deux ou plus). On peut alors avoir une diminution de la charge de travail des serveurs gérés en Load-Balancing ce qui permet d'éviter les surcharges, des ralentissements et des plantages. Un Load-balancing requiert le plus souvent un hôte dit "front-end" dont le rôle va être de réceptionner les requêtes et de les répartir entre les hôtes membres du cluster de load-balancing. Ces membres du cluster peuvent être identifiés comme des "back-end".
Note : Lors de réflexion sur la sécurité et la disponibilité d'une architecture web, il est également important de se poser la question de ce qu'il se passe si le load-balancer (agent qui se charge de répartir des tâches) plante, on arrive alors à avoir une architecture complète load-balancée dans tous les sens dépendant au final d'un seul hôte. C'est ce que l'on appelle un Single Point of Failure (SPOF)
Après cette parenthèse sécurité, voyons ce qu'est Fail-Over ;). Le Fail-Over, aussi appelé en français "basculement" est le fait que, quand un hôte assurant une tâche tombe, un autre est présent pour prendre le relais et ainsi rendre le problème transparent pour les utilisateurs finaux. C'est une notion clé dans la lute des sysadmins contre l'indisponibilité des services et des serveurs. On peut mettre en place du Fail-Over entre deux serveurs (ou plus) de deux manières. Soit un serveur prend toute la charge pendant que l'autre est totalement inutilisé. Quand le serveur principal tombe, toutes les requêtes vont vers le second serveur. Dans le deuxième cas, il s'intègre directement au processus de load-balancing. Quand un serveur tombe, il devient exclu du processus de load-balancing et le ou les serveurs restants se répartissent la charge de travail.
Un reverse proxy est un serveur qui va servir d'intermédiaire entre les utilisateurs et les serveurs web. Dans notre cas, le reverse proxy aura pour rôle de jouer les load-balancer entre nos serveurs web mais un reverse proxy peut également avoir d'autres fonctions comme des fonctions de sécurité avec mod security que nous avons vu dans un autre tuto (Installation et configuration de mod security) ou des fonctions de mise en cache (exemple de varnish). De plus, un reverse proxy va également avoir pour mission de rendre invisible toute la partie back end, les utilisateurs s'adresseront à un seul et unique serveur qui gérera ensuite vers quel back-end envoyer la requête.
III. Présentation de l'architecture Nginx & Apache
Bien ! Après ce rappel technique, je vais vous présenter brièvement l'architecture qui va nous permettre d'illustrer le tutoriel, schématisée comme suivant :
On a donc un serveur Nginx en front-end avec l'IP 192.168.1.2, son rôle sera comme je l'ai expliqué plus haut de répartir les requêtes utilisateur vers les deux serveurs "back-end" qui sont les deux serveurs Apache2 (Srv1 et Srv2). C'est eux qui ont le contenu des sites web et qui effectueront les traitements PHP (+ base de données s'il y en a, ce qui n'est pas le cas dans mon exemple car cela deviendrait hors sujet). Pour montrer qu'une architecture Load-balancée peut également en plus accueillir des sites non load-balancé, j'ai ajouté www.site2.loc qui n'est présent que sur un des deux serveurs. Cela permettra en plus de voir une configuration en reverse proxy "simple" et une configuration en reverse proxy Load-Balancing + Fail-Over.
Les serveurs Srv1 et Srv2 disposent donc de l'exacte même version du site web www.site1.loc afin de rendre le passage de l'un à l'autre invisible pour l'utilisateur. Dans mon cas, j'ai simplement mis un index.html avec le nom du site, j'ai également inclue une différence dans le texte affiché à des fins de débogage le temps de la mise en place. Cela permettra de voir si l'on est sur le serveur 1 ou 2. Pour le site2.loc, il n'est présent que sur le Srv1.
Trêve d'explication, maintenant, à vos claviers !
IV. Installation & configuration d'Nginx en reverse Proxy
Je pars ici du principe que l'architecture dont vous disposez est déjà en place au niveau réseau et interconnexion et également que les services web back-end sont opérationnels. La raison est que j'utilise pour ma part Apache mais que ce n'est pas forcément votre cas, je détaillerais néanmoins quelques subtilités pour la gestion des vHosts site1.loc et site2.loc.
Sur notre serveur Load-Balancer, on commence donc par installer Nginx :
apt-get install nginx
La configuration d'Nginx se trouve dans /etc/nginx, on y retrouve un système similaire à Apache2 sous Debian pour l'activation des configuration des modules et des sites web avec les répertoires sites-enabled qui contient les configurations des sites actifs et sites-availables qui contient les configurations des sites disponibles (mais pas forcément actifs) avec un lien symbolique entre les deux. On se rend donc dans le dossier /etc/nginx/site-availables :
cd /etc/nginx/site-availables
Dans ce dossier nous allons créer notre première configuration :
touch site1.loc
Nous allons maintenant écrire cette configuration, utilisez votre éditeur de texte préféré pour modifier le fichier site1.loc :
vim site1.loc
Voici la configuration que nous pouvons y mettre :
On distingue deux blocs, le bloc "Server" qui permet de configurer brièvement les éléments principaux du serveur web et le bloc "upstream" qui est le module permettant d'ajouter la configuration du Load-Balancing. Dans le bloc "Server", nous précisons le port d'écoute, l'URL à laquelle il est assigné et la "location" qui peut être le répertoire web généralement mais qui sera dans un cas de Reverse proxy une URL utilisant le module proxy pass. Il est important pour la liaison avec Apache que l'URL donnée soit la même que celle configurée dans les vHost Apache que nous verrons brièvement un peu plus bas. Plus simplement, le champ proxy pass permet d'inclure le bloc "upstream". Dans ce bloc upstream nous retrouvons le nom du site à nouveau puis les serveurs membres du cluster de load-balancing. J'ai ici mis des nom DNS, ce qui est plus simple à gérer au final.
Nous pouvons maintenant enregistrer le fichier et construire le fichier site2.conf pour notre deuxième site dans le même répertoire :
On voit ici une configuration similaire sans l'utilisation du module de load-balancing (upstream) étant donné que nous n'en avons pas besoin ! Le proxy_pass renvoie donc directement vers le site concerné. Un point qui peut vous mener à confusion ici est les nom DNS, j'ai en effet modifié mon fichier /etc/hosts comme suivant (utilisez votre DNS dans un environnement de production 😉 ) :
Concernant notre premier site, il va donc être redirigé avec l'URL www.site1.com tantôt vers srv1.loc (IP de mon premier serveur du cluster) ou srv2.loc (IP de mon deuxième serveur du cluster). En revanche pour mon site2, il sera uniquement redirigé vers www.site2.loc (mon premier serveur.). Il faut savoir que Nginx accepte assez mal de mettre des IP dans la partie upstream, d’où le fait de passer par les noms.
Du coté de mes serveurs Apache, voici la configuration du vHost site1 :
et celle du vHost site2 :
Une fois que notre configuration est terminée, nous allons sur notre serveur Nginx rendre nos deux sites configurés des sites actifs en faisant un lien symbolique entre les fichiers de configurations du répertoire sites-availables et sites-enabled
ln -s /etc/nginx/sites-availables/site1.conf /etc/nginx/sites-enabled ln -s /etc/nginx/sites-availables/site2.conf /etc/nginx/sites-enabled
On pourra ensuite redémarrer notre service Nginx :
service nginx restart
V. Tests
Afin de tester notre architecture, il faut maintenant effectuer un différenciation entre le contenu du site1 sur le serveur 1 et le contenu du site1 sur le serveur 2. Même s'il s'agit d'un seul caractère, cela permettra d'identifier sur quel serveur on se retrouve. Ce changement ne peut opérer que pendant la phase de débogage bien sûr. On pourra alors aller plusieurs fois de suite sur le site1.loc et voir que nous allons bien une fois sur un serveur et une fois sur l'autre. Il faut savoir que par défaut, le mode de load-balancing de Nginx est le round-robin, cela signifie que les serveurs auront une requête à traiter chacun leur tour, on arrive alors à du "50/50" en terme de nombre de requête, bien que toutes les requêtes ne se valent pas en terme de consommation des capacités et de ressources.
Un autre test pour effectuer cette vérification peut être la vérification et l'affichage des logs en direct sur les deux serveurs web , on verra alors dans les logs d'accès quel serveur répond à quel moment.
Pour tester le Fail-Over, il suffit tout simplement de couper un des deux serveurs de back-end et de voir si le service web (le site web) répond toujours, à ne pas faire en environnement de production avant d'avoir validé le fonctionnement bien entendu ;).
Enfin, on pourra également se rendre sur notre site2.loc dont la présence est là pour montrer que l'on peut également mêler site web "normal" et site web load-balancé sur une même architecture.
VI. Ajustement des paramètres
Maintenant que notre architecture est fonctionnelle, vous pouvez essayer de la customiser un peu, lors de la configuration du Load-Balancing et Fail-Over avec le module Nginx upstream, j'ai été bien avare en configuration, nous nous sommes en effet contenté du strict nécessaire, il faut savoir que nous pouvons ajouter quelques paramètres comme sur cette configuration :
upstream backend { server www.backend01.loc weight = 5; server www.backend02.loc max_fails = 3 fail_timeout=30s; server unix:/tmp/backend3 }
Ici, le champ "weight = 5" permet de définir le "poids" du serveur, c'est à dire sa priorité dans le traitement des requêtes. On peut par exemple prioriser un serveur plus performant que les autres pour optimiser le cluster.
Le champ "max_fails = 3" indique combien de fois une communication doit échouer dans un délai imparti (précisé par "fail_timeout" qui vient juste après) pour considérer le serveur comme HS et pour l’exclure du cluster (processus de Fail-Over). Par défaut, un seul échec exclut le serveur du cluster. En effet, si un serveur HS reste dans le cluster et que le load-balancer continue de lui envoyer des requêtes, une requête sur deux va échouer. Astuce pour les configurations exotiques et les courageux : mettre ces deux valeurs à 0 désactive la vérification de fonctionnement d'un hôte ;).
Vous trouverez toutes les explications dont vous aurez besoin sur ce lien pour le reste de la configuration du module upstream (load-balancing et failover) et sur celui-ci pour le module de reverse proxy dont nous avons seulement effleuré les possibilités dans ce tutoriel.
Voila une petite architecture load-balancing, sur un environnement réel, il est possible de rajouter d'autres modules comme le cache ou la sécurité mais j'ai ici cherché à vous présenter une architecture et une configuration de base qui puisse permettre de comprendre la configuration et le fonctionnement standard. Libre à vous de vous aventurer plus loin par la suite !
Pas mal !
Mais du coup dans le cas du round-robin, si je ne m’abuse la session de l’utilisateur est perdu ?
Bonjour,
j’ai un problème avec le server_name dans Nginx
quand je tape l’IP de mon module Nginx avec le port 8081 la redirection se fait bien.mais quand j’essaye de tapé debian.local rien ne s’affiche.
Ayant installé un serveur DNS dans mon serveur web je ne vois pas d’où vient le problème .
Pouvez-vous m’aider à trouver une solution à ce problème?
Merci Cordialement
bonjour j’aurais une question par rapport a la machine dans la quelle tourne nginx.
la machine serveur faisant tourner nginx doit elle avoir au moins deux cartes réseaux pour pouvoir relier le réseau ou se trouve les serveurs et l’internet par exemple.
Super ta documentation, dans ton fichier de configuration nginx, dans la partie upstream, tu met les adresses http://www.backend01.loc et http://www.backend02.loc ? ça devrait être http://www.site1.loc et http://www.site2.loc ?
nous vous remercie pour votre travail