Dans le cadre de la TX du semestre de A16, une première infrastructure Picasoft a été mise en place. Cette infrastructure, comme expliqué dans les premières étapes de la documentation, est basée sur un cluster Proxmox qui permet de centraliser la gestion de plusieurs serveurs physiques. Chacune des machines virtuelles émulées sur les machines physiques (Alice et Bob) hébergent des services s’exécutant dans des conteneurs Docker. Dans le but de rendre le déploiement des services de Picasoft plus flexibles et plus robustes aux pannes, il a été décidé d’utiliser Docker Swarm.
Contrairement au simple “Docker”, Docker Swarm permet de déployer des services (et non plus de simples conteneurs). Ces services sont en réalité des “abstractions” de conteneurs, dans le sens où ils peuvent être créés depuis n’importe quelle machine du cluster Swarm. L’utilisateur n’a pas à se soucier de l’instanciation des conteneurs, de la répartition de charge sur le cluster Swarm, ou encore du “service discovery”. Tout est géré par Swarm. En résumé, il suffit de déployer un nombre X de services depuis un nœud du cluster Swarm pour que, en interne, Docker créé des conteneurs sur Y nœuds du cluster et s’occupe de faire en sorte que les nœuds exécutent un nombre équivalent de conteneurs pour éviter qu’un nœud se retrouve surchargé (exécute 100 conteneurs) alors que d’autres ne font quasiment rien (exécute 2 conteneurs).
Oui, mais voilà, alors que Swarm et Proxmox semblent être des solutions idéales aux problématiques de robustesse, flexibilité et de haute disponibilité, il existe en réalité un problème majeur dans l’infrastructure actuelle: le cluster ne contient que 2 nœuds !
En fait, un cluster de 2 nœuds est certainement la pire configuration imaginable pour faire du clustering, puisque que des situations de split-brain
peuvent se produire et le quorum
peut devenir difficilement atteignable.
Avant de regarder de plus près ces deux phénomènes qui menacent, plus qu’ils n’aident, l’infrastructure, parlons de Corosync.
Corosync représente la couche de communication au sein du cluster Proxmox. Il est très utilisé de nos jour pour assurer la communication au sein des clusters open-source.
Pour fonctionner, Corosync utilise le protocole “totem”. Ce dernier consiste à passer un token de nœud en nœud du cluster. Chaque nœud fait la même séquence d’instructions (envoyer des messages, approbation des anciens messages etc), avant de passer le token au nœud suivant. Ce token (ou jeton) est propagé de proche en proche, de nœud en nœud, et cela de façon continue. Si un nœud venait à ne pas envoyer son token, alors, ce dernier serait déclaré comme étant perdu, et un nouveau token serait émis et re-propagé sur le cluster. En revanche, si un nœud perd son token plusieurs fois de suite, alors le nœud est déclaré “mort” au restant du cluster.
Si un nœud est déclaré mort, alors le restant des nœuds du cluster forment un nouveau cluster à N-1 nœuds (ils “excluent” le nœud mort du cluster). Toutefois, pour assurer le bon fonctionnement du nouveau cluster, il est nécessaire de savoir si ce nouvel ensemble de nœuds peut satisfaire la même tâche que le cluster initial. Une question se pose alors, “le nouveau cluster a-t-il une capacité calculatoire suffisante pour assurer le bon fonctionnement de l’application répartie ?”. Afin de répondre à cette question, le cluster nouvellement formé va calculer un “quorum” qui permet, en fonction du pouvoir de vote de chaque nœud, de savoir si suffisamment de voix sont présentes dans le cluster pour continuer l’exécution (NB: Des nœuds du cluster peuvent être dotés de plus de voix que d’autres. Ils ont donc un pouvoir de décision plus important que le restant des nœuds du cluster). Ainsi, si le nouveau cluster rassemble suffisamment de voix (quorum suffisamment élevé), un token est de nouveau propagé sur le cluster et l’exécution peut reprendre.
Ainsi, Corosync représente la couche de communication au sein du cluster de machines. Ces machines s’échangent un token de façon perpétuelle pour s’assurer que “tout va bien”. En cas de perte répétée du token par une machine, elle est déclarée “morte” et est exclue du cluster. Le nouveau cluster calcule ce que l’on appelle un “quorum” pour savoir s’il possède un “pouvoir” suffisant, lui permettant d’assurer le bon fonctionnement de l’application repartie.
Le quorum est un synonyme de “majorité”. Lorsque le cluster démarre, chaque nœud du cluster se voit affecter un nombre de voix (un pouvoir de vote) qui peut différer d’une machine à une autre (dans le cas de nœud “master” et “esclave” par exemple). Pour pouvoir continuer à fonctionner, le cluster doit recevoir le nombre limite de votes à avoir. Si un nœud est déclaré “mort” (un problème est survenu sur cette machine, ou elle a été déconnectée), alors le cluster se divise en une ou plusieurs partitions qui se reforment en nouveaux clusters sans le/les nœuds “mort(s)”. Avant de continuer à s’exécuter chaque nœud va calculer le quorum, en ajoutant son pouvoir de vote à celui des nœuds voisins. Si le quorum est suffisamment élevé, le cluster peut continuer à assurer les services du cluster. Si le quorum n’est pas suffisant, alors les nœuds s’excluront mutuellement et le cluster ne fonctionnera plus.
Le split brain est un risque particulièrement présent dans les clusters à 2 nœuds. En effet, comme son nom l’indique, le split-brain va mener à une division en 2 du cluster. Cela se produit lorsque 2 nœuds perdent contact l’un et l’autre et essayent de prendre le contrôle du cluster et des ressources partagées de façon simultanée. Chaque nœud pensera avoir le quorum et ne parviendra pas à exclure l’autre nœud. De ce fait, les deux nœuds se mettent à fonctionner indépendamment l’un de l’autre, ce qui peut mener à une corruption des systèmes de stockages distribués !
Maintenant que nous avons vu Corosync, et les notions de quorum et de split brain, il apparaît évident que le cluster de machines formé d’Alice et de Bob présente clairement des risques de split-brain en cas de panne. De ce fait, les avantages du clustering (haute disponibilité, flexibilité, robustesse face aux pannes etc) ne sont pas réellement perceptibles, ET, chaque nœud du cluster (Alice et Bob dans le cas du cluster Proxmox) représentent un point de faille. De ce fait, on multiplie l’apparition de problèmes par 2 sans pouvoir dégager davantage clairs sur notre cluster.
De plus, l’infrastructure comporte 2 clusters:
Ce qui signifie que les erreurs liées au clustering ont 2 fois plus de chance de se produire.
Ainsi, utiliser un système de clustering est certainement le meilleur moyen d’assurer la robustesse d’une infrastructure. Toutefois, ceci s’applique surtout a des clusters d’au moins 3 nœuds. Les clusters de 2 nœuds (dans le cas de Picasoft en tout cas) sont trop propices aux bugs en cas de panne et cela complexifie grandement la mise en place et le déploiement des services, tout en rallongeant les temps de maintenance.