13 nov. 2008
Haute disponibilité d'un serveur web
Par Christophe de saint leger le jeudi, novembre 13 2008, 19:01 - Serveur - Lien permanent
Intro
Cet article présente la mise en place d'un "cluster" permettant une haute disponibilité ... Attention , ce n'est pas une répartition de charge , mais bien un basculement automatique en cas de panne d'un des deux nodes ...
Plan
- le matériel
- les distributions
- mysql en réplication voir aussi le billet réplication mysql
- apache2 / php5
- synchro des data
- heartbeat
- tests
Cet article est écrit au fur et à mesure de l'évolution de la mise en place de cette structure ... n'hésitez donc pas à revenir pour voir la suite de l'article ...
Le matériel
J'ai opté pour deux serveurs identiques , pour une simplicité d'administration , et de compatibilité . Les serveurs choisis sont deux PowerEdge R200 dell
La configuration choisis est la suivante :
Config Quad Code Intel Xeon 2.83Ghz Ram 4Go DD 25Go (un seul disque) 2 cartes réseaux Gbits
Définition Les serveurs seront configurés comme suite :
Nom: faramir Ip1 : 10.0.0.220 Ip2 : 192.168.0.220
Nom: boromir Ip1 : 10.0.0.221 Ip2 : 192.168.0.221
Le cluster possédera 3 adresses :
10.0.0.223 10.0.0.224 10.0.0.225
Voilà , pour le matériel , pour la disposition , les interfaces #1 en 10.0.0.x seront les adresses accessibles par le réseau local , et les interfaces #2 seront paramétrés uniquement pour les dialogues serveur<->serveur (prise de pouls ,synchro des data, replication mysql ) afin de ne pas saturer le réseau local .
Les distributions
J'ai choisi debian Etch (qui est la version stable au moment ou j'écris cet article ).
Je ne suis pas allé directement sur la version testing qui est sid , pour la simple raison que Etch suffit amplement , et de plus , je cite : Veuillez noter que les mises à jour relatives à la sécurité pour la distribution de test ne sont pas gérées par l'équipe en charge de la sécurité. En conséquence de quoi ces mises à jour ne sont soumises à aucune contrainte de temps.
suite ici
L'installation de etch s'est trés bien passé , pour des raisons de simplicité , j'ai utilisé une seule partition pour la totalité du système , ce qui n'est pas forcément un bon choix , mais dans mon cas , ce sont des serveurs disponibles uniquement en interne , pas de portes ouvertes vers l'extérieur , ce qui limite de voir mon système être saturé par les log ou autres ... De plus l'espace disque est plus que suffisant , et ne risque pas de grossir prématurément au point de bloquer le système .
jusqu'ici l'installation a été rigoureusement la même sur les deux machines faramir et boromir
Une fois les systèmes installés et fonctionnels , j'ai mis en place mysql .
mysql en réplication
Edite 11/12/2009 : Voir aussi le billet réplication mysql
Mysql n'ayant pas énormément d'options de compilation , j'ai utilisé la version disponible dans les dépots ....
apt-get install mysql-server
Enfin installé sur chaque machine , vient la configuration de la réplication .
La réplication type maître->esclave , permet d'avoir une copie exacte des bases de données du serveur maître sur le serveur esclave ... les insertions doivent toujours être faites sur le poste maître sinon , la réplication est cassé .. Par contre , les requêtes de type select peuvent trés bien être faites directement sur l'esclave ou le maître .. tant que les données ne changent pas ...
Si un mauvais jour , le serveur maître tombe en panne , on bascule sur le serveur esclave qui prend le relais , et devient donc maître ... une fois l'ancien serveur maître réparé , il devient esclave afin de simplifier les choses niveau importation de données ect ...
Ici : faramir est le maître et boromir est l'esclave
Nous allons commencer par la configuration du maître
my.cnf du maître
vous allez juste commenter cette ligne afin de permettre la connexion à partir de l'esclave :
#bind-address = 127.0.0.1
Puis vérifier que vous avez bien décommenté ces deux lignes :
server-id = 1 log_bin = /var/log/mysql/mysql-bin.log
Nous allons ensuite ajouter l'utilisateur qui va se connecter au maître pour synchroniser les data ...
soit par phpmyadmin , soit directement en ligne de commande
mysql> GRANT REPLICATION SLAVE ON *.* TO 'slave_user'@'%' IDENTIFIED BY '<password>'; (Remplacer <password> par votre password!) mysql> FLUSH PRIVILEGES;
my.cnf de l'esclave
Vérifier que vous avez bien décommenté ces deux lignes et changer le server-id=1 par server-id=2:
server-id = 2 log_bin = /var/log/mysql/mysql-bin.log
Puis ajouter en fin de fichier les lignes suivantes (a adapter à votre cas):
master-host=<adresse ip du serveur maitre> master-user=slave_user master-password=<password> master-connect-retry=60
Redémarrer votre serveur mysql
/etc/init.d/mysql restart
Puis nous allons importer les données déjà présentes sur le maître ..
mysql> LOAD DATA FROM MASTER; mysql> quit;
Enfin , nous allons démarrer notre esclave :
mysql> SLAVE START; mysql> quit;
Il ne vous reste plus qu'à tester la réplication , en ajoutant des données sur votre serveur maître (jamais sur l'esclave)
Apache2 et PHP5
Je vais donner les grandes étapes de l'installation d'apache2 et php5 , celle-ci étant déjà expliqué dans un précédent billet .. Je vais éditer toutes les étapes qui ont été nécessaires pour que l'installation fonctionne sur une etch toute neuve .
Apache2
Récupération de l'archive
cd /usr/local/src wget http://mirror.mkhelif.fr/apache/httpd/httpd-2.2.10.tar.gz tar xzf httpd-2.2.10.tar.gz rm httpd-2.2.10.tar.gz cd httpd-2.2.10/
fichier de configuration
A adapter dans votre cas
vim my_configure
le contenu
#!/bin/sh #Optimisation pour la compilation export CC="gcc" export CFLAGS="-02" #Config des sources pour l'env ./configure --prefix=/usr/local \ --enable-rewrite \ --enable-so \ --enable-cache \ --enable-mem-cache \ --enable-alias \ --enable-vhost-alias \ --enable-ssl=shared \ --disable-status \ --disable-cgi \ --disable-cgid \ --enable-unique-id \
Paquets que j'ai été obligé d'installer pour que la compilation se passe bien
apt-get install build-essential libssl-dev
Lancement de la compilation
./my_configure make make install
PHP5
Récupération de l'archive
cd /usr/local/src/ wget http://fr.php.net/distributions/php-5.2.6.tar.gz tar xzf php-5.2.6.tar.gz rm php-5.2.6.tar.gz cd php-5.2.6/
fichier de configuration
A adapter dans votre cas
vim my_configure
le contenu
#!/bin/sh
export OPTIM=-02
./configure --prefix=/usr/local \
--with-apxs2=/usr/local/bin/apxs \
--with-xsl \
--enable-soap \
--with-gettext \
--enable-mbstring --with-mbstring=all \
--disable-debug \
--enable-memory-limit \
--enable-ftp \
--with-mcrypt \
--enable-zip \
--disable-cgi \
--enable-calendar \
--enable-exif \
--enable-pdo \
--with-pdo-mysql \
--with-mysql \
--with-pdo-sqlite \
--with-sqlite \
--with-zlib \
Paquets que j'ai été obligé d'installer pour que la compilation se passe bien
apt-get install libxml2-dev libmcrypt-dev libmysqlclient15-dev libxslt1-dev
Lancement de la compilation
./my_configure make make install
Vérification/ajout des trois lignes suivantes dans httpd.conf
vim /usr/local/conf/httpd.conf
vérifier les lignes suiventes sont présentes et décomentés
LoadModule php5_module modules/libphp5.so AddType application/x-httpd-php .php .phtml AddType application/x-httpd-php-source .phps
php.ini Par défaut , il n'y a pas de fichier php.ini de cree , les valeurs sont donc toutes par défaut , si vous souhaitez l'ajouter pour y modifier des valeurs même plus tard , vous devez le copier à partir des sources
cp /usr/local/src/php-5.2.6/php.ini-dist /usr/local/lib/php.ini
Lanceur d'apache Le "lanceur" d'apache , se trouve dans /usr/local/bin/ , et se nomme apachectl , pour que votre serveur se lance au démarrage , nous allons creer un lien dans /etc/init.d
ln -s /usr/local/bin/apachectl /etc/init.d/apache2 update-rc.d apache2 defaults
Et voilà , votre serveur web est fin prêt .. il ne vous reste plus qu'à le sécuriser et/ou activer les vhosts , ces deux points feront l'objet de future articles ...
Note: vous devez faire exactement les même manœuvres expliqués ci-dessus sur les deux serveurs
synchro des data
Pour la synchronisation , j'ai cherché une solution simple et rapide à mettre en place . Le serveur web ayant une majorité de données statiques la synchronisation peut être faite toutes les 2 minutes , cela ne posera aucun souci en cas de panne ...
Je suis d'abord allé voir du coté d'UNISON ... UNISON permet une synchronisation dans les deux sens , ce qui est un gros avantage dans certains cas , mais ici , c'est toujours le serveur maître qui va envoyer des données sur l'esclave ... de plus , je n'ai pas trouvé l'option pour supprimer les fichiers qui l'ont été sur le serveur maître , ce qui rendait impossible la suppression de fichier ... Bref UNISON ne me convient pas ...
Je suis donc parti sur une solution simple avec rsync
Dans un premier , temps , j'ai vérifié les connexions en ssh entre les deux serveurs , grace à des clef rsa . Voici le principe :
Clef RSA serveur maitre
ssh-keygen -t rsa
Taper deux ou trois fois sur "Entrée" sans entrer de pass phrase ... car le but ici , est de ne pas avoir de mot de passe à saisir ...
Puis éditer la clef public créé
cat .ssh/id_rsa.pub
Vous aller avoir cette fameuse clef sous cette forme:
ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAw+Z0uzNQndQJtOLaRC9MnLt6IVTwHVg4Am370biDHTvuFy8jImJi+DV3OkA5SgQO3ei48OnX6KP9tKWBeIY/AriNkXaXGUzmvxngMeioXWySUc1OEUQ6vRirsv5avEc8F96McfF3b6aafRO/M3hMN/RjJjoqz1vrZtFps277ivFJJLho05mHqnq3z1LuqP13Prrg8ZRQwEDr0QC7X6GGHU/KkvhSoimGQCpjEAw/+QtddMOJUE/zFbBc4W+1Uzi/ZimUKJTz3czxlrioCNBY8Ut0HbwzvMu7fgJUcIcjL5YZJ4ppn/X2EQxFCzvKgO8sM259PPOgiTgjPNLVTN0d6Q== utilisateur@faramir
Copiez là , et connectez vous sur le serveur esclave . Ouvrir / creer le fichier authorized_keys
vim .ssh/authorized_keys
Et copier la clef du serveur maître dans ce fichier ... NOTE : le nom d'hote ( ici faramir ) doit être connu sur le serveur esclave , il doit donc y avoir la ligne <adresse ip> faramir dans le fichier /etc/hosts afin de pouvoir faire la relation nom d'hote <-> adresse ip
Faites la même procédure mais dans l'autre sens , générer la clef rsa sur l'esclave , et copiez là sur le maître ...
Ainsi , les deux serveurs faramir et boromir peuvent communiquer de façon crypté sans avoir à entrer de mots de passe .
Création du script :
Un script trés simple , lancé toutes les 2 minutes , afin de synchroniser les données du serveur :
vim synchro.sh
et voici un exemple de script :
#!/bin/bash #la synchro faramir -> boromir rsync -avz --stats --delete --itemize-changes --partial --timeout=30 --exclude-from=/home/user/scripts/EXCLUDES.EXCL --progress -e "ssh -l util-ssh -p22 " /home/user/www/ user@<adresse id serv esclave>:www/ 2>> backup-src.error
une doc sur rsync
Ainsi , ce script , synchronise le dossier /home/user/www du serveur maitre avec le dossier /home/user/www du serveur esclave.
Ajout dans la crontab
Pour lancer le script de synchronisation toutes les deux minutes , nous allons l'ajouter dans la crontab
crontab -e
Ajouter la ligne de ce style ( a adapter dans votre cas )
- /2 * * * * /home/user/scripts/synchro.sh >>/dev/null
Et voilà , notre script de synchronisation , sera lancé toutes les deux minutes ...
Nous avons donc à ce stade , un serveur maître et un serveur esclave avec APACHE/PHP5 fonctionnel MYSQL fonctionnel et synchroniser en temps reel le répertoire WWW synchronisé toutes les deux minutes
Il ne reste plus qu'à mettre en place la prise de pouls pour basculer automatiquement sur le serveur esclave en cas d'arrêt du serveur maître .
C'est donc ici qu'entre en jeux HEARTBEAT
HEARTBEAT
L'installation est on ne peut plus simple ....
apt-get install heartbeat
Une fois installé , il reste trois fichiers à configurer , qui se trouvent dans :
/etc/heartbeat/
Les trois fichiers sont :
- ha.cf
- haresources
- authkeys
Comme expliqué dans README.config
ha.cf ( paramétres de heartbeat)
voici mon fichier ha.cf:
bcast eth1 debugfile /var/log/ha-debug logfile /var/log/ha-log logfacility local0 keepalive 2 deadtime 10 warntime 6 udpport 694 node faramir node boromir auto_failback off
Ici , je précise l'interface qui sera utilisé pour la prise de pouls (eth1 qui correspond au réseau type : 192.168.0.0/24) , definition ensuite des fichiers de log , puis keepalive le delai entre deux battements de pouls , deadtime duré limite , qui une fois dépassé , le node sera considéré comme mort .
warntime delai avant d'enregistrer dans les log , qu'un battement est en retard.
udpport numéro udp du port pour la communication entre serveur ( prise de pouls )
node noms/adresses des machines faisant partie de l'ensemble .
il faut absoluement que les noms de machines soient connu sur chacun des serveurs , pour en être certains , il est conseillé d'ajouter dans le fichier /etc/hosts les déclarations des machines déclaré comme node.
auto_failback off ici , le retour à la normal ne se fait que manuellement .. en effet ici , si le serveur maître tombe , le second prend le relai , les enregistrements dans la base se fait donc directement sur l'esclave , nous devons donc ensuite considérer devient maître , et le maître esclave ...
haresources ( liste des serveurs synchronisés )
faramir IPaddr::10.0.0.223 IPaddr::10.0.0.224 IPaddr::10.0.0.225
Ce fichier , défini ici quel serveur est le maître , et quelles sont les adresses ip virtuelles ... Ici , le maître est faramir , et pour accéder au serveur , l'on peut utiliser 3 adresses : 10.0.0.223 10.0.0.224 10.0.0.225
Pour executer un script en cas de défaillance , il nous suffit d'ajouter à la fin de la ligne de haresources , le nom d'un script qui peut répondre , aux commandes { start | stop | status }
Les scripts sont cherchés dans les répertoires suivant , et dans cette ordre :
/etc/heartbeat/resource.d /etc/rc.d.init.d/
Plusieurs scripts sont déjà disponible dans le répertoire resource.d
authkeys ( méthode d'authentification des machines entre elles )
auth 2 1 crc 2 md5 "le site lindev est interessant"
Ce ficher se comporte comme ceci : la premiére ligne , suivie du chiffre défini quel mode d'authentification sera utilisé . Puis chaque ligne qui comprend un chiffre , et la méthode d'authentification .
Ici , j'utilise une authentification md5 , avec le mot de passe "le site lindev est intéressant"
Voilà , ces trois fichiers doivent être rigoureusement les mêmes sur chaque serveur , le service peut ensuite être redémarré ...
Attention : l'ordre de démarrage de ce service a son importance , vous devez démarrer le maître , puis l'esclave ...
En cas de basculement , l'esclave prend le relais ... même si vous relancez le serveur maître ... Pour revenir dans l'etat initiale , relancer heartbeat sur le serveur esclave .. le maître reprendra la main.
Voilà , il ne reste plus qu'à tester en coupant la prise de pouls sur le serveur maître , l'on doit passer automatiquement sur le serveur esclave ... pour ce faire , puisque la prise de pouls s'effectue sur eth1 :
ifdown eth1
Une fois votre test terminé , réactiver eth1 :
ifup eth1
puis redémarrer le service heartbeat sur le serveur esclave .. sinon , vous allez rester sur le serveur esclave ( le node maître ne sera pas réinséré ) .
Attention: ne pas faire d'enregistrement dans la base de données pendant vos tests , sinon , la réplication sera brisé ...
En espérant que cet article vous a plu ... N'hésitez pas à commenter ..

Commentaires
Bonjour, tout d'abord bravo pour ce tuto très complet.
Je viens, il y a peu, de mettre en place 2 serveurs debian en HA, avec heartbeat, rsync, et apache2.
Sur heartbeat, j'ai activé le auto_failback , mais ce que je voulais savoir, c'est si il était possible de faire un script qui automatise rsync dans un sens particulier, je m'explique :
Si on fait une config normale, on écrit sur Node1, et rsync synchronise toute les 2 min sur Node2.
Mais là, pour une raison X ou Y, Node1 tombe en panne pendant 1h, donc le relai est passé sur Node2, mais quand Node1 sera de nouveau opérationnel, rsync va recommencer de mettre Node2 à niveau par rapport à Node1 ( qui lui possède du coup des info qui ne sont plus a jour puisque c'est sur Node2 que les utilisateurs ont travaillé.
En gros, je voudrais faire un script qui synchronise les données du maitre vers l'esclave, mais qui change de sens lorsque les serveurs change de role ( maitre / esclave )
Merci d'avance pour l'aide.
Francois-Xavier
salut ,
pour ton "probléme" , je crains fort que ce ne soit au dessus des possibilités de cette méthode de HT .
En effet ,
en utilisant la méthode décrite ici , vous avez de la haute disponibilité , dans le sens ou , en cas de crash de la machine Maître , l'esclave , prend automatiquement le relais .
Seulement , à partir du moment , ou il y a un enregistrement dans la base de données du servuer esclave , la réplication est cassé .. , donc même si l'on arrive à relancer le serveur maître , il n'y aura plus de réplication au niveau base de données ...
Ce n'est pas réellement un cluster , qui en plus de permettre la haute dispo , permet aussi de répartir les charges , mais il faut pour celà au minimum 3 machines ...
Voilà ... par contre , si tu n'as pas de bases de données , alors là oui c'est possible ..
Lor d'un changement de serveur ( suite à une panne ) , l'on peut lancer n'importe quel script comme précisé à la fin de cet article :
Voilà .. désolé de ne pouvoir t'aider plus que ça ... mais pour faire plus , il faut un systéme plus gros en nombre de machine , et ce n'est plus l'objet de cet article ..
Ch.
Merci pour ce tuto.. Bien pratique..
Pour répondre à Fix, il peut utiliser la solution drdb qui a pour but de faire du raid1 sur de l'Ethernet. Ce n'est pas compliqué à mettre en place.. et c'est très performant...
Je viens de le mettre ne place pour une solution clustering actif/passif..