Chez JL

Joliciel Libre

Accueil > Informatique > Haute Disponibilité > Heartbeat

Heartbeat

vendredi 22 octobre 2010

Sources :
- linux-ha.org
- http://opendoor.fr/
- http://te.to/ ts1/xen_cluster.html
- http://doc.ubuntu-fr.org/tutoriel/mirroring_sur_deux_serveurs#configuration_et_mise_en_place_de_drbd

 Installation heartbeat (v1)

# aptitude install heartbeat

- serveur1 :

  • interface réseau : 192.168.1.1
  • interface lien drbd : 10.0.0.1

- serveur2 :

  • interface réseau : 192.168.1.2
  • interface lien drbd : 10.0.0.2

Services testés :
- adresse ip virtuelle
- montage d’un répertoire
- serveur nfs, apache, ou samba (pas dans l’exemple qui suit)
- machine virtuelle

La machine virtuelle gnu/linux est gérée par xen, sur drbd sur lvm. Il y a un volulme pour le disk et un pour le swap.

- /dev/drbd0 : xen1dd pour le disque
- /dev/drbd1 : xen1sw pour le swap
- /root/xen1.cfg : fichier de configuration
- /root/xen1_domain.cfg : utilisé par heartbeat

Le script /etc/ha.d/resource.d/xendom s’appuie sur ces données.

Le failover est activé : le serveur1 récupère les services quand il est réactivé.

serveur1# vi /etc/ha.d/ha.cf
debugfile /var/log/syslog
logfile /var/log/syslog
logfacility local0
autojoin none
ucast eth0 192.168.1.2
auto_failback on
warntime 3
deadtime 10
initdead 15
keepalive 2
node serveur1
node servuer2
respawn hacluster /usr/lib/heartbeat/ipfail

dans le ucast (suffisant si que 2 machines) il faut mettre l’adresse distante
=> les ha.cf ne sont pas identiques sur les 2 machines

dans le cas du multicat mettre à la place :

bcast eth0

Créer le fichier /etc/ha.d/authkeys pour l’authentification entre les 2 machines (identiques sur les 2 machines)

( echo -ne "auth 1\n1 sha1 "; \
 dd if=/dev/urandom bs=512 count=1 | openssl md5 ) \
 > /etc/ha.d/authkeys
chmod 0600 /etc/ha.d/authkeys

Copier la clé sur l’autre serveur :

serveur1# scp /etc/ha.d/authkeys serveur2:/etc/ha.d/authkeys

haresources

serveur1  xendom::xen1
serveur1  xendom::xen2
serveur2  xendom::xen3
serveur2  xendom::xen4 MailTo::admin@domaine.fr::Changement_d_etat_serveur
serveur1 IPaddr::192.168.3.234 drbddisk::data Filesystem::/dev/drbd2::/mnt::ext3 MailTo::admin@domaine.fr::Changement_d_etat_serveur

echange de clé ssh entre les 2 machines, pour que ssh fonctionne sans mot de passe. ssh-keygen, ssh-copy-id.

 Script de gestion d’une ressource machine virutelle xen

Dans cet exemple l’architecture est de 2 noeuds.

Fichier de configuration d’une vm qui sera passer en paramètre au script xendom (à faire évoluer...)

VM=vm1
CFGFILE=/root/xen_vm_cfg/vm1.cfg
LOCKFILE=/var/lock/vm1domains
CMDCREATE=xm
DRBD1=vm1dd
DRBD2=vm1sw

CMDCREATE : des vms sont lancées par xm ou virsh
DRBD1 ET 2 : une vms peut nécessité 1 volume ou 2 (pour le swap)

Script pour que heartbeat gère les vms /etc/ha.d/resource.d/xendom

Se script n’est pas parfait !! Notamment, j’ai vu la même vm se lancer plusieurs fois. Il manque un contrôle.

#!/bin/bash

set -e
SELF=192.168.3.9
PEER=192.168.3.196
SELFMIGR=10.0.0.3
PEERMIGR=10.0.0.4

if [ $(hostname) = phenix4 ]; then
 SELF=192.168.3.196
 PEER=192.168.3.9
        SELFMIGR=10.0.0.4
        PEERMIGR=10.0.0.3
fi

SSH_OPTS="-o ConnectTimeout=15"
configfile=$1 # fichier de config de la vm pour xendom
command=$2 # contient start, stop ou status

function usage {
  echo "Usage: $0 CFG start|stop|status|test"
  exit 1
}

if [ ! -r "$configfile" ]; then
   usage
fi
. $configfile

function is_alive {
         xm list $VM >/dev/null 2>&1
}

function safe_to_migrate {
#if xm list migrating-$VM >/dev/null 2>&1 ||
#                ssh $SSH_OPTS $PEER "xm list migrating-$VM >/dev/null 2>&1";
#then
#        echo "$0 : Migration impossible, the domain is alr$VM eady migrating."
#  echo "$0 : Waiting for migration to com$VM plete...(maximum 45s)"
#  local n=0
#  while [ $n -lt 45 ]; do
#       alive=0
#           if xm list migrating-$VM >/dev/null 2>&1 || ssh $SSH_OPTS $PEER "xm list migrating-$VM" >/dev/null 2>&1; then
#               alive=1
#           fi
#       if [ $alive = 0 ]; then
#           echo "$0 : Migration $VM is completed."
#           break
#       fi
#       echo -n "."
#       sleep 1
#       n=$(expr $n + 1)
#   done
#   if xm list migrating-$VM >/dev/null 2>&1 || ssh $SSH_OPTS $PEER "xm list migrating-$VM" >/dev/null 2>&1 ; then
#     echo "$0 : $VM could not migrate, so destroying migrating-$VM"
#                        if xm list migrating-$VM  >/dev/null 2>&1; then
#                     xm destroy migrating-$VM
#                        elif ssh $SSH_OPTS $PEER "xm list migrating-$VM" >/dev/null 2>&1; then
#                     ssh $SSH_OPTS $PEER "xm destroy migrating-$VM"
#                        fi
#          fi
#                return 1;
#fi
case "$(drbdadm cstate $DRBD1)" in
  Connected|SyncSource|SyncTarget)
                        if [ "$DRBD2" ]; then
             case  "$(drbdadm cstate $DRBD2)" in
               Connected|SyncSource|SyncTarget)
                  echo "$0 : $DRBD1 and $DRBD2 are connected, safe to migrate $VM." ;
                  return 0;;
       *)
          echo "$0 : $DRBD2 is disconnected, NOT safe to migrate $VM." ;
          return 1;;
             esac
                        else
       echo "$0 : $DRBD1 is connected, safe to migrate $VM." ;
       return 0;
                        fi
     ;;
  *)
     echo "$0 : $DRBD1 is disconnected, NOT safe to migrate $VM."
     return 1
     ;;
esac
}

function prepare_migration {
        echo "$0 : Preparing for migration $VM :"
        ssh $SSH_OPTS $PEER "drbdadm primary $DRBD1;"
        if [ "$DRBD2" ]; then
                ssh $SSH_OPTS $PEER "drbdadm primary $DRBD2;"
        fi
}
       
function start_disk {
# Il me semble que Xen fait passer automatiquement en Secondaire, après une migration live
# pour les vms linux.
# On s'assure juste de passer en primairy. Au pire on a du primary/primary, pas très grave.
 echo "$0 : Starting volumes for $VM:"
 drbdadm primary $DRBD1;
        if [ "$DRBD2" ]; then
   drbdadm primary $DRBD2;
        fi
}

function stop_disk {
   echo "Stopping volumes:"
   drbdadm secondary $DRBD1 || true
   if [ "$DRBD2" ]; then
       drbdadm secondary $DRBD2 || true
   fi
}


function update_mac_cache {
  arp -d $vm >/dev/null 2>&1 || true
  ping -c1 -w1 $vm >/dev/null 2>&1 || true
}

function start_domain {
                         start_disk;
      if is_alive ; then
          echo "$0 : start_domain : $VM already running." #>> /var/log/syslog
      else
         if safe_to_migrate &&
              ssh $SSH_OPTS $PEER "xm migrate --live $VM $SELFMIGR"; then
              update_mac_cache
              echo "$0 : start_domain : $VM migrated back." # >> /var/log/syslog
         else
            $CMDCREATE create -q $CFGFILE
            echo "$0 : start_domain : $VM created." # >> /var/log/syslog
            sleep 2
         fi
      fi
        # passer la ressource drbd en secondaire sur l'autre noeud
   if safe_to_migrate; then
       ssh $SSH_OPTS $PEER "drbdadm secondary $DRBD1" || true
       if [ "$DRBD2" ]; then
           ssh $SSH_OPTS $PEER "drbdadm secondary $DRBD2" || true
       fi
   fi
            touch $LOCKFILE
}

function stop_domain {
 rm -f $LOCKFILE
        local migration
 if safe_to_migrate && prepare_migration; then
     migration="OK"
 else
     migration="NG"
 fi
 echo "$0 : stop_domain : Etat de la variable migration for $VM : $migration"
 echo ""
 echo "$0 : stop_domain : Stopping localy $VM"
 if ! is_alive ; then
     echo "$0 : stop_domain : $VM not running localy."
 else
     if [ $migration = "OK" ] && xm migrate --live $VM $PEERMIGR; then
            update_mac_cache
           echo "$0 : stop_domain : $VM migrated."
     else
           xm shutdown $VM
           echo "$0 : stop_domain : shutting down $VM..."
     fi
  fi
  echo "$0 : stop_domain :  Waiting for shutdown $VM to complete ($VM was either migrated or shutdowned) (maximum 40s)"
  local n=0
  while [ $n -lt 40 ]; do
      alive=0
          if is_alive ; then
              alive=1
          fi
      if [ $alive = 0 ]; then
          echo "$0 : stop_domain : shutdown $VM is completed."
          break
      fi
      echo -n "."
      sleep 1
      n=$(expr $n + 1)
  done
  if is_alive ; then
    echo "$0 : stop_domain : $VM could not shutdown, so destroying $VM"
    xm destroy $VM
  fi
  stop_disk
}

function print_status {
   if [ -f $LOCKFILE ]; then
       echo "OK"
   else
       echo "Stopped"
       exit 1
   fi
}

case $command in
start)
  start_domain
  ;;
stop)
  stop_domain
  ;;
status)
  print_status
  ;;
test)
  if safe_to_migrate; then echo "salut"; else echo "aurevoir"; fi
  ;;
*)
  usage
  ;;
esac
chmod u+x xendom

Pour tester le script

/etc/ha.d/resource.d/xendom /root/xen1_domain.cfg start

 Commandes

/etc/init.d/heartbeat reload
/etc/init.d/heartbeat restart # va stoper les ressources (migrer les vms), puis va les récupérer, DONC ATTENTION AVEC CETTE COMMANDE
/usr/share/heartbeat/hb_takeover # récupère toutes les ressources
/usr/share/heartbeat/hb_takeover local # ne récupère que les ressources pour lequel le noeud est "maitre"
ps aux | grep heartbeat
/usr/share/heartbeat/hb_standby # envoie les ressources vers l'autre hote, utile avant d'eteindre la machine

remarque : anciennement le chemin était /usr/lib/heartbeat/bh_takeover

Pour ne manipuler qu’une seule ressource, par exemple pour migrer un vms de srv1 à srv2, je crois que :

srv1# /etc/ha.d/resource.d/xendom /root/xen1_domain.cfg stop

La migration est alors effectué. Faire ensuite

srv2# /etc/ha.d/resource.d/xendom /root/xen1_domain.cfg start

Pour que le heartbeat de srv2 prenne en compte que la ressource est démarré sur lui.

 Remarques

- lors d’un takeover ou takeover local, pour les vms xen, elles migrent les unes après les autres (pas toutes en même temps).
- un câble réseau au dédié au réplicage drbd entre serveur1 et serveur2. heartbeat utilise le même lien réseau que les machines clientes du réseau. (si le cable drbd tombe, heartbeat ne lancera pas pour autant 2 fois les services, car l’autre lien sera actif.) Ceci est bien confirmé ici
- l’ordre des vms dans haresource a son importance. Les ressources seront gérées dans cette ordre. Trier donc par priorité des vms (serveur DNS, DHCP en premier...)
- je crois que lancer un "/usr/lib/heartbeat/hb_takeover local" revient à faire un "/etc/ha.d/resource.d/xendom xen1 start" pour chaque vm du l’hote.

 Alerte par mail

Voir si le serveur peut envoyer des mails :

echo "Essai mail" | mail -s "Sujet essai mail" admin@domain.fr

Voir si le script MailTo envoie bien le mail :

/etc/ha.d/resource.d# ./MailTo admin@domain.fr "Essai_alerte" start

En cas de problème :

# dpkg-reconfigure postfix

Ajouter la ressources dans le haresource :

serveur1 MailTo::admin@domain.fr


- Faire un reload de heartbeat

Faire un test :
- migrer une vm (la migration passe par le cable dédié, 10.0.0.x) :

serveur1# xm migrate --live vm1 10.0.0.2


- faire récupérer le service au serveur 1

# /usr/lib/heartbeat/hb_takeover local

2 mails sont reçu à l’adresse admin@domain.fr (il n’y a qu’une ligne dans le haresource) : un mail disant qu’il y a un "takeover in progress" sur serveur1, et un mail pour dire que serveur2 fait une "migration resource away".

 Etudes de cas

Takeover du service

- le service est sur srv, et il est maitre pour se service avec un ipfail
- srv2 fait /usr/lib/heartbeat/hb_takeover, il récupère le service
- le service reste sur srv2
- si srv1 fait un takeover ou un heartbeat restart (attention avec cette commande) ou un reboot, il récupère le service.

Extinction machine

- le service est sur srv1, et il est maitre pour se service avec un ipfail
- srv1 fait un shutdown -h now
- heartbeat pendant la phase d’extinction, migre le service sur srv2. Il n’y a pas d’arret du service
- au redémarrage de srv1, srv1 récupère le service.

Câble réseau débranché

- Le service S est sur srv1
- câble réseau local srv1 est débranché (celui utilisé par heartbeat)
- S reste actif sur srv1, mais n’est pas joignable
- après un certain temps, srv2 lance S, grace à heartbeat
- le câble réseau est rebranché
- on a un split brain pour les ressources drbd
- heartbeat coupe les services, pour éviter les doublons, et les relances uniquement sur srv1. (malgré le split brain les services peuvent être activés)
- il faut résoudre le split brain :

  • /etc/init.d/drbd restart

    (ou reload suffit ?) sur les 2 noeuds.

  • il y a des alertes car des ressources sont actives (en primaire pour les services actifs). pas grave. Le faire sur les 2 noeuds.
  • sur le ressources secondaire qui sont toujours déconnectés, faire un :
    drbdadm connect res
  • Ca connecte et le synchro doit se faire

Coupure d’électricité

- service S actif sur srv1
- débranché physiquement, électriquement srv1
- heartbeat lance S sur srv2
- rebrancher l’alimentation
- drbd se reconnecte, sans plit brain
- le failover migre les services sur srv1

Programmer le serveur dans le bios pour qu’il redémarrer suite à une coupure d’électricité. Sinon l’onduleur peut alerte le serveur, pour le couper correctement.

Coupure de service

- le service S est sur srv1
- on coupe manuellement le service S
- le service n’est pas relancé. ni sur srv1, ni sur srv2.
- si on fait un /etc/init.d/heartbeat restart (attention avec cette commande), sur srv1 ou srv2, le service est relancé.

 Problèmes rencontrés

Une migration live ce passe mal, sur le serveur d’origine la vm reste dans l’état migrating-vm :
- xm destroy migrating-vm
- identifié également le processus heartbeat en cours

ps aux | grep heartbeat

et le terminer

kill "du_pid_concerné"

Heartbeat ne se lance pas au démarrage de la machine, pourtant il est bien dans /etc/rc.X... Essai de la commande :

update-rc.d heartbeat defaults 99

 Gestion de apache

Désactiver apache au démarrage

update-rc.d -f apache2 remove

Pour faire machine arrière, si besoin :

# update-rc.d apache2 defaults

L’ajouter dans haresources

nomserveurprimaire apache2