0

Comparatif des gestionnaires de VIP dans un cluster Patroni : épisode 1 (KEEPALIVED)

twitterlinkedinmail

Hello à toutes / tous,

Suite à l’article de Ludo sur Patroni, cette semaine nous allons faire un comparatif des solutions de gestion de VIP dans un cluster.

Car si Patroni gère le déploiement et la supervision d’instances PostgreSQL dans un cluster actif / passif, il ne gère pas les redirections de connexion en cas de bascule. Il faudra donc s’appuyer sur une solution tierce. On travaille toujours à partir de conteneurs LXD, comme en témoigneront les commandes. Si vous êtes en environnement on-prem, simplement ignorer les préfixes type ‘lxc exec node — …’

KEEPALIVED:

C’est la solution la plus courante. Elle consiste à démarrer un service qui va créer une interface virtuelle en fonction de l’état d’une ressource (en l’occurrence ici un appel REST vers Patroni pour nous indiquer si le noeud local est le leader).

En cas d’erreur sur le test, qui indiquerait que le service n’est pas joignable, keepalived tombe l’interface sur le noeud en échec et la remonte sur le noeud survivant. Couplé à Patroni, qui va gérer le promote de l’instance standby, c’est un outil simple pour rediriger automatiquement les connexions.

Schéma:

On utilisera donc un cluster à base de conteneurs LXD, à 3 noeuds pour le quorum ETCD. Patroni / PostgreSQL / Keepalived seront déployés sur les 2 premiers noeuds seulement.

Installation et configuration de keepalived sur les 2 noeuds Patroni:

A faire sur pgpat1 et pgpat2:

root@pgpat1:~# apt-get install -y keepalived curl
# Bug https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=878241
root@pgpat1:~# apt-get install -y libipset-dev

Le fichier de configuration par défaut se trouvera sous /etc/keepalived/keepalived.conf, il faudra le créer car il n’existe pas au préalable:

Sur pgpat1:

root@pgpat1:~# vi /etc/keepalived/keepalived.conf
global_defs { 
  router_id pgpat1
  enable_script_security
  script_user root
}

vrrp_script whosprimary {
  script "/usr/bin/curl -X GET -I --fail http://10.186.157.60:8008/primary"
  user root
}

vrrp_instance PGPAT1 {
  state MASTER
  interface eth0
  virtual_router_id 50
  unicast_peer {
    10.186.157.60
    10.186.157.216
  }
  advert_int 1
  authentication {
    auth_type PASS
    auth_pass ~bG7n)4?
  }
  virtual_ipaddress {
    10.186.157.199/24 dev eth0 label eth0:1
  }
  track_script {
    whosprimary
  }
  no_accept
}

Le script whosprimary effectuera la requête en REST, et notre VIP portera l’adresse 10.186.157.199. On redémarre le service à l’issue:

root@ubuntu20:~# lxc exec pgpat1 -- systemctl restart keepalived.service
root@ubuntu20:~# lxc exec pgpat1 -- systemctl status keepalived.service
● keepalived.service - Keepalive Daemon (LVS and VRRP)
   Loaded: loaded (/lib/systemd/system/keepalived.service; enabled; vendor preset: enabled)
  Drop-In: /run/systemd/system/keepalived.service.d
           └─zzz-lxc-service.conf
   Active: active (running) since Sun 2022-03-06 14:50:49 UTC; 7min ago
  Process: 338 ExecStart=/usr/sbin/keepalived $DAEMON_ARGS (code=exited, status=0/SUCCESS)
 Main PID: 346 (keepalived)
    Tasks: 2 (limit: 4619)
   CGroup: /system.slice/keepalived.service
           ├─346 /usr/sbin/keepalived -P
           └─347 /usr/sbin/keepalived -P

On peut alors tester si la VIP est correctement montée sur le noeud pgpat1 et tester une connexion vers l’instance PostgreSQL:

root@ubuntu20:~# lxc exec pgpat1 -- ip addr show | grep eth0:1
    inet 10.186.157.199/24 scope global secondary eth0:1

root@ubuntu20:~# psql -U postgres -h 10.186.157.199 \ 
-p 5432 postgres -c "\conninfo"
Password for user postgres: 
You are connected to database "postgres" as user "postgres" 
on host "10.186.157.199" at port "5432".

Sur pgpat2:

root@pgpat2:~# vi /etc/keepalived/keepalived.conf

global_defs { 
  router_id pgpat2
  enable_script_security
  script_user root
}

vrrp_script whosprimary {
  script "/usr/bin/curl -X GET -I --fail http://10.186.157.216:8008/primary"
  user root
}

vrrp_instance PGPAT2 {
  state MASTER
  interface eth0
  virtual_router_id 51
  unicast_peer {
    10.186.157.60
    10.186.157.216
  }
  advert_int 1
  authentication {
    auth_type PASS
    auth_pass ~bG7n)4?
  }
  virtual_ipaddress {
    10.186.157.199/24 dev eth0 label eth0:1
  }
  track_script {
    whosprimary
  }
  no_accept
}

Noter que virtual_router_id doit avoir un id unique sur la topologie. Puis même chose on redémarre keepalived et on vérifie qu’il se positionne bien en off:

root@ubuntu20:~# lxc exec pgpat2 -- systemctl restart keepalived.service
root@ubuntu20:~# lxc exec pgpat2 -- systemctl status keepalived.service
● keepalived.service - Keepalive Daemon (LVS and VRRP)
   Loaded: loaded (/lib/systemd/system/keepalived.service; enabled; vendor preset: enabled)
  Drop-In: /run/systemd/system/keepalived.service.d
           └─zzz-lxc-service.conf
   Active: active (running) since Sun 2022-03-06 14:56:10 UTC; 4min 8s ago
  Process: 362 ExecStart=/usr/sbin/keepalived $DAEMON_ARGS (code=exited, status=0/SUCCESS)
 Main PID: 365 (keepalived)
    Tasks: 3 (limit: 4619)
   CGroup: /system.slice/keepalived.service
           ├─365 /usr/sbin/keepalived
           ├─366 /usr/sbin/keepalived
           └─367 /usr/sbin/keepalived

Mar 06 15:00:09 pgpat2 Keepalived_vrrp[367]: /usr/bin/curl -X GET -I --fail http://10.186.157.216:8008/primary exited with status 22
Mar 06 15:00:10 pgpat2 Keepalived_vrrp[367]: /usr/bin/curl -X GET -I --fail http://10.186.157.216:8008/primary exited with status 22
(...)

Ok on voit bien que sur le noeud pgpat2 la réponse de l’api REST de Patroni est en échec ce qui montre que l’instance PostgreSQL a bien le rôle standby.

Tests de défaillance:

Pour vérifier que la VIP bascule correctement, on utilisera deux à trois fenêtres XTERM:
– Une pour tomber et redémarrer le service Patroni noeud par noeud, et tester la connexion à PostgreSQL via la VIP.
– Une pour observer les changements de VIP entre conteneurs avec lxc list …
– Une avec un ping directement sur la VIP pour voir combien de hops sont perdus pendant la bascule.

Test 1 : arrêt de Patroni sur le leader:

root@ubuntu20:~# lxc exec pgpat1 -- systemctl stop patroni

Surveillance de la bascule:

root@ubuntu20:~# watch lxc list pgpat

Every 2,0s: lxc list pgpat                                                                                                                                                                         

+--------+---------+-------------------------+-----------------------------------------------+-----------+-----------+
|  NAME  |  STATE  |          IPV4           |                     IPV6                      |   TYPE    | SNAPSHOTS |
+--------+---------+-------------------------+-----------------------------------------------+-----------+-----------+
| pgpat1 | RUNNING | 10.186.157.60 (eth0)    | fd42:a4e7:fd78:5160:216:3eff:feaf:c4a5 (eth0) | CONTAINER | 0         |
|        |         | 10.186.157.199 (eth0:1) |                                               |           |           |
+--------+---------+-------------------------+-----------------------------------------------+-----------+-----------+
| pgpat2 | RUNNING | 10.186.157.216 (eth0)   | fd42:a4e7:fd78:5160:216:3eff:fe8c:9004 (eth0) | CONTAINER | 0         |
+--------+---------+-------------------------+-----------------------------------------------+-----------+-----------+
| pgpat3 | RUNNING | 10.186.157.3 (eth0)     | fd42:a4e7:fd78:5160:216:3eff:fe8c:fd27 (eth0) | CONTAINER | 0         |
+--------+---------+-------------------------+-----------------------------------------------+-----------+-----------+
(...)
Every 2,0s: lxc list pgpat                                                                                                                                                                         ubuntu20: Sun Mar  6 16:10:08 2022

+--------+---------+-------------------------+-----------------------------------------------+-----------+-----------+
|  NAME  |  STATE  |          IPV4           |                     IPV6                      |   TYPE    | SNAPSHOTS |
+--------+---------+-------------------------+-----------------------------------------------+-----------+-----------+
| pgpat1 | RUNNING | 10.186.157.60 (eth0)    | fd42:a4e7:fd78:5160:216:3eff:feaf:c4a5 (eth0) | CONTAINER | 0         |
+--------+---------+-------------------------+-----------------------------------------------+-----------+-----------+
| pgpat2 | RUNNING | 10.186.157.216 (eth0)   | fd42:a4e7:fd78:5160:216:3eff:fe8c:9004 (eth0) | CONTAINER | 0         |
|        |         | 10.186.157.199 (eth0:1) |                                               |           |           |
+--------+---------+-------------------------+-----------------------------------------------+-----------+-----------+
| pgpat3 | RUNNING | 10.186.157.3 (eth0)     | fd42:a4e7:fd78:5160:216:3eff:fe8c:fd27 (eth0) | CONTAINER | 0         |
+--------+---------+-------------------------+-----------------------------------------------+-----------+-----------+

Test de connexion depuis un client tiers:

root@ubuntu20:~# psql -U postgres -h 10.186.157.199 -p 5432 postgres \
-c "\conninfo"
Password for user postgres: 
You are connected to database "postgres" as user "postgres" 
on host "10.186.157.199" at port "5432".

Test 2 : Failback sur l’ancien primaire :
Restart de Patroni sur pgpat1 et stop sur pgpat2 :

root@ubuntu20:~# lxc exec pgpat1 -- systemctl start patroni
root@ubuntu20:~# lxc exec pgpat2 -- systemctl stop patroni

Surveillance de la bascule:

root@ubuntu20:~# watch lxc list pgpat

ubuntu20: Sun Mar  6 16:10:52 2022

+--------+---------+-------------------------+-----------------------------------------------+-----------+-----------+
|  NAME  |  STATE  |          IPV4           |                     IPV6                      |   TYPE    | SNAPSHOTS |
+--------+---------+-------------------------+-----------------------------------------------+-----------+-----------+
| pgpat1 | RUNNING | 10.186.157.60 (eth0)    | fd42:a4e7:fd78:5160:216:3eff:feaf:c4a5 (eth0) | CONTAINER | 0         |
+--------+---------+-------------------------+-----------------------------------------------+-----------+-----------+
| pgpat2 | RUNNING | 10.186.157.216 (eth0)   | fd42:a4e7:fd78:5160:216:3eff:fe8c:9004 (eth0) | CONTAINER | 0         |
|        |         | 10.186.157.199 (eth0:1) |                                               |           |           |
+--------+---------+-------------------------+-----------------------------------------------+-----------+-----------+
| pgpat3 | RUNNING | 10.186.157.3 (eth0)     | fd42:a4e7:fd78:5160:216:3eff:fe8c:fd27 (eth0) | CONTAINER | 0         |
+--------+---------+-------------------------+-----------------------------------------------+-----------+-----------+
(...)
Every 2,0s: lxc list pgpat                                                                                                                                                                         ubuntu20: Sun Mar  6 16:10:56 2022

+--------+---------+-------------------------+-----------------------------------------------+-----------+-----------+
|  NAME  |  STATE  |          IPV4           |                     IPV6                      |   TYPE    | SNAPSHOTS |
+--------+---------+-------------------------+-----------------------------------------------+-----------+-----------+
| pgpat1 | RUNNING | 10.186.157.60 (eth0)    | fd42:a4e7:fd78:5160:216:3eff:feaf:c4a5 (eth0) | CONTAINER | 0         |
|        |         | 10.186.157.199 (eth0:1) |                                               |           |           |
+--------+---------+-------------------------+-----------------------------------------------+-----------+-----------+
| pgpat2 | RUNNING | 10.186.157.216 (eth0)   | fd42:a4e7:fd78:5160:216:3eff:fe8c:9004 (eth0) | CONTAINER | 0         |
+--------+---------+-------------------------+-----------------------------------------------+-----------+-----------+
| pgpat3 | RUNNING | 10.186.157.3 (eth0)     | fd42:a4e7:fd78:5160:216:3eff:fe8c:fd27 (eth0) | CONTAINER | 0         |
+--------+---------+-------------------------+-----------------------------------------------+-----------+-----------+

et test de connexion depuis un client tiers:

root@ubuntu20:~# psql -U postgres -h 10.186.157.199 -p 5432 postgres \
-c "\conninfo"
Password for user postgres: 
You are connected to database "postgres" as user "postgres" 
on host "10.186.157.199" at port "5432".

Si on regarde les traces du ping sur la VIP pour observer le temps de bascule, on verra 2 à 3 hops perdus à chaque fois, ce qui correspond à environ 3 secondes d’interruption :

root@ubuntu20:~# ping -a 10.186.157.199
PING 10.186.157.199 (10.186.157.199) 56(84) bytes of data.
64 bytes from 10.186.157.199: icmp_seq=1 ttl=64 time=0.053 ms
64 bytes from 10.186.157.199: icmp_seq=2 ttl=64 time=0.089 ms
64 bytes from 10.186.157.199: icmp_seq=3 ttl=64 time=0.050 ms
64 bytes from 10.186.157.199: icmp_seq=4 ttl=64 time=0.112 ms
64 bytes from 10.186.157.199: icmp_seq=5 ttl=64 time=0.051 ms
From 10.186.157.216 icmp_seq=6 Redirect Host(New nexthop: 199.157.186.10)
From 10.186.157.60 icmp_seq=6 Redirect Host(New nexthop: 199.157.186.10)
From 10.186.157.60 icmp_seq=6 Destination Host Unreachable
64 bytes from 10.186.157.199: icmp_seq=10 ttl=64 time=1524 ms
64 bytes from 10.186.157.199: icmp_seq=11 ttl=64 time=504 ms
64 bytes from 10.186.157.199: icmp_seq=12 ttl=64 time=0.052 ms
64 bytes from 10.186.157.199: icmp_seq=13 ttl=64 time=0.094 ms
(...)

OK nous avons validé qu’en cas de perte du service Patroni, le cluster bascule et notre vip bascule correctement sur le nouveau primary. Je n’ai volontairement pas détaillé la partie Patroni, je vous renvoie sur l’article de Ludo cité au début.

Prochain épisode, nous verrons comment utiliser vip-manager de Cybertec, et le comparer à keepalived.

To be continued…. Bonne fin de weekend, à+

Continuez votre lecture sur le blog :

twitterlinkedinmail

David Baffaleuf

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée.

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.