LINUX:Loadbalancing - Serveurs du cluster (gate)
→ retour aux Serveurs en Loadbalancing (gate)
But
Pour cette configuration, plusieurs pièces la composent et vont subir quelques transformations par rapport à l'article sur les Serveurs en Failover. Pour pouvoir utiliser une ressource disque partagée par deux machines en accès total, il faut changer de système de formatage. Or le système choisi nécessite que les deux espaces soient accessibles. Nombre de ces changements en sont la conséquence.
Préparation
DRBD
Le système utilisé est Drbd. Classiquement ce système est utilisé en mode Actif/Passif (Primary/Secondary); il n'y a que la partie active qui peut avoir un accès à cette ressource disque. Dans cette configuration de deux machines actives, il faut que ces accès disques soient actifs des deux côtés ou Primary/Primary.
En outre, nous sommes revenus à des partitions de base de type Linux sans utilisation de LVM. Le schéma d'initialisation des disques et de la ressource Drbd est similaire à celle faite dans les articles sur le Partitionnement du disque et Drbd mais sans la couche LVM. Les raisons sont doubles: montrer que cette autre initialisation plus ancienne est possible et de ne pas se soucier des problèmes de LVM dans le contexte d'une ressource disque partagée entre deux machines.
Le fichier de configuration "/etc/drbd.d/data.res" devient:
resource drbddata { net { protocol C; verify-alg sha1; allow-two-primaries yes ; after-sb-0pri discard-zero-changes; after-sb-1pri discard-secondary; after-sb-2pri disconnect; } startup { become-primary-on both; } disk { on-io-error detach; } handlers { split-brain "/usr/lib/drbd/notify-split-brain.sh root"; out-of-sync "/usr/lib/drbd/notify-out-of-sync.sh root"; } on fo1.home.dom { disk /dev/sdb1; address ipv4 192.168.2.71:7789; device /dev/drbd1 minor 1; meta-disk internal; } on fo2.home.dom { disk /dev/sdb1; address ipv4 192.168.2.72:7789; device /dev/drbd1 minor 1; meta-disk internal; } }
Les deux options: "allow-two-primaries yes ;" et "startup { become-primary-on both; }" permettent et démarrent le système en mode "Primary/Primary". Les devices disque de base sont ici tous deux "/dev/sdb1".
Formatage disque
Auparavant nous avions formaté ce nouveau device en "XFS". Dans de cas-ci, il faut un système qui permettent un accès concurrent entre deux machines. Nous avons opté pour le formatage "GFS2". Il en existe un autre connu: "OCFS2".
Nous avons besoin d'installer de deux paquets spécifiques:
dnf install gfs2-utils dnf install dlm
Le premier les utilitaires de formatage et d'utilisation de "GFS2"; le second est nécessaire pour gérer à travers le réseau la gestion concurrente de accès des disques spécialement en cas de modifications; une modification ne pouvant être effectuée que par un programme à la fois, chacun à son tour. Nous aurons donc besoin de lancer un service spécifique apporté par ce paquet.
Dès que la ressource "drbddata" de Drbd est prête, on choisit une machine et on met cette ressource à l'état actif avec la commande suivante:
drbdadm primary drbddata
Ceci fait, on formate le device "/dev/drbd1":
mkfs.gfs2 -p lock_dlm -j 2 -t fo_cluster:datacluster /dev/drbd1
Explications de quelques paramètres:
- -j 2 : on choisit deux journaux car nous avons deux disques partagés
- -t fo_cluster:datacluster : la partie "fo_cluster" doit correspondre au nom du cluster repris dans la configuration de Corosync "/etc/corosync/corosync.conf":
cluster_name: fo_cluster
L'exécution de cette commande donne:
This will destroy any data on /dev/drbd1 Are you sure you want to proceed? [y/n] y Discarding device contents (may take a while on large devices): Done Adding journals: Done Building resource groups: Done Creating quota file: Done Writing superblock and syncing: Done Device: /dev/drbd1 Block size: 4096 Device size: 149,04 GB (39070542 blocks) Filesystem size: 149,04 GB (39070538 blocks) Journals: 2 Journal size: 128MB Resource groups: 598 Locking protocol: "lock_dlm" Lock table: "fo_cluster:datacluster" UUID: 4205aec6-99e4-4019-b150-aec81a885d12
Paramétrage de Corosync
Comme signalé ci-dessous, cette ressource disque qui utilise le service "dlm.service", doit être accessible en même temps sur l'autre machine. On ne peut travailler en Failover. C'est à dire que le quorum doit être de deux et non comme dans le cas du Failover où ce quorum pouvait être de un.
Dans le fichier "/etc/corosync/corosync.conf", l'option "two_node: 1" doit être éliminée.
Eventuellement on peut la remplacer par "expected_votes: 2". La section "quorum" devient:
totem { version: 2 cluster_name: fo_cluster transport: knet ip_version: ipv4 crypto_cipher: aes256 crypto_hash: sha256 cluster_uuid: 7aacd622f1484d40886c2b96120993bb interface { knet_transport: udp linknumber: 0 mcastport: 5420 } } nodelist { node { ring0_addr: 192.168.1.71 name: fo1.home.dom nodeid: 1 } node { ring0_addr: 192.168.1.72 name: fo2.home.dom nodeid: 2 } } quorum { provider: corosync_votequorum expected_votes: 2 } logging { to_logfile: yes logfile: /var/log/cluster/corosync.log to_syslog: yes timestamp: on }
Ne pas oublier de changer les adresses IP des machines du cluster selon le schéma du début d'article.
Pour devenir actif, il faut redémarrer le service Corosync.
Ces opérations doivent être faites sur les deux machines du cluster.
ATTENTION: Avant de redémarrer ce service Corosync, il faut démonter le disque Drbd
umount /data
car en arrêtant le service Corosync, celui de Dlm s'arrête également et comme le service Dlm est nécessaire, vous risquez fortement d'avoir des problèmes.
Configurer le mur de feu ou FireWall
Si vous activez le Firewall, ce qui est recommandé, il faut y ajouter les règles suivantes:
- sur la machine "fo1.home.dom", on ajoute:
-A INPUT -p tcp -m tcp --sport 21064 -s 192.168.1.72 -m conntrack --ctstate NEW -j ACCEPT -A OUTPUT -p tcp -m tcp --dport 21064 -d 192.168.1.72 -j ACCEPT
- sur la machine "fo2.home.dom", on ajoute:
-A INPUT -p tcp -m tcp --sport 21064 -s 192.168.1.71 -m conntrack --ctstate NEW -j ACCEPT -A OUTPUT -p tcp -m tcp --dport 21064 -d 192.168.1.71 -j ACCEPT
Dès que le disque "/data" est monté, le service Dlm utilise le port TCP 21064 pour effectuer son travail.
Montage de "/data"
On peut essayer de monter cette espace disque mais auparavant il est impératif de lancer le service Corosync:
systemctl start corosync.service
et de lancer le service de gestion des accès concurrents des disques:
systemctl start dlm.service
Ces deux services devront être lancés sur les deux machines du cluster.
Si vous ne le faites pas, le montage ne se fera pas et restera bloqué et ne pourra pas être tué; il ne vous restera que la solution que le redémarrage de la machine
La ressource "drbddata" devra être dans l'état "Primary/Primary" sur les deux machines du cluster
Le montage s'effectue avec la commande suivante, similaire à celle déjà vue excepté le type de formatage:
mount -t gfs2 /dev/drbd1 /data
On peut le faire sur les deux machines.
On peut en profiter pour recopier dans ce répertoire "/data", les sous-répertoires "web" et "home" utilisés dans l'article sur sur le Paramétrage des services en Failover.
Services des serveurs
Dans l'article sur les Serveurs en Failover, nous avions ajouté divers services accessibles par les clients tels Web et messagerie électronique. Tous ces services, paramétrés dans l'article sur le Paramétrage des services en Failover, restent changés à l'exception:
- du service Postfix-Base qui n'est plus utilisé sauf si vous voulez le réactiver manuellement dans le cas où Pacemaker et l'ensemble de ses services ne sont pas actifs.
- du service Mariadb.
Nous allons ajouter quelques éléments qui nous seront nécessaires pour la partie Loadbalancing de cette machine.
Mariadb
Deux services Mariadb ne peuvent utiliser les fichiers d'une même base de données ensemble. On choisit une des deux machines du cluster sur laquelle on lance ce service de façon autonome. Le répertoire de la base de données est mis sur un des disques non partagés de cette machine. Il n'y a plus de raison de le mettre sur un espace partagé. A l'origine, ce répertoire est "/var/lib/mysql" mais il peut être mis à un emplacement à votre convenance. Si on voulait utiliser Mariadb en mode Loadbalancing, Mariadb possède son propre système de cluster. Sur l'autre machine, le service Mariadb ne sera pas lancé.
L'option concernée dans le fichier de configuration du serveur Mariadb "/etc/my.conf.d/mariadb-server.cnf" redevient:
datadir=/var/lib/mysql
Apache
On ajoute un fichier "/data/web/vivant.html" dont le contenu est:
Je suis vivant.
Il servira au service "ldirectord.service" de vérifier qu'Apache est bien actif.
Dovecot
On ajoute sur les deux machines du cluster un utilisateur qui permettra au service "ldirectord.service" de vérifier que Dovecot est bien actif:
adduser -b /data/home -u 1001 -g users -s /sbin/nologin -c "Test Mail" testmail
On lui attrinue un mot de passe:
passwd testmail
Le mot de passe peut être:
Bateau52Ivre
Configuration de Pacemaker
Systemd: services nécessaires
Avant de lancer la configuration qui suit, il faut que les services suivants soient lancés sur les deux machines du cluster, spécialement "dlm.service":
systemctl start dlm.service systemctl start corosync.service systemctl start pcsd.service systemctl start pacemaker.service
Quorum
Comme nous devons avoir un quorum de deux machines car si une occurrence subsiste, nous risquons d'avoir des problèmes avec le disque partagé, il faut prendre une action spécifique; en cas de quorum non atteint, on stoppe toutes les ressources.
On adapte cette propriété avec la commande suivante à effectuer sur une des machines du cluster:
pcs property set no-quorum-policy=stop
Script
On effectue la suite des commandes suivantes à partir d'une des machines du cluster. On peut les mettre dans un script.
#!/bin/bash pcs resource create ClusterDrbd ocf:linbit:drbd drbd_resource=drbddata \ op start interval=0s timeout=240s \ op stop interval=0s timeout=100s \ op monitor interval=29s role=Promoted \ clone promotable=true master-max=2 clone-max=2 notify=true pcs resource create ClusterFs ocf:heartbeat:Filesystem device="/dev/drbd1" directory="/data" fstype="gfs2" \ "options=noatime,errors=panic" \ op monitor interval=20s on-fail=stop clone interleave=true pcs constraint order ClusterDrbd-clone then start ClusterFs-clone pcs resource create ClusterHttp systemd:httpd op monitor interval=30s clone pcs constraint order ClusterFs-clone then start ClusterHttp-clone pcs resource create ClusterPhp systemd:php-fpm op monitor interval=30s clone pcs constraint order ClusterHttp-clone then start ClusterPhp-clone pcs resource create ClusterPostfix systemd:postfix op monitor interval=30s clone pcs constraint order ClusterPhp-clone then start ClusterPostfix-clone pcs resource create ClusterDovecot systemd:dovecot op monitor interval=30s clone pcs constraint order ClusterPostfix-clone then start ClusterDovecot-clone pcs resource create ClusterMailTo ocf:heartbeat:MailTo email=root subject="FailOver_Home" op monitor interval=30s clone pcs constraint order ClusterDovecot-clone then start ClusterMailTo-clone
Clones
On remarque ici que toutes création de ressource comporte le paramètre "clone"; ceci implique que chaque ressource sera présente sur chaque machine du cluster. Chaque service sera actif sur chaque machine alors que précédemment, elles n'étaient présente que sur une seule machine. En outre la ressource Drbd est active sur les deux machines ("master-max=2 clone-max=2"); l'état sera en mode "Primary/Primary".
GFS2
On remarque que la ressource disque est montée en "gfs2". Cette ressource peut être plus sujette à des problèmes; divers précautions sont prises en cas d'erreur.
Services
On active les services Apache, PHP, Postfixe, Dovecot et la notification par mail.
Contraintes
Les contraintes d'ordre de démarrage sont connues; elles ont déjà été rencontrées dans les articles précédents. Il tombe sous le sens que la ressource "drbddata" doit être effective avant de pouvoir monter cet espace partagé. Et les services qui utilisent l'espace partagé, doivent être activés après ce montage.
Systemd: Pacemaker et Dlm
J'ai rencontré des problèmes après l'ajout du service Dlm. Par exemple, le service Dlm s'arrête quand on arrête le service Corosync mais quand on redémarre le service Corosync, celui de Dlm ne démarre pas. Quand on le sait, on veille à redémarrer également le service Dlm. Autre cas, on rencontre de temps en temps des problèmes lors du démarrage de la machine si tout est lancé ensemble. La solution consistait à attendre quelque temps (1 min) avant de lancer le service Pacemaker. Mais le plus gros problème se passe lors de l'arrêt de la machine. Systématiquement la machine se bloque ou prend beaucoup de temps pour s'arrêter ou redémarrer. On remarque que le service Dlm essaie de s'arrêter alors que le service Pacemaker n'a pas encore fini son étape d'arrêt, spécialement son étape de démontage du disque partagé. Or ce disque partagé a besoin du service Dlm sinon il se bloque.
Par contre si les services concernés sont arrêtés manuellement dans l'ordre (pacemaker, pcsd, corosync puis dlm), nous n'avons pas de problème.
Il nous faut trouver une solution.
System V et Systemd
Pour mémoire, par défaut, le démarrage d'Unix est structuré en couche en fonction de la niveau de fonctionnalités finales. Les plus connus sont:
- le niveau 0 pour l'arrêt de la machine
- le niveau 1 pour l'utilisation utilisation unique; ce niveau est utilisé en cas de dépannage
- le niveau 3 pour l'utilisation multi-utilisateurs avec support réseau mais sans la couche graphique; ce niveau est normalement utilisé pour les serveurs
- le niveau 5 pour l'utilisation multi-utilisateurs avec le support du réseau et avec la couche graphique; ce niveau est normalement utilisé pour les stations de travail
- le niveau 6 pour le redémarrage
Chaque service était numéroté pour définir son ordre de lancement ou d'arrêt. Ce système était appelé System V.
Dans notre cas, nous sommes au niveau 3 pour une fonctionnalité de type serveur.
Mais maintenant nous sommes passés au système Systemd. La couche 3 est devenue "multi-user.target". Lors du démarrage et de l'arrêt, on passe d'une couche ou "target" à l'autre imbriquées comme pour les pelures d'oignon pour enfin arriver à la couche désirée définie par le fichier "/etc/systemd/system/default.target". Dans le cas d'un serveur, le fichier pointe vers le fichier "/usr/lib/systemd/system/multi-user.target". Lors de la dernière couche à exécuter "multi-user.target", tous les services (ou autres) se trouvant dans le répertoire "/etc/systemd/system/multi-user.target.wants" seront exécutés. On y retrouve notre service Mariadb activé ci-dessus
Target
La solution trouvée consiste à isoler le lancement de ces services liés au clustering et de forcer leurs dépendances: corosync.service, dlm.service, pcsd.service et pacemaker.service. Nous allons ajouter une couche au dessus de la dernière exécutée lors du lancement "multi-user.target".
Nous créons le fichier "/usr/lib/systemd/system/cluster.target" dont voici le contenu:
[Unit] Description=Cluster Target Requires=multi-user.target After=multi-user.target AllowIsolate=yes
On note que cette couche se lance après ("After") la couche "multi-user.target" et que cette couche précédente "multi-user.target" est nécessaire ("Requires").
Comme on veut l'atteindre au final, on doit la définir comme défaut via le lien suivant:
ln -sf /usr/lib/systemd/system/cluster.target /etc/systemd/system/default.target
Il ne faut pas oublier de recharger les paramètres de Systemd suite à ces changements:
systemctl daemon-reload
Services
Maintenant qu'on a créé une nouvelle couche, il faut la remplir. On élimine celles qui nous concernent de la couche "multi-user.target":
systemctl disable dlm.service systemctl disable corosync.service systemctl disable pcsd.service systemctl disable pacemaker.service
Ensuite il nous faut adapter le service "pacemaker.service" qui nous pose quelques problèmes.
Pour ne pas modifier le fichier "pacemaker.service" d'origine, on en fait une copie:
cp /usr/lib/systemd/system/pacemaker.service /etc/systemd/system/cluster.service
On y apporte les modifications suivantes. Les lignes suivantes:
[Unit] ... After=corosync.service Requires=corosync.service ... [Install] WantedBy=multi-user.target ...
sont remplacées par
[Unit] ... After=corosync.service dlm.service pcsd.service Requires=corosync.service dlm.service pcsd.service ... [Install] WantedBy=cluster.target ...
Ce nouveau service va se placer dans la couche "cluster.target" et va exiger le lancement au préalable des services "corosync.service", "dlm.service" et "pcsd.service". On n'aura pas besoin de les activer spécifiquement.
Il ne faut pas oublier de recharger les paramètres de Systemd suite à ce changement:
systemctl daemon-reload
On active enfin ce nouveau service:
systemctl enable cluster.service
Un répertoire "/etc/systemd/system/cluster.target.wants" est créé et un lien est alors ajouté dans ce répertoire vers le fichier "/etc/systemd/system/cluster.service" de notre nouveau service.
Si on lance le nouveau service:
systemctl start cluster.service
les services "corosync.service", "dlm.service" et "pcsd.services" sont aussi lancés.
Lors de l'arrêt de la machine (et de son démarrage), nos problèmes ont disparu.
Statut
Après ces opérations, l'état du cluster peut être visualisé par la commande:
crm_mon -1
qui donne:
Status of pacemakerd: 'Pacemaker is running' (last updated 2023-02-21 12:46:02 +01:00) Cluster Summary: * Stack: corosync * Current DC: fo2.home.dom (version 2.1.5-3.fc37-a3f44794f94) - partition with quorum * Last updated: Tue Feb 21 12:46:02 2023 * Last change: Mon Feb 20 16:51:45 2023 by root via cibadmin on fo1.home.dom * 2 nodes configured * 14 resource instances configured Node List: * Online: [ fo1.home.dom fo2.home.dom ] Active Resources: * Clone Set: ClusterDrbd-clone [ClusterDrbd] (promotable): * Masters: [ fo1.home.dom fo2.home.dom ] * Clone Set: ClusterFs-clone [ClusterFs]: * Started: [ fo1.home.dom fo2.home.dom ] * Clone Set: ClusterHttp-clone [ClusterHttp]: * Started: [ fo1.home.dom fo2.home.dom ] * Clone Set: ClusterPhp-clone [ClusterPhp]: * Started: [ fo1.home.dom fo2.home.dom ] * Clone Set: ClusterPostfix-clone [ClusterPostfix]: * Started: [ fo1.home.dom fo2.home.dom ] * Clone Set: ClusterDovecot-clone [ClusterDovecot]: * Started: [ fo1.home.dom fo2.home.dom ] * Clone Set: ClusterMailTo-clone [ClusterMailTo]: * Started: [ fo1.home.dom fo2.home.dom ]
Si la machine "fo2.home.dom" est éteinte ou si ses services du cluster sont arrêtés, cette même commande donne:
Status of pacemakerd: 'Pacemaker is running' (last updated 2023-02-21 13:36:17 +01:00) Cluster Summary: * Stack: corosync * Current DC: fo1.home.dom (version 2.1.5-3.fc37-a3f44794f94) - partition WITHOUT quorum * Last updated: Tue Feb 21 13:36:18 2023 * Last change: Mon Feb 20 16:51:45 2023 by root via cibadmin on fo1.home.dom * 2 nodes configured * 14 resource instances configured Node List: * Online: [ fo1.home.dom ] * OFFLINE: [ fo2.home.dom ] Active Resources: * No active resources
On peut voir les port réseaux utilisés avec la commande:
netstat -natup
qui donne après filtrage de ce qui nous concernent:
Connexions Internet actives (serveurs et établies) Proto Recv-Q Send-Q Adresse locale Adresse distante Etat PID/Program name udp 0 0 192.168.1.71:5420 0.0.0.0:* 889/corosync tcp 0 0 0.0.0.0:2224 0.0.0.0:* LISTEN 977/python3 tcp 0 0 192.168.1.71:21064 0.0.0.0:* LISTEN - tcp 0 0 192.168.1.71:58475 192.168.1.72:21064 ESTABLISHED - tcp 0 0 192.168.1.71:21064 192.168.1.72:60905 ESTABLISHED - tcp 0 0 192.168.2.71:56993 192.168.2.72:7789 ESTABLISHED - tcp 0 0 192.168.2.71:7789 192.168.2.72:60513 ESTABLISHED - tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN 1823/httpd tcp 0 0 0.0.0.0:443 0.0.0.0:* LISTEN 1823/httpd tcp 0 0 0.0.0.0:25 0.0.0.0:* LISTEN 2135/master tcp 0 0 0.0.0.0:587 0.0.0.0:* LISTEN 2135/master tcp 0 0 0.0.0.0:465 0.0.0.0:* LISTEN 2135/master tcp 0 0 0.0.0.0:110 0.0.0.0:* LISTEN 2169/dovecot tcp 0 0 0.0.0.0:143 0.0.0.0:* LISTEN 2169/dovecot tcp 0 0 0.0.0.0:993 0.0.0.0:* LISTEN 2169/dovecot tcp 0 0 0.0.0.0:995 0.0.0.0:* LISTEN 2169/dovecot tcp 0 0 0.0.0.0:3306 0.0.0.0:* LISTEN 62285/mariadbd
Je les ai ordonnés: en début, ce qui concerne la base de Pacemaker et les services liées et en bas, les services lancés par Pacemaker.
Pour le paramétrage du mur de feu ou firewall, il faut tenir compte de ces ports et de leurs destinations et origines.
Configurer le mur de feu ou FireWall (Gate)
Cette partie de la configuration d'Iptables (ou équivalent; à adapter en fonction) est obligatoire. Elle est minimaliste; on peut ajouter le filtrage classique vu précédemment si désiré. Elle est à effectuer sur les deux serveurs du cluster.
Le trafic venant du client a été envoyé à la machine "cluster.home.dom" ayant l'adresse IP "192.168.1.73". Cette machine a renvoyé tel quel le paquet à un de nos deux serveurs du cluster. Ce serveur qui reçoit la requête ("PREROUTING") est perturbé car le destinateur ("192.168.1.73") ne lui correspond pas. Les rêgles suivantes vont remplacer l'adresse IP "192.168.1.73" par la sienne ("192.168.1.71" ou "192.168.1.72" selon) avant de la traiter en interne par ses services (HTTP,...). Ces rêgles ne reprennent que les ports qui concernent le LoadBalancing. Le résultat du traitement par le service (HTTP,...) sera envoyé directement au client sans passer par la machine "cluster.home.dom". On évite ainsi ce passage par cet intermédiaire qui peut constituer un goulet d'étranglement. Dans le précédent cas ("masq"), ce passage était obligatoire; la machine "cluster.home.dom" était un router.
Voici le contenu:
#**************************************************************** # FILTER #**************************************************************** *filter :INPUT ACCEPT [0:0] :FORWARD ACCEPT [0:0] :OUTPUT ACCEPT [0:0] COMMIT #**************************************************************** # NAT #**************************************************************** *nat :PREROUTING ACCEPT [0:0] :POSTROUTING ACCEPT [0:0] :OUTPUT ACCEPT [0:0] :INPUT ACCEPT [0:0] -A PREROUTING -i eth1 -p tcp -d 192.168.1.73 --dport 80 -j REDIRECT -A PREROUTING -i eth1 -p tcp -d 192.168.1.73 --dport 443 -j REDIRECT -A PREROUTING -i eth1 -p tcp -d 192.168.1.73 --dport 110 -j REDIRECT -A PREROUTING -i eth1 -p tcp -d 192.168.1.73 --dport 143 -j REDIRECT -A PREROUTING -i eth1 -p tcp -d 192.168.1.73 --dport 993 -j REDIRECT -A PREROUTING -i eth1 -p tcp -d 192.168.1.73 --dport 995 -j REDIRECT -A PREROUTING -i eth1 -p tcp -d 192.168.1.73 --dport 25 -j REDIRECT -A PREROUTING -i eth1 -p tcp -d 192.168.1.73 --dport 587 -j REDIRECT -A PREROUTING -i eth1 -p tcp -d 192.168.1.73 --dport 465 -j REDIRECT COMMIT
Assurez-vous que le paquet permettant l'utilisation du service d'Iptables est bien installé:
dnf install iptables.services
On active et lance ce service:
systemctl enable iptables.service systemctl start iptables.service
→ retour aux Serveurs en Loadbalancing (gate)