Alors comme ça je t'ai manqué ami lecteur ? Ne t'en fais pas, je suis de retour (peut-être pas pour longtemps, je vais probablement passer mes prochains week-ends à faire les magasins pour rédiger ma lettre au père noël...).
Quoi qu'il en soit, je te présentais cette semaine une petite maquette fort sympathique à base de keepalived, nginx et haproxy. Éh bien figure toi que j'ai amélioré un peu cette maquette pour ton plus grand plaisir
Concrètement, qu'ai-je fait ? J'ai ajouté du load-balancing DNS pour avoir une répartition de charge en amont de mes frontaux qui font ensuite du load-balancing sur les backends.
Alors, oui, comme ça avec des mots ça semble un peu tordu/compliqué. Sur un dessin ça devrait sembler plus clair... mais là j'ai un peu beaucoup la flemme de sortir mon joli dia.
Mais voici l'idée :
- Je dispose de deux ip virtuelles que je vais enregistrer sous un même nom DNS
- J'assigne une de ces ip virtuelle à chacun de mes load-balancer
En pratique, ça donne ça :
root@lb2:~# ip addr sh eth1
3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
link/ether 00:16:3e:30:24:71 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.7/24 brd 172.25.0.255 scope global eth1
inet 172.17.0.10/32 scope global eth1
inet6 fe80::216:3eff:fe30:2471/64 scope link
valid_lft forever preferred_lft forever
root@lb1:~# ip addr sh eth1
3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
link/ether 00:16:3e:20:4d:9b brd ff:ff:ff:ff:ff:ff
inet 172.17.0.6/24 brd 172.25.0.255 scope global eth1
inet 172.17.0.5/32 scope global eth1
inet6 fe80::216:3eff:fe20:4d9b/64 scope link
valid_lft forever preferred_lft forever
ziirish@carbon:~$ dig lb.ziirish.info
; <<>> DiG 9.7.3 <<>> lb.ziirish.info
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 30116
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 1, ADDITIONAL: 1
;; QUESTION SECTION:
;lb.ziirish.info. IN A
;; ANSWER SECTION:
lb.ziirish.info. 10800 IN A 172.17.0.10
lb.ziirish.info. 10800 IN A 172.17.0.5
;; AUTHORITY SECTION:
ziirish.info. 10800 IN NS yoda.ziirish.info.
;; ADDITIONAL SECTION:
yoda.ziirish.info. 10800 IN A 10.0.0.30
;; Query time: 3 msec
;; SERVER: 10.0.0.3#53(10.0.0.3)
;; WHEN: Sat Nov 12 11:56:21 2011
;; MSG SIZE rcvd: 101
Je ne reviendrais pas sur la configuration du DNS qui est relativement triviale... Je vous détaillerai juste les modifications apportées à keepalived et haproxy. En effet, pour utiliser ce mode de fonctionnement sans craindre de faire sauter les sessions (rendre le passage d'un lb à l'autre transparent pour le client final), il nous faut utiliser une petite fonctionnalité de haproxy qui n'est pas encore dans la branche stable : les pools. Nous couplerons cela aux stick-table qui étaient déjà présentes dans la version 1.4.
On commence donc par récupérer les dernières sources de haproxy à l'adresse suivante , puis nous le compilons :
% tar xvzf haproxy-1.5-dev7.tar.gz
% mv haproxy-1.5-dev7 /opt/
% cd /opt/haproxy-1.5-dev7
% make TARGET=linux26
J'avais installé la précédente version de haproxy via les paquets debian, j'ai donc à ma disposition le script init que je vais modifié comme ceci :
#HAPROXY=/usr/sbin/haproxy
HAPROXY=/opt/haproxy-1.5-dev7/haproxy
Notre nouveau haproxy est désormais utilisable.
Voici la nouvelle configuration :
global
maxconn 30000
ulimit-n 65536
log 127.0.0.1 local0
log 127.0.0.1 local1 debug
peers haproxy_pool
peer ha1 10.0.0.6:1024
peer ha2 10.0.0.7:1024
defaults
balance leastconn
retries 3
option redispatch
timeout connect 5000ms
timeout client 50000ms
timeout server 50000ms
listen stats 10.0.0.6:80 # remplacer par 10.0.0.7:80 sur le second lb
mode http
stats enable
stats uri /stats
stats realm HAProxy\ Statistics
stats auth utilisateur:motdepasse
backend http
mode http
balance roundrobin
stick on src table https
cookie SRV insert indirect nocache
server s1 10.0.0.6:8080 cookie s1 check
server s2 10.0.0.7:8080 cookie s2 check
backend https
mode tcp
balance roundrobin
stick-table type ip size 200k expire 30m peers haproxy_pool
stick on src
server s1 10.0.0.6:4443 check
server s2 10.0.0.7:4443 check
frontend public_http
bind 172.17.0.5:80
bind 172.17.0.10:80
default_backend http
frontend public_https
bind 172.17.0.5:443
bind 172.17.0.10:443
default_backend https
Enfin, il nous faut ajouter un nouveau paramètre au lancement de haproxy. On le renseignera dans le fichier /etc/default/haproxy :
EXTRAOPTS="-L ha1" # remplacer ha1 par ha2 sur le second lb
Nos deux instances de haproxy vont désormais communiquer entre-elles via le port 1024.
Il ne nous reste plus qu'à configurer keepalived.
Voici la conf sur le lb1 :
vrrp_script chk_haproxy { # Requires keepalived-1.1.13
script "killall -0 haproxy" # cheaper than pidof
interval 2 # check every 2 seconds
weight 2 # add 2 points of prio if OK
}
vrrp_instance VI_1 {
interface eth1
state MASTER
virtual_router_id 51
priority 101 # 101 on master, 100 on backup
virtual_ipaddress {
172.17.0.15
}
track_script {
chk_haproxy
}
}
vrrp_instance VI_2 {
interface eth1
state BACKUP
virtual_router_id 52
priority 100 # 101 on master, 100 on backup
virtual_ipaddress {
172.17.0.10
}
track_script {
chk_haproxy
}
}
Et celle sur le lb2 :
vrrp_script chk_haproxy { # Requires keepalived-1.1.13
script "killall -0 haproxy" # cheaper than pidof
interval 2 # check every 2 seconds
weight 2 # add 2 points of prio if OK
}
vrrp_instance VI_1 {
interface eth1
state BACKUP
virtual_router_id 51
priority 100 # 101 on master, 100 on backup
virtual_ipaddress {
172.17.0.15
}
track_script {
chk_haproxy
}
}
vrrp_instance VI_2 {
interface eth1
state MASTER
virtual_router_id 52
priority 101 # 101 on master, 100 on backup
virtual_ipaddress {
172.17.0.10
}
track_script {
chk_haproxy
}
}
Et voilà, enjoy !