Pourquoi ?

Suite à l'article précédent sur la mise en place d'un cluster Keepalived, un problème se présentait à moi. Si j'ai bien un cluster fonctionnel de serveurs Nginx, je n'ai cependant pas de configuration redondante. Si je met à jour un site ou que j'ajoute un certificat, je dois penser à changer la configuration de l'autre côté, avec ce que cela inclut comme oubli ou risque d'erreur de frappe. Alors, il fallait que je réfléchisse comment faire pour que tout cela s'automatise.

Comment fait-on ?

Mes deux reverse proxy sont uniquement des reverse proxy, ils n'hébergent aucun site. Ils portent des certificats, des définitions de sites web, et c'est tout.

Mais il est important aussi pour moi d'avoir des informations de supervision. Je vais donc créer un micro-site qui donnera le nom de l'hôte sur l'adresse IP du routeur VRPP Keepalived.

Il va me falloir donc synchroniser les fichiers présents dans /etc/nginx (pour les configurations du serveur web et des sites), ceux dans /etc/letsencrypt (pour les certificats et les informations de renouvellement) et ceux de /var/www (pour le fameux micro-site précisé juste au dessus).

Mais il me fallait aussi réfléchir à la manière dont les configurations allaient se synchroniser : idéalement, il faudrait que les informations marchent toujours dans le même sens, que je n'ai qu'à toucher un seul et même serveur pour m'assurer que la synchro se fasse bien. J'ai donc décidé que la configuration serait tirée par le backup depuis le master, en tâche de fond, et pour ce faire il fallait tout d'abord pouvoir effectuer de la connexion SSH sans mot de passe via clé.

L'outil pour synchroniser le tout m'apparaissait clair : rsync. Rapide, fiable, scriptable, on peut lui présenter des clés de connexion, c'était l'outil idéal.

Mais pour arriver à savoir qui est backup et qui est master, il me fallait plus d'informations. Lorsque je regardais la première configuration de Keepalived, j'avais remarqué des options pour présenter des informations depuis le SNMP. C'est par ce biais que l'on connaîtra qui tient le rôle.

Lançons nous !

Tout d'abord, il nous faut quelques prérequis.

Le micro-site (facultatif)

C'est purement pour la supervision. Installez php ainsi que php-fpm et créer un fichier index.php dans /var/www/dossier_de_votre_choix/

Ajoutez-y ce contenu

<?php
$host = gethostname();
$array = Array ( "host" => $host);
echo json_encode($array);
?>

Créez ensuite un fichier de site (ici keepalived.conf) dans /etc/nginx/sites-available/

Pensez bien à mettre un nom dans server_name qui vous va, et également de créer cette entrée dans votre DNS.

server {
    listen 80 default;
    listen [::]:80 default;
    server_name reverse-ha.local;
    add_header  Content-Type    application/json;
    default_type application/json;
         location / {
            add_header  Content-Type    application/json;
            try_files $uri /index.php$is_args$args;
         }

         location ~ \.php$ {
            fastcgi_split_path_info ^(.+\.php)(/.+)$;
            fastcgi_pass unix:/var/run/php/php-fpm.sock;
            fastcgi_index index.php;
            include fastcgi.conf;
        }
root /var/www/keepalived;

    error_log /var/log/nginx/keepalived.err;
}

Créez le lien symbolique :

sudo ln -s /etc/nginx/sites-available/keepalived.conf /etc/nginx/sites-enabled

Vérifiez votre configuration :

sudo nginx -t

Rechargez la conf si tout est ok :

sudo systemctl reload nginx

La configuration SNMP pour Keepalived

Modifiez le fichier /etc/default/keepalived, pour ajouter dans DAEMON_ARGS la valeur -x (-x ou --snmp active le SNMP)

DAEMON_ARGS="-x"

Installez snmp, snmpd et snmp-dowload-mibs (disponibles sur les repos non-free sur Debian)

sudo apt install snmp snmpd snmpd-download-mibs -y

Modifiez ensuite votre fichier snmp.conf pour permettre de charger les mibs externes.

Décommentez "mibsdirs" et changez la ligne "mibs" en :

mibs +/usr/share/snmp/mibs/KEEPALIVED-MIB.txt

Modifiez /etc/snmp/snmpd.conf pour y ajouter :

rocommunity public

Redémarrez ensuite snmpd et keepalived

sudo systemctl restart keepalived
sudo systemctl restart snmpd

Attendez quelques instants, puis testez avec snmp d'obtenir l'information de l'état de l'instance

root@reverseproxy-1:~# snmpget -v2c -c public 127.0.0.1 KEEPALIVED-MIB::vrrpInstanceState.1
KEEPALIVED-MIB::vrrpInstanceState.1 = INTEGER: master(2)

Nous voyons ici que l'instance est master. Mais nous voyons également que la valeur "master" est polluée par pas mal d'informations. Nous allons donc faire une petite regex pour que sed puisse avoir la bonne information.

root@reverseproxy-1:~# snmpget -v2c -c public 127.0.0.1 KEEPALIVED-MIB::vrrpInstanceState.1 | sed -Er 's/(.*)INTEGER: (.*)\(([0-9])\)/\2/g'
master

La configuration rsync

Maintenant que nous avons l'ensemble des briques, nous allons pouvoir scripter ça. Je vous fournis directement le code, commenté. Enregistrez ce script dans le crontab d'un utilisateur avec suffisament de droits, au rythme que vous souhaitez. N'oubliez pas de préciser /bin/bash en tant que shell car crontab ne prend pas le shebang de début de script en considération (exemple : */10 * * * * /bin/bash /root/sync_nginx.sh > /root/nginx_sync.log ).

Vous pouvez télécharger le script sur mon espace git personnel.

#!/bin/bash
KEYPATH="/root/.ssh/reverseproxy2"
REMOTEHOST="reverseproxy-2.domaine"

# La synchro se fait par une récupération depuis le backup de master.
# Si keepalived est master, on ne fait pas de synchro
STATE=`/bin/snmpget -v2c -c public 127.0.0.1 KEEPALIVED-MIB::vrrpInstanceState.1 | /bin/sed -Er 's/(.*)INTEGER: (.*)\(([0-9])\)/\2/g'`
echo "State : ${STATE}"
if [[ "$STATE" == "master" ]]; then
 echo "Master : No sync"
 exit 2
fi

# Si keepalived est down, on ne fait pas de synchro (maintenance)
systemctl is-active --quiet keepalived
if [ $? -ne 0 ]; then
  echo "Keepalived down : no sync"
  exit 0
fi
echo "Run sync nginx"
RSYNCNGINX=$(/bin/rsync -e "ssh -i $KEYPATH" -aiuh root@$REMOTEHOST:/etc/nginx/ /etc/nginx)
if [ $? -eq 0 ]; then

echo "Run sync Let's Encrypt'"
 RSYNCLE=$(/bin/rsync -e "ssh -i $KEYPATH" -aiuh root@$REMOTEHOST:/etc/letsencrypt/ /etc/letsencrypt)
else 
 exit 3
fi

if [ $? -eq 0 ]; then 
 echo "Run sync www"
 RSYNCWWW=$(/bin/rsync -e "ssh -i $KEYPATH" -aiuh root@$REMOTEHOST:/var/www/ /var/www)
else
 exit 2
fi

if [ $? -eq 0 ]; then 
  if [ -n "${RSYNCNGINX}" ] || [ -n "${RSYNCWWW}" ]; then
     /usr/sbin/nginx -s reload
     echo "reloaded."
  fi
else
  exit 1
fi

Supervision du changement d'IP

Maintenant que tout est prêt, on peut aller créer la config dans Zabbix.

J'ai créé un hôte dans Zabbix qui pointe sur l'adresse VIP partagée entre les noeuds.

J'y ai créé un élément, qui est la récupération du fichier .json créé par les micro-sites web sur chaque noeud.

Screenshot_20231203_163329

Screenshot_20231203_163607

Sur cet élément, je n'ai qu'un seul déclencheur nommé "Changement porteur VIP", qui surveille la différence entre l'actuelle et la dernière valeur qui est renvoyée par le micro-site.

last(/reverse-ha.maison/vip_owner)<>last(/reverse-ha.maison/vip_owner,#2)

Et lorsqu'un problème arrive, j'ai mes notifications qui s'enclenchent.

reverse-ha.maison Problem: Changement porteur VIP
Problem started at 13:03:32 on 2023.12.03
Problem name: Changement porteur VIP
Host: reverse-ha.maison
Severity: Warning
Operational data: reverseproxy-1
Original problem ID: 1377405

Ajouter un commentaire

Article précédent Article suivant