Aller au contenu
Cloud medium

Haute Dispo avec EIP Flottante sur Outscale

34 min de lecture

logo 3ds outscale

Ce guide présente la mise en place d’une infrastructure haute disponibilité sur Outscale. L’objectif est de fournir un point d’entrée unique capable de basculer automatiquement entre deux nœuds situés dans des zones de disponibilité différentes. La solution combine Terraform pour le provisionnement, Ansible pour la configuration, et un cluster Corosync/Pacemaker en mode actif/passif avec une EIP flottante gérée dynamiquement.

L’architecture repose sur une approche multi-zones pour maximiser la résilience. Chaque zone (eu-west-2a et eu-west-2b) héberge un VPC distinct avec un nœud HAProxy et un serveur web Nginx. Cette séparation physique garantit qu’une défaillance d’une zone entière n’affecte pas le service.

Le cœur du système est l’EIP flottante qui constitue le point d’accès unique. Cette adresse IP publique statique peut être attachée et détachée dynamiquement, maintenant ainsi la continuité même en cas de panne. Cette solution utilise exclusivement des primitives Outscale sans dépendre de services managés, la rendant adaptée aux environnements souverains.

Un VPC Peering interconnecte les deux réseaux, permettant au cluster de communiquer et aux HAProxy d’accéder aux backends dans l’autre zone tout en préservant l’isolation réseau.

Internet
Elastic IP (EIP)
80.247.2.238
┌────────┴ ─ ─ ─ ─ ─┐
HAProxy A HAProxy B
(Actif) (Passif)
│ │
Web A Web B
Nginx Nginx
│ │
eu-west-2a eu-west-2b
└──── VPC Peering ───┘

L’EIP pointe en permanence vers un seul HAProxy, celui désigné comme actif par le gestionnaire de cluster Pacemaker. Les backends Nginx sont répartis sur les deux zones et restent accessibles via le peering, garantissant ainsi que le HAProxy actif peut toujours distribuer la charge vers les serveurs disponibles, quelle que soit leur localisation.

Le système repose sur plusieurs composants détaillés dans le guide Corosync/Pacemaker. Corosync assure la communication inter-nœuds et détecte les pannes, tandis que Pacemaker orchestre les ressources et décide des actions correctives.

Pour un cluster à deux nœuds, l’option two_node: 1 dans Corosync adapte le comportement du quorum pour permettre au cluster de fonctionner avec un seul nœud actif en cas de perte de communication.

L’EIP est la ressource critique. Lorsque Pacemaker détecte une défaillance (nœud injoignable ou HAProxy défaillant), il détache automatiquement l’EIP du nœud problématique et la réattache au nœud secondaire avec un temps d’interruption minimal.

Provisionnement de l’infrastructure avec Terraform

Section intitulée « Provisionnement de l’infrastructure avec Terraform »

Le provisionnement suit une approche méthodique détaillée dans le guide Infrastructure as Code. La configuration du backend Terraform sur un bucket S3 Outscale garantit que l’état reste accessible et partageable, ce qui est essentiel en production.

terraform {
backend "s3" {
# Configuration du backend pour stocker l'état Terraform
bucket = "tf-state-ha"
key = "ha/terraform.tfstate"
endpoint = "https://oos.eu-west-2.outscale.com"
region = "eu-west-2"
}
}

Chaque zone reçoit un VPC avec un bloc CIDR distinct : 10.0.0.0/24 pour la zone A et 10.0.1.0/24 pour la zone B, évitant tout conflit d’adressage.

resource "outscale_vpc" "vpc_a" {
# VPC pour la zone de disponibilité A
cidr_block = "10.0.0.0/24"
tags = {
Name = "vpc-ha-zone-a"
}
}
resource "outscale_vpc" "vpc_b" {
# VPC pour la zone de disponibilité B
cidr_block = "10.0.1.0/24"
tags = {
Name = "vpc-ha-zone-b"
}
}

Le VPC Peering crée une connexion bidirectionnelle mais ne configure pas automatiquement les routes. Il faut explicitement les ajouter dans les tables de routage de chaque VPC.

resource "outscale_net_peering" "peer" {
# Création du peering entre les deux VPC
source_net_id = outscale_vpc.vpc_a.net_id
acceptor_net_id = outscale_vpc.vpc_b.net_id
tags = {
Name = "peering-ha"
}
}
resource "outscale_route" "a_to_b" {
# Route du VPC A vers le VPC B via le peering
net_id = outscale_vpc.vpc_a.net_id
destination_ip_range = "10.0.1.0/24"
gateway_id = outscale_net_peering.peer.net_peering_id
}
resource "outscale_route" "b_to_a" {
# Route du VPC B vers le VPC A via le peering
net_id = outscale_vpc.vpc_b.net_id
destination_ip_range = "10.0.0.0/24"
gateway_id = outscale_net_peering.peer.net_peering_id
}

Les Security Groups définissent les règles pare-feu. Ports obligatoires : UDP 5404-5405 (Corosync), TCP 2224 et 3121 (Pacemaker), TCP 80 (HAProxy) et TCP 22 (SSH depuis bastion).

resource "outscale_security_group" "cluster_sg" {
description = "Security Group pour le cluster HA"
net_id = outscale_vpc.vpc_a.net_id
# Port SSH depuis le bastion
ingress {
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = ["10.0.0.0/16"]
}
# Ports Corosync
ingress {
from_port = 5404
to_port = 5405
protocol = "udp"
cidr_blocks = ["10.0.0.0/16", "10.0.1.0/16"]
}
# Ports Pacemaker
ingress {
from_port = 2224
to_port = 2224
protocol = "tcp"
cidr_blocks = ["10.0.0.0/16", "10.0.1.0/16"]
}
ingress {
from_port = 3121
to_port = 3121
protocol = "tcp"
cidr_blocks = ["10.0.0.0/16", "10.0.1.0/16"]
}
# Port HTTP depuis Internet
ingress {
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
}

Les instances utilisent une image Packer personnalisée et reçoivent des tags (Role, Zone, Type) pour l’inventaire dynamique Ansible.

resource "outscale_vm" "haproxy_a" {
# Nœud HAProxy dans la zone A
keypair_name = outscale_keypair.main.keypair_name
image_id = var.rocky_image
instance_type = "tinav5.c2r4p2"
subnet_id = outscale_subnet.subnet_a.id
security_group_ids = [outscale_security_group.cluster_sg.id]
tags = {
Name = "haproxy-a"
Role = "haproxy"
Zone = "a"
Type = "cluster-node"
}
}
resource "outscale_vm" "haproxy_b" {
# Nœud HAProxy dans la zone B
keypair_name = outscale_keypair.main.keypair_name
image_id = var.rocky_image
instance_type = "tinav5.c2r4p2"
subnet_id = outscale_subnet.subnet_b.id
security_group_ids = [outscale_security_group.cluster_sg.id]
tags = {
Name = "haproxy-b"
Role = "haproxy"
Zone = "b"
Type = "cluster-node"
}
}

L’EIP est réservée mais non attachée lors du provisionnement. Pacemaker gérera l’attachement dynamique une fois le cluster configuré, évitant ainsi les conflits.

resource "outscale_public_ip" "eip" {
# Réservation de l'EIP sans attachement initial
# Pacemaker gérera l'attachement dynamique
tags = {
Name = "eip-ha-cluster"
}
}
output "elastic_ip" {
description = "Adresse IP publique pour l'accès au cluster"
value = outscale_public_ip.eip.public_ip
}

Ansible automatise la configuration du cluster de la préparation système à la déclaration des ressources Pacemaker.

L’inventaire dynamique utilise le plugin aws_ec2 compatible avec l’API Outscale. Point critique : utilisation des adresses IP privées pour éviter les incohérences liées à la bascule de l’EIP. Les connexions SSH passent par le bastion via ProxyJump.

# Inventaire dynamique aws_ec2.yml
plugin: amazon.aws.aws_ec2
aws_profile: outscale
regions:
- eu-west-2
# Utilisation des IP privées pour éviter les conflits avec l'EIP flottante
compose:
ansible_host: private_ip_address
# Organisation en groupes basée sur les tags
keyed_groups:
- key: tags.Role
separator: ''
- key: tags.Zone
separator: ''
- key: tags.Type
separator: ''
# Configuration du bastion comme jump host
ansible_ssh_common_args: '-o ProxyJump=bastion.example.com'

La préparation système installe les packages requis (Corosync, Pacemaker, pcs, HAProxy), désactive le firewall local (filtrage géré par Security Groups) et configure les hostnames avec mise à jour de /etc/hosts pour la résolution DNS locale.

- name: Préparation système pour le cluster
hosts: cluster-node
become: true
tasks:
- name: Installation des packages nécessaires
package:
name:
- corosync
- pacemaker
- pcs
- haproxy
state: present
- name: Désactivation du firewall
# Le firewall est désactivé car les Security Groups gèrent déjà le filtrage
systemd:
name: firewalld
enabled: false
state: stopped
- name: Configuration du hostname
hostname:
name: "{{ inventory_hostname }}.cluster.local"
- name: Mise à jour de /etc/hosts
# Ajout de tous les nœuds du cluster pour la résolution DNS locale
lineinfile:
dest: /etc/hosts
line: "{{ hostvars[item].ansible_host }} {{ item }}.cluster.local {{ item }}"
state: present
loop: "{{ groups['cluster-node'] }}"

Les routes statiques OS sont indispensables pour la communication Corosync via le peering. Important : Terraform configure les routes VPC mais elles ne sont pas automatiquement appliquées dans l’OS. Ansible crée des fichiers de route persistants.

- name: Configuration des routes pour le peering
hosts: cluster-node
become: true
vars:
# Gateway par défaut du sous-réseau
gateway_ip: "{{ ansible_default_ipv4.gateway }}"
tasks:
- name: Configuration de route statique vers l'autre zone
# Création d'un fichier de route persistant
copy:
dest: /etc/sysconfig/network-scripts/route-eth0
content: |
# Route vers la zone {{ 'B' if 'a' in inventory_hostname else 'A' }}
{{ '10.0.1.0/24' if 'a' in inventory_hostname else '10.0.0.0/24' }} via {{ gateway_ip }}
mode: '0644'
notify: Redémarrage réseau
handlers:
- name: Redémarrage réseau
systemd:
name: network
state: restarted

La CLI Outscale (osc-cli) est configurée pour l’agent OCF. Les credentials sont stockés dans Ansible Vault et déployés dans /root/.osc/config.json. Seul root nécessite cette configuration car Pacemaker exécute les agents sous cette identité.

- name: Configuration de la CLI Outscale
hosts: cluster-node
become: true
vars_files:
- vars/vault.yml
tasks:
- name: Création du répertoire de configuration
file:
path: /root/.osc
state: directory
mode: '0700'
- name: Déploiement du fichier de configuration
# Template contenant les credentials depuis le vault
template:
src: config.json.j2
dest: /root/.osc/config.json
mode: '0600'
no_log: true

La récupération dynamique de l’EIP via l’API Outscale évite le codage en dur et rend les playbooks réutilisables.

- name: Récupération de l'adresse EIP
hosts: localhost
connection: local
tasks:
- name: Interrogation de l'API pour obtenir l'EIP
shell: |
osc-cli api ReadPublicIps \
--profile default \
--Filters.Tags '[{"Key": "Name", "Values": ["eip-ha-cluster"]}]' \
--query 'PublicIps[0].PublicIp' \
--output text
register: eip_result
changed_when: false
- name: Sauvegarde de l'EIP comme fait
set_fact:
cluster_eip: "{{ eip_result.stdout }}"
cacheable: true

La configuration Corosync définit la topologie cluster. Le transport udpu (UDP unicast) est préféré en cloud. Chaque nœud a une IP privée et un nodeid unique. L’option two_node: 1 est fondamentale pour le quorum à deux nœuds.

# Template corosync.conf.j2
totem {
version: 2
cluster_name: ha-cluster
transport: udpu
interface {
ringnumber: 0
# Utilisation du réseau privé pour la communication cluster
bindnetaddr: {{ ansible_default_ipv4.address }}
broadcast: yes
mcastport: 5405
}
}
nodelist {
# Déclaration explicite de chaque nœud du cluster
node {
ring0_addr: 10.0.0.10
name: haproxy-a
nodeid: 1
}
node {
ring0_addr: 10.0.1.10
name: haproxy-b
nodeid: 2
}
}
quorum {
provider: corosync_votequorum
# Configuration spécifique pour un cluster à deux nœuds
two_node: 1
}
logging {
to_logfile: yes
logfile: /var/log/corosync/corosync.log
to_syslog: yes
timestamp: on
}

Ordre de démarrage : CorosyncPacemakerpcsd (daemon pour gestion via pcs). Ansible active aussi le démarrage automatique au boot.

- name: Démarrage des services cluster
hosts: cluster-node
become: true
tasks:
- name: Démarrage de Corosync
systemd:
name: corosync
enabled: true
state: started
- name: Démarrage de Pacemaker
# Pacemaker doit démarrer après Corosync
systemd:
name: pacemaker
enabled: true
state: started
- name: Démarrage de pcsd
# Nécessaire pour la gestion via pcs
systemd:
name: pcsd
enabled: true
state: started

L’authentification cluster utilise un mot de passe hacluster identique sur tous les nœuds. La commande pcs host auth établit la confiance mutuelle.

- name: Configuration de l'authentification cluster
hosts: cluster-node
become: true
vars_files:
- vars/vault.yml
tasks:
- name: Définition du mot de passe hacluster
user:
name: hacluster
password: "{{ hacluster_password | password_hash('sha512') }}"
- name: Authentification des nœuds
# Exécuté depuis un seul nœud pour configurer tout le cluster
command: >
pcs host auth
haproxy-a.cluster.local
haproxy-b.cluster.local
-u hacluster
-p {{ hacluster_password }}
run_once: true
delegate_to: "{{ groups['cluster-node'][0] }}"

Les ressources Pacemaker constituent le cœur de la configuration. HAProxy utilise l’agent systemd, tandis que l’EIP utilise un agent OCF personnalisé. Les contraintes garantissent la colocation (EIP + HAProxy sur même nœud) et l’ordre de démarrage.

- name: Configuration des ressources Pacemaker
hosts: cluster-node
become: true
run_once: true
delegate_to: "{{ groups['cluster-node'][0] }}"
tasks:
- name: Création de la ressource HAProxy
# Utilisation de l'agent systemd pour gérer HAProxy
command: >
pcs resource create haproxy systemd:haproxy
op monitor interval=30s timeout=20s
op start timeout=60s
op stop timeout=60s
args:
creates: /var/lib/pacemaker/cib/.haproxy_created
- name: Création de la ressource EIP
# Agent OCF personnalisé pour gérer l'Elastic IP
command: >
pcs resource create ElasticIP ocf:custom:osc-eip
ip="{{ cluster_eip }}"
op monitor interval=30s timeout=60s
op start timeout=120s
op stop timeout=60s
args:
creates: /var/lib/pacemaker/cib/.eip_created
- name: Contrainte de colocation
# L'EIP doit toujours être sur le même nœud que HAProxy
command: >
pcs constraint colocation add ElasticIP with haproxy INFINITY
- name: Contrainte d'ordre
# HAProxy doit démarrer avant l'attachement de l'EIP
command: >
pcs constraint order haproxy then ElasticIP

La configuration HAProxy utilise un template Jinja2 qui génère dynamiquement la liste des backends depuis l’inventaire Ansible, incluant tous les serveurs web multi-zones.

# Template haproxy.cfg.j2
global
log /dev/log local0
chroot /var/lib/haproxy
stats socket /run/haproxy/admin.sock mode 660 level admin
stats timeout 30s
user haproxy
group haproxy
daemon
defaults
log global
mode http
option httplog
option dontlognull
timeout connect 5000
timeout client 50000
timeout server 50000
frontend http-in
bind *:80
default_backend webservers
backend webservers
balance roundrobin
# Génération dynamique des backends depuis l'inventaire
{% for host in groups['webservers'] %}
server {{ host }} {{ hostvars[host].ansible_host }}:80 check inter 2000 rise 2 fall 3
{% endfor %}

L’agent OCF personnalisé fait le pont entre Pacemaker et l’API Outscale. Il implémente les opérations start, stop, monitor et meta-data selon les conventions OCF.

Déployé dans /usr/lib/ocf/resource.d/custom/osc-eip, il utilise des fonctions bash avec des codes de retour OCF stricts pour que Pacemaker interprète correctement l’état de la ressource.

/usr/lib/ocf/resource.d/custom/osc-eip
#!/bin/bash
# Agent OCF pour la gestion de l'Elastic IP Outscale
# En-têtes OCF obligatoires
: ${OCF_FUNCTIONS_DIR=${OCF_ROOT}/lib/heartbeat}
. ${OCF_FUNCTIONS_DIR}/ocf-shellfuncs
# Codes de retour OCF standards
OCF_SUCCESS=0
OCF_ERR_GENERIC=1
OCF_ERR_ARGS=2
OCF_ERR_UNIMPLEMENTED=3
OCF_ERR_PERM=4
OCF_ERR_INSTALLED=5
OCF_ERR_CONFIGURED=6
OCF_NOT_RUNNING=7
# Récupération des paramètres de la ressource
EIP="${OCF_RESKEY_ip}"
PROFILE="${OCF_RESKEY_profile:-default}"
# Fonction pour obtenir l'ID de l'instance locale
get_instance_id() {
# Utilise les métadonnées d'instance Outscale
curl -s http://169.254.169.254/latest/meta-data/instance-id
}
# Fonction start: attache l'EIP à cette instance
eip_start() {
local instance_id=$(get_instance_id)
ocf_log info "Attachement de l'EIP ${EIP} à l'instance ${instance_id}"
# Appel à l'API Outscale pour attacher l'EIP
osc-cli api LinkPublicIp \
--profile "${PROFILE}" \
--PublicIp "${EIP}" \
--VmId "${instance_id}" \
2>&1 | ocf_log debug
if [ $? -eq 0 ]; then
ocf_log info "EIP ${EIP} attachée avec succès"
return ${OCF_SUCCESS}
else
ocf_log err "Échec de l'attachement de l'EIP ${EIP}"
return ${OCF_ERR_GENERIC}
fi
}
# Fonction stop: détache l'EIP
eip_stop() {
ocf_log info "Détachement de l'EIP ${EIP}"
# Appel à l'API pour détacher l'EIP
osc-cli api UnlinkPublicIp \
--profile "${PROFILE}" \
--PublicIp "${EIP}" \
2>&1 | ocf_log debug
if [ $? -eq 0 ]; then
ocf_log info "EIP ${EIP} détachée avec succès"
return ${OCF_SUCCESS}
else
ocf_log warn "Échec du détachement de l'EIP ${EIP}"
# On retourne SUCCESS même en cas d'échec car l'EIP peut déjà être détachée
return ${OCF_SUCCESS}
fi
}
# Fonction monitor: vérifie que l'EIP est attachée à cette instance
eip_monitor() {
local instance_id=$(get_instance_id)
# Interroge l'API pour connaître l'état actuel de l'EIP
local attached_instance=$(osc-cli api ReadPublicIps \
--profile "${PROFILE}" \
--Filters.PublicIps "[\"${EIP}\"]" \
--query 'PublicIps[0].VmId' \
--output text)
if [ "${attached_instance}" = "${instance_id}" ]; then
ocf_log debug "EIP ${EIP} correctement attachée à ${instance_id}"
return ${OCF_SUCCESS}
elif [ -z "${attached_instance}" ] || [ "${attached_instance}" = "None" ]; then
ocf_log info "EIP ${EIP} non attachée"
return ${OCF_NOT_RUNNING}
else
ocf_log warn "EIP ${EIP} attachée à une autre instance: ${attached_instance}"
return ${OCF_NOT_RUNNING}
fi
}
# Fonction meta-data: décrit la ressource pour Pacemaker
eip_meta_data() {
cat <<END
<?xml version="1.0"?>
<!DOCTYPE resource-agent SYSTEM "ra-api-1.dtd">
<resource-agent name="osc-eip">
<version>1.0</version>
<longdesc lang="fr">
Agent OCF pour gérer une Elastic IP Outscale dans un cluster Pacemaker.
Cet agent permet d'attacher/détacher dynamiquement une EIP en fonction
de l'état du cluster.
</longdesc>
<shortdesc lang="fr">Gestion d'une Elastic IP Outscale</shortdesc>
<parameters>
<parameter name="ip" unique="1" required="1">
<longdesc lang="fr">
Adresse IP publique élastique à gérer
</longdesc>
<shortdesc lang="fr">Elastic IP</shortdesc>
<content type="string" />
</parameter>
<parameter name="profile" unique="0" required="0">
<longdesc lang="fr">
Profil de configuration osc-cli à utiliser (par défaut: default)
</longdesc>
<shortdesc lang="fr">Profil osc-cli</shortdesc>
<content type="string" default="default" />
</parameter>
</parameters>
<actions>
<action name="start" timeout="120s" />
<action name="stop" timeout="60s" />
<action name="monitor" timeout="60s" interval="30s" depth="0" />
<action name="meta-data" timeout="5s" />
</actions>
</resource-agent>
END
}
# Point d'entrée principal
case "${1}" in
start)
eip_start
;;
stop)
eip_stop
;;
monitor)
eip_monitor
;;
meta-data)
eip_meta_data
;;
validate-all)
# Validation de la configuration
if [ -z "${EIP}" ]; then
ocf_log err "Paramètre 'ip' obligatoire manquant"
exit ${OCF_ERR_CONFIGURED}
fi
exit ${OCF_SUCCESS}
;;
*)
echo "Usage: ${0} {start|stop|monitor|meta-data|validate-all}"
exit ${OCF_ERR_UNIMPLEMENTED}
;;
esac
exit $?

L’agent nécessite les permissions API : LinkPublicIp, UnlinkPublicIp et ReadPublicIps. Recommandation : créer un utilisateur dédié avec politique IAM restrictive.

Le déploiement Ansible copie le script, le rend exécutable (chmod 755) et vérifie son fonctionnement.

- name: Déploiement de l'agent OCF EIP
hosts: cluster-node
become: true
tasks:
- name: Création du répertoire pour les agents personnalisés
file:
path: /usr/lib/ocf/resource.d/custom
state: directory
mode: '0755'
- name: Copie de l'agent OCF
copy:
src: files/osc-eip
dest: /usr/lib/ocf/resource.d/custom/osc-eip
mode: '0755'
- name: Vérification de l'agent
# Test que l'agent répond correctement à meta-data
command: /usr/lib/ocf/resource.d/custom/osc-eip meta-data
register: agent_test
failed_when: agent_test.rc != 0
changed_when: false

La surveillance est essentielle. La commande pcs status fournit une vue d’ensemble : état des nœuds, ressources et contraintes. C’est le premier réflexe en cas de problème.

Fenêtre de terminal
# Vérification de l'état global du cluster
pcs status
Cluster name: ha-cluster
Cluster Summary:
* Stack: corosync
* Current DC: haproxy-a (version 2.0.5-9) - partition with quorum
* Last updated: Sun Jan 15 10:30:45 2024
* Last change: Sun Jan 15 09:15:20 2024
* 2 nodes configured
* 2 resource instances configured
Node List:
* Online: [ haproxy-a haproxy-b ]
Full List of Resources:
* haproxy (systemd:haproxy): Started haproxy-a
* ElasticIP (ocf::custom:osc-eip): Started haproxy-a
Daemon Status:
corosync: active/enabled
pacemaker: active/enabled
pcsd: active/enabled

La commande crm_mon offre une surveillance temps réel (option -1 pour vue instantanée). Les logs sont essentiels au diagnostic :

  • Corosync : /var/log/corosync/corosync.log (communication, détection pannes)
  • Pacemaker : journalctl -u pacemaker (décisions ressources, basculements)
  • HAProxy : journalctl -u haproxy (trafic)
Fenêtre de terminal
# Surveillance des logs Pacemaker en temps réel
journalctl -u pacemaker -f
# Logs Corosync pour déboguer la communication cluster
tail -f /var/log/corosync/corosync.log
# Logs HAProxy pour analyser le trafic
journalctl -u haproxy -f

Les fail-counts et migration-threshold (détaillés dans le guide Corosync/Pacemaker) gèrent les échecs. Pacemaker incrémente le compteur à chaque échec. Atteinte du seuil = basculement automatique. Réinitialisation via pcs resource cleanup.

Fenêtre de terminal
# Consultation des compteurs d'échecs
pcs resource failcount show
# Réinitialisation du compteur pour une ressource spécifique
pcs resource cleanup ElasticIP
# Réinitialisation globale de tous les compteurs
pcs resource cleanup

Pour la maintenance, mettre un nœud en standby via pcs node standby déplace les ressources sans alarmes. Le rechargement HAProxy (systemctl reload) se fait sans interruption ni détection d’échec par Pacemaker.

Fenêtre de terminal
# Rechargement de la configuration HAProxy sans interruption
systemctl reload haproxy
# Vérification que Pacemaker voit toujours la ressource comme active
pcs resource show haproxy --full

Cause la plus fréquente de dysfonctionnement. Vérifier les routes réseau OS avec ip route show et ping. Contrôler l’ouverture des ports UDP 5404-5405.

Fenêtre de terminal
# Vérification des routes configurées
ip route show
# Test de connectivité vers l'autre nœud
ping -c 3 10.0.1.10
# Vérification que les ports Corosync sont ouverts
nc -zu 10.0.1.10 5404
nc -zu 10.0.1.10 5405

Généralement : authentification API ou erreurs agent OCF. Tester avec pcs resource debug-monitor ElasticIP et vérifier les credentials osc-cli.

Fenêtre de terminal
# Test manuel de l'agent OCF
/usr/lib/ocf/resource.d/custom/osc-eip monitor
# Vérification des logs de la ressource
pcs resource debug-monitor ElasticIP
# Test de l'API Outscale avec osc-cli
osc-cli api ReadPublicIps --profile default

Corosync est sensible aux décalages d’horloge. Utiliser NTP ou chrony est indispensable (timedatectl status pour vérifier).

Fenêtre de terminal
# Vérification de l'heure système
timedatectl status
# Synchronisation immédiate avec NTP
chronyc makestep
# Activation de la synchronisation automatique
systemctl enable --now chronyd

Vérifier : connectivité réseau, Security Groups, santé services Nginx. Utiliser socat pour consulter les stats HAProxy.

Fenêtre de terminal
# Consultation des statistiques HAProxy
echo "show stat" | socat stdio /run/haproxy/admin.sock
# Test de connectivité vers un backend
curl -v http://10.0.0.20:80
# Vérification des health checks
pcs resource show haproxy --full | grep monitor

Situation rare avec bonne config. Solution : arrêter un nœud, vérifier l’autre, puis redémarrer pour resynchronisation.

Fenêtre de terminal
# Arrêt complet d'un nœud
pcs cluster stop haproxy-b
# Vérification sur l'autre nœud
pcs status
# Redémarrage du nœud arrêté
pcs cluster start haproxy-b

Améliore drastiquement la stabilité avec quorum natif. Retirer two_node: 1 et le cluster tolère l’isolation d’un nœud sans split-brain.

Amélioration majeure : isolation complète du nœud défaillant avant basculement, éliminant les corruptions de données. Nécessite un agent fencing pour API Outscale.

  • TLS : termination sur HAProxy ou passthrough, automatisable avec Let’s Encrypt
  • Monitoring : Prometheus + Grafana pour métriques HAProxy, Corosync et Pacemaker
  • Multi-applications : frontends HAProxy multiples avec contraintes colocation
  • Persistance : DRBD pour réplication volumes entre nœuds, géré par Pacemaker

Cette architecture démontre qu’une infrastructure haute disponibilité robuste et souveraine est possible sur Outscale CloudGouv sans dépendre de services managés. L’approche multi-AZ avec VPC Peering offre une excellente résilience, tandis que le cluster Corosync/Pacemaker garantit des basculements automatiques rapides.

L’automatisation complète (Terraform + Ansible) rend cette infrastructure reproductible et maintenable, réduisant considérablement les erreurs humaines.

L’EIP flottante gérée par un agent OCF personnalisé illustre la flexibilité de l’open source : un mécanisme de basculement en quelques centaines de lignes, parfaitement intégré aux primitives Outscale.

Cette solution constitue une base solide pour des environnements de production critiques nécessitant un contrôle complet de la pile, extensible selon les besoins (fencing, TLS, nœuds supplémentaires, multi-services).

Ce site vous est utile ?

Sachez que moins de 1% des lecteurs soutiennent ce site.

Je maintiens +700 guides gratuits, sans pub ni tracing. Aujourd'hui, ce site ne couvre même pas mes frais d'hébergement, d'électricité, de matériel, de logiciels, mais surtout de cafés.

Un soutien régulier, même symbolique, m'aide à garder ces ressources gratuites et à continuer de produire des guides de qualité. Merci pour votre appui.

Abonnez-vous et suivez mon actualité DevSecOps sur LinkedIn