XinCTO/vagrant multi noeuds pour swarm

Ecrit le Sun, 14 January 2018 16:35:06 +0000

vagrant multi noeuds pour swarm

Je vous propose pour cette rentrée un atelier de préparation des sujets que nous traiterons plus tard sur la base de docker swarm. Le but est d’utiliser vagrant pour préparer 4 noeuds et les configurer afin de recevoir swarm ; vagrant permet de construire l’orchestration sur la base d’une programmation, servons-en nous.

Si ce n’est pas déjà fait et que vagrant ça ne vous parle pas tant que cela, faites vous les dents avec le premier lab sur ce sujet. Ici, nous continuons sur la base d’un poste Windows disposant de vagrant et de virtualbox, sur d’autres environnements les principes devraient être assez similaires.

Sur la base de ce qui est présenté ici, vous pourrez monter un cluster swarm1 de 4 noeud en moins de 10 minutes (environ 2 minutes par noeud sur mon poste, le délai étant principalement lié à l’installation de docker).

Nous allons détailler ici les syntaxes afin de réaliser :

1- paramètres en tableau

Puisque nous avons à construire un cluster de plusieurs noeuds, nous n’allons pas utiliser un bloc de définition de VM par noeud mais utiliser un itérateur sur la base d’un tableau associatif reprenant l’ensemble des configurations des noeuds. Ce sera ainsi plus simple de modifier les paramètres, d’ajouter ou elever des noeuds, mais surtout le code spécifique de création de la VM sera bien plus simple à lire et à modifier si besoin.

Pour l’exemple, je propose de mettre en place une liste de noeuds avec les paramètres suivants : la taille mémoire, le nombre de vCPU et le rôle dans le cluster swarm, soit master soit slave. Le tableau étant associatif, nous utiliserons la clé comme le nom du serveur de donc de la VM, puisqu’elle doit être unique ce sera ainsi bien plus simple.

Le tableau est défini comme ça :

1cluster = {
2  "docker-node01" => { :cpu => 4, :mem => 4096, :swarm => "master" },
3  "docker-node02" => { :cpu => 2, :mem => 2048, :swarm => "slave" },
4  "docker-node03" => { :cpu => 2, :mem => 2048, :swarm => "slave" },
5  "docker-node04" => { :cpu => 2, :mem => 2048, :swarm => "slave" }
6}

Cette définition est globale à la configuration Vagrant, elle est donc à positionner en début de fichier, avant le Vagrant.configure.

Afin de l’exploiter, nous allons utiliser un intégrateur, il sera alors possible de récupérer les valeurs de l’index et le contenu pointé par celui-ci, par exemple :

1cluster.each_with_index do |(hostname, info), index|
2     puts "#{hostname} #{info[:cpu]}"
3end

2- renommer la VM

On utilise ici le paramètre name dans le provider virtualbox pour changer le nom de la VM, récupéré depuis le tableau des noeuds dans l’itération sur les membres du tableau associatif cluster comme l’index et nommé hostname.

1v.name = hostname

3- inventaire ansible

ansible travaille sur la base d’un fichier d’inventaire, dans notre précédent lab nous avions crée ce fichier à la main, mais ici, puisque nous souhaitons utiliser un tableau associatif ce n’est pas possible. La base de vagrant étant le ruby, il est possible d’utiliser le langage afin de préparer le fichier sur la base du tableau.

Le fichier possède 2 sections, la première détaille comment se connecter à chaque noeud, nous utilisons ansible_local, il faut donc le spécifier. La seconde partie liste les noeuds dans la section par défaut.

Nous utilisons l’itérateur afin de créer les 2 sections dans le même fichier, sur la base uniquement de la clé du tableau :

 1File.open('inventory' ,'w') do |f|
 2   cluster.each_with_index do |(hostname, info), index|
 3        f.write "#{hostname} ansible_connection=local\n"
 4   end
 5
 6   f.write "\n[default]\n"
 7
 8   cluster.each_with_index do |(hostname, info), index|
 9        f.write "#{hostname}\n"
10   end
11end

Ce bloc concerne toutes les VM et doit donc être positionné au niveau du Vagrant.configure.

4- trigger post création de VM

La création de la VM avec ansible permet de mettre en place les packages, mais ici il nous faut executer des commandes différenciées entre les noeuds et surtout récupérer des paramètres de nature dynamique comme l’adresse IP qui sera utilisée par le manager swarm.

Le principe est de mettre en place un trigger sur l’évènement de fin d’installation de chaque VM et en fonction de la nature du noeud dans le tableau de configuration d’effectuer des actions spécifiques. Sur le noeud de type manager (qui doit être le premier pour ne pas alourdir la configuration) on initialise le cluster swarm, sur les slave on rejoindra celui-ci. La commande docker swarm init retourne la commande à passer sur les noeuds slave, il nous faudra donc la récupérer et la stocker.

Vous aurez besoin d’installer le plugin spécifique à cette gestion des trigger :

1vagrant plugin install vagrant-triggers

Première étape, on détermine les actions en fonction de la nature du noeud (variable swarm dans notre tableau) :

1	config.trigger.after :up, :stdout => false, :stderr => false do
2		hostname = "#{@machine.name}"
3
4		if cluster[hostname][:swarm].eql? "master" then
5			puts "=> master swarm node"
6		else
7			puts "=> slave swarm node"
8		end
9	end

Sur la ligne 1, on positionne le trigger sur l’évènement :up, la ligne 2 récupère le nom de la VM qui vient d’être démarrée dans une chaîne de caractères. Nous allons utiliser le nom de la VM qui est également la clé de notre tableau associatif afin de trouver la nature du noeud, la ligne 4 vérifie s’il s’agit du master.

Il ne reste plus qu’à insérer le code spécifique pour les 2 cas de figure, la partie intéressante ici est comment executer une commande via la canal ssh mais aussi comment récupérer le résultat afin de pouvoir l’exploiter plus tard.

 1  if cluster[hostname][:swarm].eql? "master" then
 2     puts "=> master swarm node"
 3     get_ip_address = %Q(vagrant ssh #{@machine.name} -c "ip addr show eth1 | grep 'inet ' | cut -d' ' -f6 | cut -d/ -f1")
 4     output = `#{get_ip_address}`
 5     cluster[hostname][:ip] = "#{output.strip}"
 6     start_swarm = %Q(vagrant ssh #{@machine.name} -c "docker swarm init --advertise-addr #{cluster[hostname][:ip]} | fgrep 'join --token'")
 7     output = `#{start_swarm}`
 8     $swarm_join = "#{output.strip}"
 9  else
10     puts "=> slave swarm node"
11     start_swarm = %Q(vagrant ssh #{@machine.name} -c "#{$swarm_join}")
12     output = `#{start_swarm}`
13  end
  • ligne 3 : on défini la commande permettant de récupérer l’adresse IP de l’interface eth1 (dans mon cas)
  • ligne 4 : on exécute la commande, le résultat est positionné dans output
  • ligne 5 : on garde l’information de l’adresse IP du noeud master qui devra être réutilisé dans le démarrage du cluster swarm dans le paramètre --advertise-addr, puisque le serveur dispose de plusieurs interfaces réseau.
  • ligne 8 : on stock dans une variable globale la valeur de la commande permettant aux noeuds slave de rejoindre le cluster, puisque le trigger est exécuté à chaque démarrage de VM, une variable locale ne serait pas de portée suffisante

5- paramètre vers ansible

Certains paramètres dans le fichier playbook d’ansible peuvent nécessiter un ajustement en fonction de notre tableau de serveurs, ici par exemple nous allons utiliser le nom du serveur pour limiter la portée de l’installation d’une part et nommer le serveur afin de s’y retrouver lorsque nous y serons connecté.

Dans la section ansible_local nous allons utiliser la variable ansible.extra_vars afin de positionner la variable vag_name au nom de la VM que nous sommes en train de construire, récupéré comme précédemment via hostname qui est la clé de notre tableau associatif :

1ansible.extra_vars = {
2 vag_name: hostname
3}

et récupérer les variables dans le fichier ansible, ici avec vag_name :

1- name: lab
2  hosts: "{{ vag_name }}"
3
4  tasks:
5    - name: set hostname
6      hostname:
7        name: "{{ vag_name }}"

Conclusion

Et voilà un résumé rapide de quelques outils qui vous permettrons de simplifier très largement votre fichier de paramétrage de vagrant tout en bénéficiant de fonctionnalités avancées. Ici l’exemple est assez simple, vous pourriez faire des choses bien plus complexes.

J’ai volontairement cherché des solutions permettant de conserver le maximum d’autonomie dans la construction des VM, notamment en m’interdisant de positionner à l’avance les adresses IP, vous trouverez ce type de méthode sur d’autres articles, mais je trouve que la solution est trop restrictive et pas très élégante. Enfin, disposer de moyen de récupérer des informations d’une VM récemment construite est un bon moyen d’enrichir le fonctionnement du couple vagrant + ansible.

Vous trouverez les sources de base sur mon git dans le labo d’orchestration.

Nous utiliserons cette base dans notre prochain lab à base de swarm, notamment en préparation un sujet sur openfaas, stay tuned.


Photo from jesse orrico


  1. nous verrons plus tard pour passer sur kubernetes suite aux récentes annonces de docker sur le sujet de l’orchestration, mais pour l’instant swarm est supporté ↩︎