Aller au contenu principal

Corosync et Pacemaker

Je poursuis sur la haute disponibilité et, dans ce guide, je vais explorer les outils Corosync et Pacemaker. Ces technologies sont essentielles pour garantir la continuité des services dans des environnements où la disponibilité des systèmes est une priorité. En tant qu'administrateur système, il est crucial de comprendre comment ces outils fonctionnent ensemble pour fournir une résilience et une gestion efficace des pannes dans les clusters de serveurs.

Corosync est au cœur de la communication au sein du cluster, assurant la gestion des messages et des informations d'état entre les différents nœuds. Sa robustesse et sa fiabilité en font un choix privilégié pour la coordination des nœuds dans un cluster. D'autre part, Pacemaker agit comme un gestionnaire de ressources avancé, capable de gérer la répartition et la récupération des services en cas de défaillance d'un composant du système.

L'association de Corosync et Pacemaker permet de créer des clusters flexibles et hautement disponibles, capables de supporter les défaillances sans interruption notable du service. Ce guide détaillera leur fonctionnement, leur configuration et leur maintenance, en fournissant des conseils pratiques et des exemples concrets pour aider à mettre en place et à optimiser des clusters utilisant ces technologies.

Historique

La genèse et le développement de Corosync et Pacemaker sont intrinsèquement liés à l'évolution des besoins en haute disponibilité et en gestion de clusters.

Corosync est issu du projet OpenAIS, qui avait pour objectif de développer une implémentation open source des standards de l'API de service d'interface d'application (API). Le but était de créer une infrastructure de communication pour les services de haute disponibilité. À mesure que le projet évoluait, le besoin de simplifier et de focaliser les fonctionnalités sur la communication en cluster est devenu évident. Corosync a ainsi été créé pour se concentrer exclusivement sur la couche de communication, laissant la gestion des ressources à d'autres outils, tels que Pacemaker.

Pacemaker a été développé initialement par la société Linux-HA (High-Availability Linux) pour étendre les capacités de l'outil Heartbeat, qui était alors limité à la gestion de deux nœuds seulement. Avec l'augmentation de la complexité des infrastructures IT et la nécessité de gérer des clusters plus grands et plus dynamiques, Pacemaker est devenu un gestionnaire de ressources complet capable de supporter des configurations de clusters étendues et complexes.

Au fil du temps, Corosync et Pacemaker ont été intégrés pour travailler conjointement, fournissant une solution complète pour la gestion de clusters haute disponibilité. Cette intégration a permis aux utilisateurs de bénéficier d'une communication efficace entre les nœuds avec Corosync, tout en utilisant Pacemaker pour la gestion fine et stratégique des ressources du cluster. Cette synergie a renforcé leur position comme la solution de référence pour les systèmes nécessitant une haute disponibilité.

L'adoption de Corosync et Pacemaker a été significative, surtout dans les secteurs nécessitant une disponibilité continue tels que les services financiers, les télécommunications et le commerce électronique. Leur capacité à maintenir la continuité des opérations, même face à des défaillances de composants, a prouvé leur valeur. Aujourd'hui, ils sont largement reconnus et utilisés dans divers environnements Linux et continuent d'être développés et soutenus par une communauté active de développeurs et d'utilisateurs.

Concepts clés

Pour comprendre pleinement comment Corosync et Pacemaker fonctionnent ensemble dans la gestion des clusters, il est crucial de maîtriser certains concepts fondamentaux du clustering. Ces concepts sont essentiels pour configurer et maintenir un cluster de haute disponibilité.

Quorum

Le quorum est un concept clé dans la gestion des clusters, désignant la majorité nécessaire pour prendre des décisions opérationnelles. Dans un cluster, le quorum aide à éviter le problème de "split brain", où le cluster pourrait être divisé en plusieurs sous-groupes qui fonctionnent de manière indépendante, ce qui peut entraîner des conflits de données. Corosync utilise des mécanismes de quorum pour s'assurer qu'un seul sous-ensemble de nœuds (ayant la majorité) peut opérer à un moment donné, améliorant ainsi l'intégrité et la cohérence des données.

Fencing (Isolation)

Le fencing est une stratégie de sécurité critique pour la gestion des clusters. Il s'agit de l'isolation d'un nœud qui semble défaillant ou instable, pour empêcher qu'il cause des dommages au reste du cluster, comme des corruptions de données. Pacemaker utilise le fencing pour garantir que seulement les nœuds sains et fiables participent au cluster, en éteignant ou en redémarrant les nœuds problématiques si nécessaire.

Gestion des ressources

La gestion des ressources est le processus par lequel Pacemaker contrôle les applications et services au sein du cluster. Cela inclut le démarrage, l'arrêt, et la surveillance des ressources, ainsi que la réaction aux défaillances. Les ressources peuvent être définies de manière à garantir qu'elles s'exécutent sur des nœuds spécifiques ou qu'elles migrent entre les nœuds en cas de besoin.

Tolérance aux pannes

La tolérance aux pannes est la capacité du cluster à continuer de fonctionner en présence de défaillances matérielles ou logicielles. Ceci est réalisé grâce à la redondance des ressources et à la capacité du cluster à basculer automatiquement les opérations vers des nœuds sains sans intervention humaine. Pacemaker et Corosync jouent un rôle essentiel dans la mise en œuvre de la tolérance aux pannes en détectant les défaillances et en réaffectant les ressources rapidement et efficacement.

Équilibrage de charge

L'équilibrage de charge dans le contexte du clustering fait référence à la distribution équitable des charges de travail et des ressources entre les nœuds du cluster. Cela permet d'optimiser la performance du système et de prévenir la surcharge de certains nœuds. Bien que Pacemaker ne soit pas un équilibreur de charge dans le sens traditionnel, il peut être configuré pour gérer la distribution des ressources de manière à maximiser l'efficacité du cluster.

Fonctionnalités de Corosync

Corosync joue un rôle essentiel dans la gestion des clusters en assurant la communication et la coordination entre les nœuds du cluster. Voici un aperçu des fonctionnalités clés de Corosync qui contribuent à son efficacité et sa fiabilité en tant que moteur de clustering.

L'une des fonctionnalités principales de Corosync est sa capacité à gérer de manière efficace les messages entre les nœuds du cluster. Il utilise un système de messagerie fiable qui garantit que les messages sont livrés même en cas de perturbations temporaires du réseau. Ce système est crucial pour le maintien de l'état du cluster et pour assurer que tous les nœuds possèdent une vue cohérente de l'état du système.

Corosync inclut un mécanisme de détection des pannes robuste qui surveille l'état des nœuds et des services au sein du cluster. Si un nœud cesse de répondre, Corosync peut rapidement détecter cette défaillance et en informer le reste du cluster. Cette détection rapide permet une intervention rapide pour résoudre le problème ou pour réaffecter les ressources nécessaires à d'autres nœuds.

Une autre fonctionnalité importante est la capacité de Corosync à synchroniser l'état du cluster entre tous les nœuds. Cette synchronisation est vitale pour la cohérence du cluster, assurant que chaque nœud ait la même information concernant l'état global du cluster. Cela permet une gestion homogène et une prise de décision basée sur des données à jour et synchronisées.

Corosync fournit également des fonctions de sécurité pour protéger la communication au sein du cluster. Il supporte le chiffrement des messages et l'authentification des nœuds, assurant que seuls les nœuds autorisés peuvent participer au cluster. Ces mesures de sécurité empêchent les acteurs malveillants de perturber ou d'espionner la communication entre les nœuds du cluster.

La conception de Corosync est hautement modulaire, permettant aux administrateurs de personnaliser et d'étendre ses fonctionnalités selon les besoins spécifiques de leur environnement. Cette extensibilité rend Corosync adaptable à divers scénarios de déploiement, de la simple paire de nœuds à des clusters de grande taille.

Fonctionnalités de Pacemaker

Pacemaker est un gestionnaire de ressources avancé pour la haute disponibilité dans les clusters Linux.

La principale force de Pacemaker réside dans sa capacité à gérer divers types de ressources au sein du cluster. Il peut gérer des applications, des services, des systèmes de fichiers virtuels et bien plus encore. Pacemaker assure que ces ressources sont démarrées, arrêtées et surveillées correctement, et il réagit automatiquement pour corriger tout dysfonctionnement.

En cas de défaillance d'un nœud ou d'une ressource, Pacemaker est capable d'effectuer une bascule (failover) vers d'autres nœuds du cluster. Cette capacité à récupérer rapidement les services en déplaçant les ressources vers des nœuds sains garantit une interruption minimale des services. Pacemaker peut également être configuré pour tenter de récupérer une ressource sur le même nœud avant de la déplacer, optimisant ainsi la gestion des pannes.

Pacemaker offre des options avancées pour contrôler où et comment les ressources sont placées dans le cluster. Les administrateurs peuvent définir des règles, des contraintes de localité, des préférences d'affinité ou d'anti-affinité et des politiques de gestion des ressources qui influencent les décisions de placement des ressources afin d'optimiser la performance et la disponibilité.

Pacemaker utilise Corosync pour la gestion des communications de cluster et pour garantir la cohérence de l'état du cluster à travers tous les nœuds. Cette intégration permet à Pacemaker de prendre des décisions éclairées sur la gestion des ressources en s'appuyant sur des informations à jour sur l'état du cluster.

Pacemaker est hautement configurable, permettant aux administrateurs de personnaliser presque tous les aspects de la gestion des ressources et du comportement du cluster. Cette flexibilité fait de Pacemaker un outil puissant pour s'adapter à de nombreux scénarios de déploiement différents, du simple cluster de basculement au complexe cluster de charges équilibrées.

Les différents types de ressources Pacemaker

Dans le contexte de Pacemaker, une ressource représente un service ou un élément du système que le cluster doit gérer pour garantir une haute disponibilité. Ces ressources peuvent inclure des services comme une base de données, un serveur web, ou même des adresses IP flottantes. Pacemaker utilise différents types d'agents pour gérer ces ressources. Ces agents définissent comment démarrer, arrêter et surveiller une ressource spécifique. Les principaux types d'agents de ressources utilisés dans Pacemaker incluent OCF, systemd et lsb.

OCF (Open Cluster Framework)

Les scripts OCF sont un standard développé par le projet Linux-HA pour uniformiser la manière dont les ressources sont gérées dans un cluster de haute disponibilité. Les scripts OCF sont des scripts shell qui suivent une convention spécifique et offrent des actions standardisées telles que start, stop, monitor, meta-data, entre autres. Chaque script OCF doit être capable de :

  • Démarrer une ressource
  • Arrêter une ressource
  • Surveiller l'état actuel de la ressource
  • Fournir des métadonnées décrivant la ressource et ses paramètres

Un exemple de configuration d'une ressource OCF dans Pacemaker pourrait ressembler à ceci :

pcs resource create myResource ocf:heartbeat:Dummy op monitor interval=30s

Ici, heartbeat:Dummy indique que le script OCF Dummy du fournisseur heartbeat est utilisé.

Les scripts OCF sont généralement stockés dans des répertoires spécifiques au fournisseur sous le dossier /usr/lib/ocf/resource.d/. Chaque fournisseur, tel que heartbeat ou pacemaker, a son propre sous-dossier dans ce répertoire.

Exemple de contenu du dossier /usr/lib/ocf/resource.d/heartbeat:

root@node1:/usr/lib/ocf/resource.d# ls heartbeat/
AoEtarget     LVM              SphinxSearchDaemon  apache           docker            iface-bridge  minio                    oralsnr           rsyslog
AudibleAlarm  LVM-activate     Squid               asterisk         docker-compose    iface-vlan    mpathpersist             ovsmonitor        scsi2reservation
CTDB          LinuxSCSI        Stateful            aws-vpc-move-ip  dovecot           ipsec         mysql                    pgagent           sfex
ClusterMon    MailTo           SysInfo             aws-vpc-route53  dummypy           iscsi         mysql-proxy              pgsql             sg_persist
Delay         ManageRAID       VIPArip             awseip           eDir88            jboss         nagios                   pingd             slapd
Dummy         ManageVE         VirtualDomain       awsvip           ethmonitor        jira          named                    podman            sybaseASE
EvmsSCC       NodeUtilization  WAS                 azure-events     exportfs          kamailio      nfsnotify                portblock         symlink
Evmsd         Pure-FTPd        WAS6                azure-lb         fio               ldirectord    nfsserver                postfix           syslog-ng
Filesystem    Raid1            WinPopup            clvm             galera            lvmlockd      nginx                    pound             tomcat
ICP           Route            Xen                 conntrackd       garbd             lxc           openstack-cinder-volume  proftpd           varnish
IPaddr        SAPDatabase      Xinetd              crypt            gcp-vpc-move-ip   lxd-info      openstack-floating-ip    rabbitmq-cluster  vdo-vol
IPaddr2       SAPInstance      ZFS                 db2              iSCSILogicalUnit  machine-info  openstack-info           redis             vmware
IPsrcaddr     SendArp          aliyun-vpc-move-ip  dhcpd            iSCSITarget       mariadb       oraasm                   rkt               vsftpd
IPv6addr      ServeRAID        anything            dnsupdate        ids               mdraid        oracle                   rsyncd            zabbixserver

systemd

Les unités systemd sont des scripts de service pour le système d'initialisation systemd, utilisé par de nombreuses distributions Linux modernes pour gérer les services système et les processus. Pacemaker peut directement gérer ces services en tant que ressources, en utilisant les commandes et fonctionnalités fournies par systemd. Cela permet une intégration étroite avec les composants système sous-jacents et simplifie la gestion des services qui sont déjà configurés pour être gérés par systemd.

Pour configurer une ressource systemd dans Pacemaker, vous pouvez utiliser une commande telle que :

pcs resource create myWebServer systemd:httpd.service op monitor interval=60s

Dans cet exemple, httpd.service est le nom du service systemd géré par Pacemaker.

LSB (Linux Standard Base)

Les scripts LSB sont basés sur les standards de la Linux Standard Base, qui définit les actions de service standard comme start, stop, status, et restart. Pacemaker peut utiliser ces scripts pour gérer des services qui ne sont pas encore intégrés à systemd. Bien que moins fréquemment utilisés aujourd'hui en raison de la prévalence de systemd, ils sont toujours pris en charge pour assurer la compatibilité avec les systèmes plus anciens.

Un exemple de commande pour configurer une ressource LSB pourrait être :

pcs resource create myOldService lsb:my-service op monitor interval=120s

Choix de l'agent de ressource

Le choix de l'agent de ressource dépend principalement du type de service à gérer et de l'environnement système. Les agents OCF sont préférables pour leur portabilité et leur extensibilité, tandis que les agents systemd sont mieux intégrés avec les systèmes qui utilisent systemd pour la gestion des services. Les agents LSB peuvent être utilisés pour les services plus anciens ou pour ceux qui ne sont pas encore pris en charge par systemd.

En résumé, comprendre et choisir le bon type d'agent de ressource est essentiel pour optimiser la gestion de la haute disponibilité avec Pacemaker, en fonction de vos besoins spécifiques et de votre environnement système.

Stratégie de fencing de Pacemacker

Le fencing, également connu sous le terme de clôture, est une stratégie importante dans la gestion des clusters de haute disponibilité, comme ceux contrôlés par Pacemaker. Le but principal du fencing est de prévenir les scénarios de "cerveau divisé" (split-brain) où plusieurs nœuds du cluster croient être le coordinateur actif, conduisant potentiellement à des corruptions de données.

Le fencing est une méthode utilisée pour isoler un nœud défectueux ou non fiable d'un cluster, afin de garantir que ce nœud ne puisse pas causer de dommages aux données partagées ou aux services du cluster. Cela est souvent réalisé en coupant l'accès du nœud aux ressources partagées, telles que le stockage réseau ou l'adresse IP virtuelle. Il existe principalement deux types de fencing :

Fencing actif : où le système prend des mesures actives pour isoler le nœud défectueux, comme redémarrer ou éteindre le nœud. Fencing passif : où le nœud défectueux est simplement ignoré par les autres nœuds du cluster sans prendre de mesures actives pour l'arrêter.

Les principaux agents de fencing de Pacemaker

Pacemaker supporte une variété d'agents de fencing (aussi appelés agents STONITH, pour "Shoot The Other Node In The Head"), qui sont essentiels pour assurer l'intégrité des données et la haute disponibilité dans un environnement de cluster. Ces agents permettent de garantir qu'un nœud défectueux est correctement isolé du cluster pour éviter les conflits et la corruption des données. Voici une liste de quelques agents de fencing communément utilisés avec Pacemaker :

  1. fence_aws : Conçu pour interagir avec les services Amazon Web Services (AWS). Cet agent peut arrêter, redémarrer ou isoler des instances EC2 via l'API AWS.
  2. fence_azure_arm : Utilisé pour les environnements Microsoft Azure. Cet agent fait appel à Azure Resource Manager pour gérer les instances virtuelles.
  3. fence_gce : Dédié aux environnements Google Cloud Platform (GCP). Il utilise l'API Google Compute Engine pour contrôler les instances virtuelles.
  4. fence_vmware_soap : Cet agent utilise l'API SOAP de VMware pour gérer les machines virtuelles sur des hôtes VMware ESXi ou vSphere.
  5. fence_ipmilan : Utilise l'interface de gestion à distance IPMI (Intelligent Platform Management Interface) pour contrôler le matériel serveur, permettant des actions telles que l'arrêt ou le redémarrage de la machine.
  6. fence_rhevm : Conçu pour les environnements Red Hat Enterprise Virtualization (RHEV), maintenant connu sous le nom de Red Hat Virtualization (RHV). Cet agent interagit avec l'API RHEV pour gérer les machines virtuelles.
  7. fence_xvm : Utilisé pour le fencing de machines virtuelles Xen à l'aide de commandes xm ou xl sur un hôte Xen.
  8. fence_scsi : Un agent de fencing qui utilise le SCSI persistent reservations pour contrôler l'accès aux périphériques de stockage partagé.
  9. fence_brocade : Permet le contrôle des switches Fibre Channel Brocade via telnet, ssh ou SNMP.
  10. fence_drac : Cible les serveurs Dell équipés de la carte de gestion à distance iDRAC, permettant diverses opérations de contrôle à distance.

Ces agents couvrent un large éventail de technologies et de plateformes, offrant ainsi des solutions de fencing flexibles et adaptées à divers environnements de datacenter et de cloud. Choisir l'agent approprié dépend des équipements et des services spécifiquement utilisés dans votre infrastructure.

Mise en place d'un LAB

Pour tester ces outils avec comme objectif de configurer un cluster HA avec Corosync et Pacemaker, je vais utiliser un environnement cloud, comme celui proposé par Outscale.

Pour cela, je vais modifier l'infrastructure du guide suivant pour avoir un NET composé de deux subnets provisionnés dans deux AZ différentes de la région SNC cloudgouv-eu-west-1.

Provisionnement Terraform

resource "outscale_security_group_rule" "security_group_rule01" {
  flow              = "Inbound"
  security_group_id = outscale_security_group.sg-ssh-all.id
  from_port_range   = "22"
  to_port_range     = "22"
  ip_protocol       = "tcp"
  ip_range          = "46.231.144.178/32"
}

resource "outscale_security_group_rule" "security_group_rule02" {
  flow              = "Inbound"
  security_group_id = outscale_security_group.sg-all-all.id

  ip_protocol = "-1"
  ip_range    = "0.0.0.0/0"
}

resource "outscale_security_group_rule" "security_group_rule03" {
  flow              = "Inbound"
  security_group_id = outscale_security_group.sg-all-all.id
  from_port_range   = "80"
  to_port_range     = "80"
  ip_protocol       = "tcp"
  ip_range          = "46.231.144.178/32"
}

resource "outscale_security_group_rule" "security_group_rule04" {
  flow              = "Inbound"
  security_group_id = outscale_security_group.sg-all-all.id
  from_port_range   = "443"
  to_port_range     = "443"
  ip_protocol       = "tcp"
  ip_range          = "46.231.144.178/32"
}

resource "outscale_security_group" "sg-ssh-all" {
  description         = "Permit SSH from All"
  security_group_name = "seg-ssh-all"
  net_id              = outscale_net.my_net.net_id
}

resource "outscale_security_group" "sg-all-all" {
  description         = "Permit All from All"
  security_group_name = "seg-all-all"
  net_id              = outscale_net.my_net.net_id
}

resource "outscale_route_table" "private_route_table" {
  net_id = outscale_net.my_net.net_id
  tags {
    key   = "Name"
    value = "private_route_table-a"
  }
}

resource "outscale_route_table" "private_route_table2" {
  net_id = outscale_net.my_net.net_id
  tags {
    key   = "Name"
    value = "private_route_table-b"
  }
}

resource "outscale_route_table" "public_route_table" {
  net_id = outscale_net.my_net.net_id
  tags {
    key   = "Name"
    value = "public_route_table"
  }
}

resource "outscale_route" "route-IGW" {
  destination_ip_range = "0.0.0.0/0"
  gateway_id           = outscale_internet_service.internet_gateway.internet_service_id
  route_table_id       = outscale_route_table.public_route_table.route_table_id
}

resource "outscale_route" "to_nat_gateway" {
  nat_service_id       = outscale_nat_service.public_nat_gateway.nat_service_id
  destination_ip_range = "0.0.0.0/0"
  route_table_id       = outscale_route_table.private_route_table.route_table_id
}

resource "outscale_route" "to_nat_gatewa2" {
  nat_service_id       = outscale_nat_service.public_nat_gateway.nat_service_id
  destination_ip_range = "0.0.0.0/0"
  route_table_id       = outscale_route_table.private_route_table2.route_table_id
}

resource "outscale_route_table_link" "backend_subnet-a_private_route_table_link" {
  subnet_id      = outscale_subnet.backend_subnet-a.subnet_id
  route_table_id = outscale_route_table.private_route_table.route_table_id
}

resource "outscale_route_table_link" "backend_subnet-b_private_route_table_link" {
  subnet_id      = outscale_subnet.backend_subnet-b.subnet_id
  route_table_id = outscale_route_table.private_route_table2.route_table_id
}

resource "outscale_route_table_link" "public_subnet_public_route_table_link" {
  subnet_id      = outscale_subnet.public_subnet.subnet_id
  route_table_id = outscale_route_table.public_route_table.route_table_id
}

resource "outscale_public_ip" "public_nat_gateway_ip" {}

resource "outscale_nat_service" "public_nat_gateway" {
  subnet_id    = outscale_subnet.public_subnet.subnet_id
  public_ip_id = outscale_public_ip.public_nat_gateway_ip.public_ip_id
  tags {
    key   = "Name"
    value = "public_nat_gateway"
  }
}

resource "outscale_subnet" "public_subnet" {
  subregion_name = "${var.region}a"
  ip_range       = "10.0.1.0/24"
  net_id         = outscale_net.my_net.net_id
  tags {
    key   = "Name"
    value = "public_subnet"
  }
}

resource "outscale_subnet" "backend_subnet-a" {
  subregion_name = "${var.region}a"
  ip_range       = "10.0.2.0/24"
  net_id         = outscale_net.my_net.net_id
  tags {
    key   = "Name"
    value = "backend_subnet-a"
  }
}

resource "outscale_subnet" "backend_subnet-b" {
  subregion_name = "${var.region}b"
  ip_range       = "10.0.3.0/24"
  net_id         = outscale_net.my_net.net_id
  tags {
    key   = "Name"
    value = "backend_subnet-b"
  }
}

resource "outscale_net" "my_net" {
  ip_range = "10.0.0.0/16"
  tags {
    key   = "Name"
    value = "my_net"
  }
}

resource "outscale_internet_service" "internet_gateway" {
}

resource "outscale_internet_service_link" "internet_gateway_link" {
  internet_service_id = outscale_internet_service.internet_gateway.internet_service_id
  net_id              = outscale_net.my_net.net_id
}

Je provisionne deux nœuds en les répartissant sur les deux sous-réseaux (remplacer node1 par node2 et backend_subnet-a par backend_subnet-b pour la seconde machine) :

data "outscale_images" "images" {
  filter {
    name   = "image_ids"
    values = ["ami-510ceb36"]
  }
}

data "outscale_keypair" "keypair01" {
  keypair_name = "bastion"
}

data "outscale_subnet" "subnet" {
  filter {
    name   = "tag_values"
    values = ["backend_subnet-a"]
  }
}

data "outscale_security_group" "sg-all-all" {
  security_group_name = "seg-all-all"
}

data "outscale_security_group" "sg-ssh-all" {
  security_group_name = "seg-ssh-all"
}

resource "outscale_vm" "vm" {
  image_id     = data.outscale_images.images.images[0].image_id
  vm_type      = "tinav5.c4r8p1"
  keypair_name = data.outscale_keypair.keypair01.keypair_name
  security_group_ids = [
    data.outscale_security_group.sg-all-all.security_group_id,
    data.outscale_security_group.sg-ssh-all.security_group_id
  ]
  subnet_id = data.outscale_subnet.subnet.id
  state     = "running"
  private_ips = ["10.0.2.10"]
  block_device_mappings {
      device_name = "/dev/sda1"
      bsu {
          volume_size           = 100
          volume_type           = "io1"
          iops                  = 2000
          delete_on_vm_deletion = true
      }
  }
  tags {
    key   = "Name"
    value = "node1"
  }
  tags {
    key   = "Application"
    value = "cluster"
  }
  tags {
    key   = "Group"
    value = "samba"
  }
  tags {
    key   = "Env"
    value = "test"
  }
}

output "IP" {
  value = outscale_vm.vm.private_ip
}

Configuration des noeuds

Pour cette tâche je vais utiliser un playbook ansible.

---
- name: Create Corosync Pacemaker Cluster
  hosts: cluster
  gather_facts: true
  vars:
    cluster_name: my_cluster
    pacemaker_disable_stonith: true
    pacemaker_cluster_resources: []
      # - resource_id: 'webserver'
      #   action: 'create'
      #   provider: 'ocf:heartbeat:apache'
      #   options:
      #     - 'configfile=/etc/apache2/apache2.conf'
      #   op: 'monitor'
      #   op_options:
      #     - 'timeout=5s'
      #     - 'interval=5s'
  tasks:
    - name: Add IP address of all hosts to all hosts | {{ inventory_hostname }}
      ansible.builtin.lineinfile:
        dest: /etc/hosts
        regexp: "^.*{{ hostvars[item].tags.Name }}.{{ hostvars[item].tags.Env }}.local"
        line: "{{ (hostvars[item].ansible_all_ipv4_addresses | select('match', '10.0.') | list)[0] }} {{ hostvars[item].tags.Name }}.{{ hostvars[item].tags.Env }}.local {{ hostvars[item].tags.Name }}"
        state: present
      when: hostvars[item].ansible_nodename is defined
      with_items: "{{ groups.bastions }}"
      become: true
    - name: Install packages
      become: true
      ansible.builtin.apt:
        name:
          - pcs
          - pacemaker
          - corosync
          - fence-agents-extra
          - resource-agents-extra
        state: present
    - name: Set password of user hacluster
      ansible.builtin.user:
        name: hacluster
        state: present
        password: "hacluster" # mettre dans un vault ansible
      become: true
    - name: Authorize pcs auth
      ansible.builtin.command: "pcs cluster auth -u hacluster -p hacluster"
      become: true
      changed_when: false
      when: inventory_hostname == "10.0.2.10"
    - name: Upgrade packages
      become: true
      ansible.builtin.apt:
        force_apt_get: true
        update_cache: true
        upgrade: true
        cache_valid_time: 3600
    - name: Create corosync-config
      become: true
      ansible.builtin.template:
        src: corosync.conf.j2
        dest: /etc/corosync/corosync.conf
        mode: "0644"
      notify: Restart corosync
    - name: Start pacemaker
      ansible.builtin.service:
        name: pacemaker
        state: started
    - name: Capturing Cluster Resources
      ansible.builtin.command: "pcs resource show --full"
      become: true
      register: "_pcs_resource_show"
      changed_when: false
    - name: Setting Stonith
      ansible.builtin.command: pcs property set stonith-enabled=false
      become: true
      when: pacemaker_disable_stonith
    - name: Creating Cluster Resources
      ansible.builtin.command: >
              pcs resource create {{ item['resource_id'] }}
              {{ item['provider'] }} {{ item['options']|join(' ') }}
              {% if item['op'] is defined %}op {{ item['op'] }}{% endif %}
              {% if item['op_options'] is defined %}{{ item['op_options'] | join(' ') }}{% endif %}
      become: true
      with_items: '{{ pacemaker_cluster_resources }}'
      when: >
            (pacemaker_cluster_resources is defined and
            inventory_hostname == "10.0.2.10") and
            (item['options'] is defined and
            (item['resource_id'] not in _pcs_resource_show['stdout'] and
            item['options']|join(' ') not in _pcs_resource_show['stdout'])) and
            item['action']|lower == 'create'
  handlers:
    - name: Restart corosync
      become: true
      ansible.builtin.systemd:
        name: corosync
        state: restarted

Ce playbook Ansible est conçu pour configurer un cluster Corosync et Pacemaker sur un groupe d'hôtes désigné sous le nom cluster. Il inclut plusieurs tâches pour préparer les hôtes, installer les paquets nécessaires, configurer les fichiers et gérer les ressources du cluster. Voici une explication détaillée des différentes parties de ce playbook :

Structure et Variables Globales

  • hosts: cluster : Le playbook cible les hôtes du groupe cluster.
  • gather_facts: true : Collecte les informations sur les hôtes avant d'exécuter les tâches.
  • vars : Définit des variables utilisées dans le playbook :
    • cluster_name: Nom du cluster.
    • pacemaker_disable_stonith: Une variable booléenne pour activer ou désactiver STONITH (fencing).
    • pacemaker_cluster_resources: Une liste de dictionnaires définissant les ressources du cluster à créer.

Tâches

  1. Add IP address of all hosts : Met à jour le fichier /etc/hosts sur tous les hôtes du cluster pour inclure les adresses IP et noms d'hôte de chaque hôte, facilitant ainsi la résolution de noms au sein du cluster.
  2. Set password of user hacluster : Définit le mot de passe pour l'utilisateur hacluster, qui est utilisé pour l'authentification par les outils de cluster. Le commentaire suggère de stocker ce mot de passe dans un "vault" Ansible pour la sécurité.
  3. Authorize pcs auth : Exécute l'authentification de cluster sur le nœud avec l'adresse IP 10.0.2.10 en utilisant le nom d'utilisateur et le mot de passe hacluster.
  4. Upgrade packages : Met à jour tous les paquets sur les hôtes du cluster pour s'assurer que les dernières mises à jour de sécurité et de logiciel sont appliquées.
  5. Install packages : Installe les paquets nécessaires pour le cluster, y compris pcs, pacemaker, corosync, des agents de clôture et de ressources, ainsi que Apache et PHP.
  6. Create corosync-config : Utilise un template Jinja2 pour configurer Corosync à partir du fichier corosync.conf.j2 et le place dans /etc/corosync/corosync.conf.
  7. Start pacemaker : Démarre le service Pacemaker.
  8. Create index.php et Remove index.html : Gère les fichiers dans le répertoire web d'Apache, en s'assurant que index.php est en place et en supprimant index.html.
  9. Capturing Cluster Resources : Capture la sortie de pcs resource show --full pour vérifier les ressources actuellement gérées par le cluster.
  10. Setting Stonith : Désactive STONITH si pacemaker_disable_stonith est vrai. STONITH est une méthode de fencing critique pour la gestion de cluster.
  11. Creating Cluster Resources : Crée les ressources de cluster spécifiées dans pacemaker_cluster_resources si elles ne sont pas déjà présentes, en utilisant les options fournies.

Handlers

  • Restart corosync : Redémarre le service Corosync si nécessaire, généralement après une modification de configuration.

Points Clés

  • Le playbook utilise des conditions when pour s'assurer que certaines tâches ne s'exécutent que dans des circonstances appropriées, par exemple, l'authentification et la création de ressources ne se produisent que sur le nœud spécifié 10.0.2.10.
  • Les tâches de configuration sont protégées par become: true pour exécuter les commandes avec des privilèges élevés.
  • La gestion des configurations de ressources est dynamique, permettant des modifications faciles via les variables définies au début du playbook.
important

Veillez à ne pas reproduire ce playbook sans mettre le mot de passe de l'utilisateur hacluster dans un vault ansible.

Le template corosync.conf.j2

totem {
  version: 2
  cluster_name: {{ cluster_name }}
  transport: udpu
}

quorum {
  provider: corosync_votequorum
{% if groups['cluster']|count == 2 %}
  two_node: 1
{% else %}
  wait_for_all: 1
  last_man_standing: 1
{% endif %}
}

nodelist {
{% for node in groups['cluster']|sort %}
  node {
    ring0_addr: {{ hostvars[node]['ansible_default_ipv4']['address'] }}
    nodeid: {{ loop.index }}
    name: {{ hostvars[node]['ansible_fqdn'] }}

  }
{% endfor %}
}

logging {
  to_logfile: yes
  logfile: /var/log/corosync/corosync.log
  to_syslog: yes
  timestamp: on
}

Les principaux outils pour gérer des clusters

Il existe deux principaux outils en ligne de commande pour gérer les clusters : crm et pcs.

Utilisation et commandes principales de crm

crm est une interface en ligne de commande pour gérer les clusters qui utilisent le moteur de haute disponibilité Pacemaker. Cet outil est essentiel pour la configuration et la gestion du cluster, permettant aux administrateurs de surveiller, de modifier et de maintenir les paramètres et les ressources du cluster de manière interactive. crm offre une interface complète pour la gestion des clusters, ce qui en fait un choix privilégié pour les configurations complexes et les ajustements fins.

crm status

Cette commande fournit un aperçu de l'état actuel du cluster, y compris l'état des nœuds, des ressources et des contraintes de groupe.

crm configure show

Utilisez cette commande pour afficher la configuration actuelle des ressources du cluster.

crm configure edit <resource_name>

Cette commande permet de modifier la configuration d'une ressource spécifique.

crm node status

Montre le statut de chaque nœud du cluster.

crm configure colocation add <constraint_name> <resource1> with <resource2>

Définit une contrainte de colocation pour que deux ressources soient placées sur le même nœud.

crm configure stonith

Permet de configurer et de gérer les dispositifs STONITH dans le cluster.

Utilisation et commandes principales de pcs

pcs (Pacemaker/Corosync Configuration System) est un outil de gestion de cluster qui simplifie le processus de configuration de clusters utilisant Corosync et Pacemaker. Il fournit une interface de ligne de commande unifiée pour configurer, gérer et visualiser tous les aspects du cluster.

pcs status

Cluster name: my_cluster
Cluster Summary:
  * Stack: corosync
  * Current DC: node2.test.local (version 2.1.2-ada5c3b36e2) - partition with quorum
  * Last updated: Tue May 14 08:37:39 2024
  * Last change:  Tue May 14 06:10:26 2024 by hacluster via crmd on node1.test.local
  * 2 nodes configured
  * 1 resource instance configured

Node List:
  * Online: [ node1.test.local node2.test.local ]

Full List of Resources:
  * webserver   (ocf:heartbeat:apache):  Started node2.test.local

Daemon Status:
  corosync: active/enabled
  pacemaker: active/enabled
  pcsd: active/enabled

Cette commande donne une vue d'ensemble de l'état du cluster, incluant les nœuds, les ressources et les contraintes.

pcs resource create <resource_name> <agent> [options]

Crée une nouvelle ressource avec le type d'agent spécifié et des options configurables.

pcs cluster start --all
pcs cluster stop --all

Ces commandes permettent de démarrer ou d'arrêter tous les nœuds du cluster.

pcs property set stonith-enabled=true

Active ou modifie une propriété du cluster, comme l'activation de STONITH.

pcs constraint colocation add <resource1> with <resource2> [score]

Ajoute une contrainte de colocation entre deux ressources.

Conclusion

Bien que crm et pcs accomplissent des fonctions similaires, pcs est souvent préféré pour sa simplicité et son approche plus direct.

pcs est conçu pour être plus accessible et plus facile à utiliser pour les nouveaux administrateurs de clusters, fournissant des commandes claires et des options de configuration simplifiées. Cela en fait un outil idéal pour les tâches courantes de gestion de clusters, rendant la configuration et la surveillance plus intuitives et moins sujettes aux erreurs.

pcs est conçu pour être plus accessible et plus facile à utiliser pour les nouveaux administrateurs de clusters, fournissant des commandes claires et des options de configuration simplifiées. Cela en fait un outil idéal pour les tâches courantes de gestion de clusters, rendant la configuration et la surveillance plus intuitives et moins sujettes aux erreurs.

Test du cluster provisionné par l'arrêt d'un nœud

Maintenant que notre cluster Corosync et Pacemaker est en place, il est important de tester sa robustesse et sa capacité à gérer les pannes de manière adéquate. Un test fréquent consiste à arrêter un nœud pour observer si le cluster réagit correctement en basculant les ressources comme prévu.

Assurez-vous que toutes vos configurations sont correctes et que toutes les ressources sont opérationnelles avant de commencer le test. Il est également important de s'assurer que toutes les données nécessaires sont sauvegardées pour éviter toute perte en cas de problème durant le test.

Arrêt d'un nœud

Choisissez un nœud à arrêter dans votre cluster (dans mon cas, je choisis le noeud 2). Cette action devrait simuler une panne et forcer le cluster à réagir. Vous pouvez arrêter un nœud de manière contrôlée via la commande suivante :

sudo pcs cluster stop node2.test.local

Vérification du statut du cluster

Après avoir arrêté le nœud, utilisez la commande pcs status pour observer comment le cluster réagit. Cette commande vous fournira une vue d'ensemble de l'état du cluster, y compris le statut des nœuds et des ressources. Voici un exemple de commande et de sortie typique :

pcs status
Cluster name: my_cluster
Cluster Summary:
  * Stack: corosync
  * Current DC: node1.test.local (version 2.1.2-ada5c3b36e2) - partition with quorum
  * Last updated: Tue May 14 10:16:46 2024
  * Last change:  Tue May 14 09:23:11 2024 by hacluster via crmd on node1.test.local
  * 2 nodes configured
  * 1 resource instance configured

Node List:
  * Online: [ node1.test.local ]
  * OFFLINE: [ node2.test.local ]

Full List of Resources:
  * webserver   (ocf:heartbeat:apache):  Started node1.test.local

Daemon Status:
  corosync: active/enabled
  pacemaker: active/enabled
  pcsd: active/enabled

Dans cet exemple, node2 est arrêté et vous pouvez voir que le nœud node1 est en ligne et que la ressource WebServer a basculé sur node1.

Analyse des résultats

Lorsque vous vérifiez le résultat de la commande pcs status, cherchez les points suivants :

  • Le nœud arrêté doit apparaître comme OFFLINE.
  • Les autres nœuds du cluster doivent être Online.
  • Toutes les ressources critiques qui fonctionnaient sur le nœud arrêté devraient maintenant être actives sur un autre nœud, indiquant un basculement réussi.

Conclusion du test

Ce test est crucial pour valider la configuration de haute disponibilité de votre cluster. Il assure que le cluster est capable de gérer les défaillances de nœuds sans interruption du service. Des tests réguliers comme celui-ci aident à maintenir l'intégrité du cluster et à préparer l'équipe de gestion à répondre efficacement aux incidents réels.

Si le cluster ne réagit pas comme prévu, il peut être nécessaire de revoir les configurations des ressources, les politiques de basculement ou même les paramètres réseau du cluster.

Conclusion

Corosync et Pacemaker offrent une fondation solide pour la gestion des clusters de haute disponibilité, adaptée à une large gamme d'applications et de scénarios. En tirant parti de ces outils, les entreprises peuvent considérablement améliorer la résilience et la fiabilité de leurs infrastructures critiques. La mise en œuvre efficace de ces technologies est une compétence précieuse pour tout administrateur système cherchant à optimiser la disponibilité et la performance dans des environnements complexes et exigeants.

La suite

Une adresse IP flottante est importante dans un environnement de haute disponibilité car elle permet aux clients de rester connectés au service actif même en cas de défaillance d'un nœud. Intégrer la gestion d'une IP flottante dans le playbook Ansible renforcerait la résilience du service web géré par Apache dans notre exemple. La configuration d'une IP flottante pourrait être réalisée via les ressources de cluster de Pacemaker, en utilisant un agent de ressource comme ocf:heartbeat:IPaddr2.

Les agents de clôture, ou "fencing", sont essentiels pour garantir que les ressources ne soient pas simultanément actives sur plusieurs nœuds, ce qui peut entraîner des conflits de données. Intégrer le fencing dans le playbook nécessiterait l'installation et la configuration des agents de clôture appropriés. Pour un environnement cloud comme Outscale, cela pourrait impliquer le développement d'un agent de clôture personnalisé adapté aux API et aux mécanismes de contrôle spécifiques d'Outscale.

Un projet futur pourrait inclure le développement d'un agent de fencing spécifique pour le cloud Outscale. Cet agent assurerait que les instances défaillantes soient correctement isolées pour éviter tout risque de "split-brain" ou d'autres problèmes liés à la cohérence des données. Ce développement nécessiterait une compréhension approfondie de l'API Outscale et des mécanismes de gestion de l'infrastructure virtuelle.

Plus d'infos