Équilibreurs de charge pour les systèmes d'orchestration

Les équilibreurs de charge dans les systèmes d'orchestration (Kubernetes, Nomad et autres) ont plus d'exigences que le simple équilibrage de charge. Premièrement, l'équilibreur de charge doit pouvoir lire un répertoire avec une liste de services vers lesquels le trafic doit être redirigé (ou, en option, permettre aux services de s'enregistrer pour les inclure dans le trafic). Deuxièmement, faites-le dynamiquement, car Les systèmes d'orchestration peuvent à tout moment augmenter ou diminuer le nombre de répliques de services, ou les déplacer vers d'autres adresses sur le réseau. Et troisièmement, faites-le sans arrêter le trafic.

Dans le post d'aujourd'hui, je décrirai le travail avec deux équilibreurs de charge - Traefik et HAProxy. Ces équilibreurs de charge ont la capacité de travailler avec une liste impressionnante d'outils d'orchestration. Les exemples décrivent comment travailler avec le système d'orchestration Nomad.

Dans le dernier article, j'ai déjà donné un exemple d'équilibreurs de charge - Fabio. Ses limites: ne fonctionne qu'avec les protocoles http / https et ne fonctionne qu'avec Consul. Contrairement à Fabio, Load Balancers Traefik fonctionne avec un nombre impressionnant de systèmes différents. Voici une liste partielle tirée du site du développeur: Docker, Swarm mode, Kubernetes, Marathon, Consul, Etcd, Rancher, Amazon ECS, ...

Je vais continuer l'exemple du post précédent , dans lequel plusieurs répliques du service django ont été créées.

Traefik peut être téléchargé sur le site du développeur sous forme de fichier exécutable pour les systèmes d'exploitation les plus courants. Pour intégrer avec Nomad (en fait avec Consul), vous devez créer un fichier de configuration:

[entryPoints] [entryPoints.http] address = ":5001" [web] address = ":8080" [consulCatalog] endpoint = "127.0.0.1:8500" domain = "consul.localhost" exposedByDefault = false prefix = "traefik" 

Et puis exécutez la commande avec le fichier de configuration donné:

 traefik -c nomad/traefik.toml 

Après cela, UI Traefik sera disponible sur le port 8080, qui n'a pas encore publié de services. Il existe plusieurs façons de publier des services, qui finissent par faire la même chose: ils chargent les données clés / valeurs dans le système Traefik. Nous en profiterons pour définir des paires clé / valeur via des balises de service. Développons le fichier de configuration du service django avec le paramètre tags:

 job "django-job" { datacenters = ["dc1"] type = "service" group "django-group" { count = 3 restart { attempts = 2 interval = "30m" delay = "15s" mode = "fail" } ephemeral_disk { size = 300 } task "django-job" { driver = "docker" config { image = "apapacy/tut-django:1.0.1" port_map { lb = 8000 } } resources { network { mbits = 10 port "lb" {} } } service { name = "django" tags = [ "traefik.enable=true", "traefik.frontend.entryPoints=http", "traefik.frontend.rule=Host:localhost;PathStrip:/test", "traefik.tags=exposed" ] port = "lb" check { name = "alive" type = "http" path = "/" interval = "10s" timeout = "2s" } } } } } 

Dans cet exemple, le service sera publié sur l'hôte localhost et monté sur la route / test. Traefik a développé un système de règles flexible et complet pour la configuration des itinéraires, y compris le travail avec des expressions régulières. La liste des paramètres des règles dans la documentation du développeur.

Après l'exécution de la commande nomad job run nomad/django.conf règles sont appliquées et le trafic provenant de l'équilibreur de charge est dirigé vers le service. En conséquence, vous pouvez modifier ces paramètres, déployer une nouvelle option de service avec la commande nomad job run nomad/django.conf , et toutes les modifications seront appliquées sans arrêt gênant du trafic.

L'inconvénient de Traefik est qu'il fonctionne avec les protocoles de la famille http / https (juste au cas où, je note que cette famille comprend également des sockets web). Mais il existe toujours une telle possibilité qu'il sera nécessaire de travailler avec d'autres protocoles. Passons donc à la prochaine solution plus large basée sur HAProxy. Il y a quelque temps, HAProxy avait des problèmes avec le chargement doux, ce qui rendait son utilisation difficile avec les systèmes d'orchestration (lors du redémarrage, il était nécessaire d'arrêter le mouvement des paquets au niveau du réseau). Maintenant, ce n'est plus un problème.

Vous devez d'abord installer haproxy sur votre ordinateur. Ici, l'option d'installation à l'intérieur du conteneur ne fonctionnera pas. Dans haproxy, ce n'est que récemment qu'il est devenu possible de redémarrer le processus en mode «doux», mais le conteneur docker s'arrête toujours, puisque le deuxième processus démarre réellement avec haproxy, il change juste en mode veille - ce qui ne fonctionne pas avec le docker et son principe «one» -container est un processus. "

Pour que haproxy fonctionne, vous devez disposer d'un fichier de configuration contenant les règles nécessaires. Nomad (en fait dans Consul) utilise un système de modèles qui peut générer des configurations:

 global debug defaults log global mode http option httplog option dontlognull timeout connect 5000 timeout client 50000 timeout server 50000 frontend http_front bind *:5001 stats uri /haproxy?stats default_backend http_back backend http_back balance roundrobin{{range service "django"}} server {{.Node}} {{.Address}}:{{.Port}} check{{end}} 

Dans ce cas, le mot clé range agit comme un itérateur. Pour les trois services «django», le fichier de configuration suivant sera généré:

 global debug defaults log global mode http option httplog option dontlognull timeout connect 5000 timeout client 50000 timeout server 50000 frontend http_front bind *:5001 stats uri /haproxy?stats default_backend http_back backend http_back balance roundrobin server 228.195.86.224 127.0.0.1:21469 check server 228.195.86.224 127.0.0.1:25872 check server 228.195.86.224 127.0.0.1:25865 check 

La bibliothèque https://github.com/hashicorp/consul-template est utilisée pour démarrer le processus de génération selon le modèle à la volée. À partir de la ressource du développeur, vous pouvez télécharger le fichier exécutable pour tous les systèmes d'exploitation courants et démarrer le processus au nom d'un utilisateur non autorisé avec la commande:

 consul-template -template="haproxy/haproxy.cfg.tmpl:haproxy/haproxy.cfg:./haproxy/haproxy.reload.sh" 

Le paramètre -template contient des paramètres séparés par deux-points 1) le nom du modèle, 2) le nom du fichier de configuration résultant 3) la commande qui est exécutée après la génération du fichier. Le fichier sera généré automatiquement si les variables incluses dans le modèle sont modifiées (par exemple, le nombre de répliques du service django est modifié).

Après avoir démarré le moteur de modèle qui générera la première configuration, vous pouvez exécuter haproxy:

 haproxy -D -f haproxy/haproxy.cfg -p `pwd`/haproxy.pid 

Nous spécifions explicitement le fichier pid afin de pouvoir envoyer un signal à la surcharge haproxy «soft»:

 haproxy -D -f ./haproxy/haproxy.cfg -p `pwd`/haproxy.pid -sf $(cat `pwd`/haproxy.pid) 

Dans cet exemple, le service est publié sur le port 5001. Sur le même port, vous pouvez afficher les statistiques de haproxy lui-même à l'adresse /haproxy?stats .

MISE À JOUR 24/02/2019 22:43

Selon le commentaire de @ usego , un raffinement supplémentaire a été apporté au fonctionnement de haproxy dans le conteneur docker, notamment selon le fragment de la documentation github.com/neo4j/docker-library-docs/tree/master/haproxy#reloading-config

Recharger la config

Si vous avez utilisé un montage de liaison pour la configuration et avez modifié votre fichier haproxy.cfg, vous pouvez utiliser la fonction de rechargement gracieuse de HAProxy en envoyant un SIGHUP au conteneur:

$ docker kill -s HUP my-running-haproxy

Le script de point d'entrée dans l'image vérifie l'exécution de la commande haproxy et la remplace par haproxy-systemd-wrapper de HAProxy en amont qui prend en charge la gestion du signal pour effectuer le rechargement gracieux. Sous le capot, cela utilise l'option -sf de haproxy donc "il y a deux petites fenêtres de quelques millisecondes chacune où il est possible que quelques échecs de connexion soient remarqués lors de charges élevées" (voir Arrêt et redémarrage de HAProxy).


Avec cette approche, la configuration est vraiment rechargée, mais à la suite d'une interruption du processus en cours. Et cela signifie que les services auront, bien que très insignifiants, mais néanmoins une période d'inaccessibilité et certains clients pourront observer un message d'erreur. Mais parfois, ce n'est pas le principal critère de sélection. Par conséquent, je donnerai en plus la configuration docker-compose.yml pour lancer haproxy dans docker:

 version: '3' services: haproxy_lb: image: haproxy volumes: - ./haproxy:/usr/local/etc/haproxy network_mode: host 


La commande qui surchargera la configuration haproxy changera également:

 consul-template -template="haproxy/haproxy.cfg.tmpl:haproxy/haproxy.cfg:docker kill -s HUP $(docker-compose ps -q haproxy_lb)" 


Les avantages de cette implémentation incluent la possibilité de travailler sans installer de haproxy.

Un exemple de code est disponible dans le référentiel.

Liens utiles:

1.www.haproxy.com/blog/haproxy-and-consul-with-dns-for-service-discovery
2.m.mattmclaugh.com/traefik-and-consul-catalog-example-2c33fc1480c0
3.www.hashicorp.com/blog/load-balancing-strategies-for-consul

apapacy@gmail.com
24 février 2019

Source: https://habr.com/ru/post/fr441534/


All Articles