Orchestration Tools

Présentation
Enseignants : D. Donsez, GP. Bonneau

Sujet : Orchestration Tools : Puppet vs. Chef vs. Ansible vs. Salt

Auteur : Robin EUDES

Abstract
There is more and more data center in the world, and virtualization is massively used. With the emergence of the cloud, automatics deployments of new systems to guarantee and maintain a quality of service are necessary. So, the number of physical or virtual servers managed by a sysadmin becomes quickly exponential. A manual administration is, obviously, not a realistic option anymore.

The administration, previously realized by a local and physical connection to the server, is now remote and massive (multiples servers). Orchestration tools are an answer to this need. These tools will have to be able to setup a configuration, and guarantee a good behavior of the managed services.

Résumé
Il y a de plus en plus de datacenters dans le monde, la virtualisation de serveurs est massivement présente. Avec l'émergence du cloud, des solutions de déploiement automatique de nouveaux serveurs pour assurer et maintenir une qualité de service sont nécessaires. Ainsi, le nombre de serveurs physiques ou virtuels à la charge d'un administrateur système devient rapidement exponentiel. Une administration manuelle n'est plus possible, le besoin d'une automatisation des configurations est évident.

L'administration qui pouvait auparavant être réalisée en se connectant localement sur un serveur est maintenant distante et massive. C'est à ce niveau que se positionnent les outils d'orchestration, qui vont avoir pour rôle d'assurer la mise en place d'une configuration sur un ensemble de machines, mais aussi le bon fonctionnement des services.

Introduction
Avec la généralisation des solutions faisant intervenir le cloud et le besoin de dynamicité dans les architectures mise en œuvre, les outils d'orchestration sont rapidement devenus indispensables. Là où auparavant, un site web était hébergé sur un unique serveur facilement administrable, la plupart des hébergeurs proposent maintenant des solutions intégrant de la répartition de charge (load balancing) selon les besoins dynamiques du site. Ces sociétés ont donc un fort besoin d'orchestration: installation d'une nouvelle machine, installation des services associés, intégration avec le service en cours d’exécution, entre autres.

Tout administrateur système, quelle que soit la taille du parc informatique qu’il a sous sa responsabilité; va chercher à automatiser au possible les tâches pénibles ou répétitives. On pourrait bien entendu imaginer dans un premier temps une connexion distante réalisée manuellement par l’administrateur : une connexion ssh suivie d’un script bash que l’on exécute. Cependant, cette solution est très limitée, il faut connaitre les mots de passe de chaque machine auxquelles on veut se connecter, ce qui devient très rapidement une perte de temps majeure dans une infrastructure conséquente. De plus, l’aspect répétitif reste encore très présent et pour peu que les machines aient quelques différences de configuration, le script qui fonctionne sur une ne fonctionnera pas nécessairement sur l’autre. Il est très fréquent dans les parcs informatiques assez anciens d’avoir plusieurs versions de différents logiciels en cours d’utilisation suivant la date d’installation du service. Les mises à jour deviennent très rapidement un casse-tête, et ne sont très souvent jamais réalisées (bien que d’autres problématiques interviennent pour cet exemple, telles que la compatibilité de l’application courante). Sans pour autant vouloir assurer une mise à jour, la modification d’un paramètre commun à l’ensemble des machines devient ingérable. De manière générale, un parc informatique va très rapidement être très hétérogène, ce qui tend à complexifier l’administration.

En tant qu’administrateur système, on va vouloir conserver autant que possible une vue générale de notre parc informatique, en décrivant au travers d’outils de haut niveau la configuration souhaitée, sans se préoccuper de sa réalisation effective. Autrement dit, se concentrer que le « quoi » plus que sur le « comment ». Ce paradigme est dit « déclaratif », et plusieurs outils présentés par la suite vont choisir cette approche. D’autres auront une approche un peu plus mixte, se rapprochant du paradigme « impératif » et de la réalisation concrète des actions (le « comment » évoqué ci-dessus). Avec les deux paradigmes évoqués, nous touchons directement un concept qui résume parfaitement l’idée des outils d’orchestration : « infrastructure as code ». Quel que soit l’outil utilisé, nous allons chercher à décrire notre infrastructure, les configurations souhaitées sous forme de « code » plus ou moins haut-niveau. Ces outils intègrent également les notions de push et pull, présentes dans les outils de versioning, tel que Git.

Un point reste à mentionner, avant de commencer cette étude : la différence entre outils d’automatisation et outils d’orchestration, entre « tache » et « processus ». L’optimisation d’un processus ne peut pas être réalisée simplement en automatisant des tâches. L’automatisation va être autour d’une seule tâche, l’orchestration va être sur l’ensemble du workflow, sur le processus global. Par exemple, on va pouvoir automatiser l’installation des différents composants d’une architecture trois-tiers. L’outil d’orchestration ne va pas se limiter à installer ces composants, mais s’assurer qu’ils sont déployés dans le bon ordre, en optimisant le processus global.

Étude comparative
Chronologie des principaux outils d'orchestration



Présentation
La première version de Puppet est publiée en 2005. Luke Kanies, un utilisateur de CFEngine (CFEngine 2 à l’époque) n’est pas satisfait de la façon dont est géré le projet, et décide de lancer le projet « Puppet ». CFEngine est un des précurseur dans le domaine des outils d'orchestration. Nous l'étudierons pas davantage ici, il est actuellement dans sa version 3.*. Il est encore utilisé par des acteurs majeurs, tel qu'Intel ou LinkedIn.

Puppet en quelques lignes :
 * Un langage dédié, inspiré du Ruby pour la description des configurations (Une bonne connaissance du Ruby est recommandée)
 * Une configuration client-serveur, avec un ou des serveurs dits « masters » qui vont centraliser les descriptions des états voulus pour les clients. Chaque machine devra être équipée en conséquence du package « serveur » ou « client » de Puppet.
 * Plateforme : multiplateforme
 * Paradigme : déclaratif
 * Prix : environ 100$ / nœud /an pour le support “standard” (dans sa version "Entreprise"). Il existe une version "Community" gratuite.
 * Les communications entre le serveur et le client s’effectuent via HTTPS.
 * L’authentification du client par le serveur s'effectue par certificat SSL.
 * Une interface web est disponible dans la version Entreprise



Principe de fonctionnement (un peu plus détaillé) :



Auparavant, les échanges été réalisés sous la forme d’appels XML-RPC sur HTTPS, depuis la version 3 de Puppet, le fonctionnement a changé, on utilise désormais une API REST, accessible via HTTPS endpoints (autrement dit, une url). Le fonctionnement global reste identique.

Puppet est également capable de fonctionner avec un ENC (External Node Classifier). Par défaut, les scénarios à appliquer à un nœud (client) sont définis dans un unique fichier, lu par le serveur master. Cependant, ce fichier peut devenir très lourd et illisible, pour peu que l’on ait un nombre important de nœuds à gérer. Il est alors possible de décharger cela vers un programme externe appelé par le serveur (programme écrit dans le langage de notre choix), auquel on transmet le FQDN du client (Fully qualified domain name). On peut par exemple choisir de faire fonctionner Puppet avec un annuaire LDAP dans lequel seraient stockés les scénarios à appliquer.

Exemple de code
Les exemples suivants sont tirés de la documentation du module "apache ", que l'on peut télécharger dans Puppet. La communauté est très active sur Puppet, il est donc très fréquent de trouver un module qui effectuera l'opération voulue sans avoir besoin de développer notre module "from scratch".

Installation sur un client d'Apache, configuration de l'hôte virtuel, et spécification du certificat SSL (à placer sur le Puppet Master): apache::vhost { 'fourth.example.com': port    => '443', docroot => '/var/www/fourth', ssl     => true, ssl_cert => '/etc/ssl/fourth.example.com.cert', ssl_key => '/etc/ssl/fourth.example.com.key', }

Plutôt puissant, non ? :)

La documentation de ce plugin fournit de très nombreux exemples. Pour résumer, on peut ici décrire n'importe quelle configuration Apache, et très facilement la déployer sur des nouvelles machines.

Actuellement, 3699 modules sont présents sur la forge officielle.

Il peut donc être intéressant d'aller y faire un tour avant de réinventer la roue. On peut par exemple citer un module permettant de gérer nos instances AWS dans le cloud d'Amazon (AWS Module).

Présentation
La première version de Chef est publiée en 2009. Adam Jacobs, un utilisateur expérimenté de Puppet n’est pas satisfait du fonctionnement de Puppet. L’explication de ce « fork » trouve ses origines dans la méthode d’ordonnancement au sein d’un scénario de Puppet. Comme nous avons pu le voir avec Puppet, nous pouvons décrire plusieurs tâches à effectuer, l’ensemble de ces taches constituant ledit « scénario ». La différence entre Puppet et Chef va être autour de la façon de gérer l’ordonnancement des différentes taches.

Puppet fonctionne avec un graphe de dépendance, alors que Chef est basé sur un ordre procédural (c’est-à-dire l’ordre dans lequel on a écrit les règles). Chef, qui a fait le choix d’utiliser une description de ses « recettes » (l’équivalent des « scénarios » de Puppet) avec un langage dédiée pure-Ruby « s’offre » gratuitement de l’ordonnancement, grâce à l’utilisation du langage Ruby. En conséquence, nos configurations décrites via Chef auront tout le temps un ordre implicite, même si cela n’a pas d’importance pour nous. Dans Puppet, nous n’avons pas à nous préoccuper de l’ordonnancement. Cependant, si nous avons besoin de nous assurer d’un ordonnancement précis, nous pouvons alors le spécifier.

Chef en quelques lignes :


 * Un langage dédié, mais « pure-Ruby » pour la description des configurations.
 * Une configuration client-serveur, avec un ou des serveurs dits « masters » qui vont centraliser les descriptions des configurations des clients. Chaque machine devra être équipée en conséquence du package « serveur » ou « client » de Chef.
 * Paradigme : impératif (de par l’utilisation du Ruby)
 * Cet outil d’orchestration est multiplateforme.
 * Prix : environ 75$ / nœud /an pour un support « standard »



Les communications entre le client et le serveur se font via http, grâce à une API REST disponible sur le serveur. Le serveur n’accepte ici que les requêtes authentifiées. Pour cela, lors de la configuration du client chef, une paire de clés RSA est générée. La clé publique est stockée sur le serveur chef, tandis que la clé privée est conservée chez le client. Lors des échanges avec l’API, certains champs du header HTTP seront encryptés grâce à la clé privée, et le serveur pourra, grâce au jeu de clé publique dont il dispose authentifier le client.

Exemple de code
Comme pour Puppet, nous allons chercher à installer un serveur Apache, avec un hôte virtuel. Pour cela, plusieurs modules sont à récupérer, mais la configuration est "à peine" plus complexe (module ssl-config et module apache2):

Afin de comprendre cet exemple, il est nécessaire de se pencher légèrement sur l'architecture de Chef. Un Cookbook (livre de cuisine) se compose de recipes, attributes, templates, entre autres. La liste complète des composants se trouve ici.

La recette (recipe) se décrira ainsi :

{  "run_list": [ "recipe[apache2]" "recipe[ssl-config::apache]" ] }

Avec le template suivant à appliquer :

 ServerName example.com SSLEngine on  SSLCertificateFile      /path/to/signed_certificate SSLCertificateChainFile /path/to/intermediate_certificate SSLCertificateKeyFile  /path/to/private/key SSLCACertificateFile   /path/to/all_ca_certs include /etc/apache2/secure-ssl.conf #... 

Un exemple plus complet, plus explicite, mais n'utilisant pas ces modules est disponible ici. Comme vous pouvez le voir, les modules proposés par la communauté réduisent grandement le code nécessaire !

Présentation
La première version de Salt est publiée en 2011. Cette fois-ci, il ne s’agit pas d’un « fork » de Chef réalisé par un utilisateur mécontent, il s’agit d’une approche assez différente du problème. Cet outil était initialement destiné à de l’exécution distante, l’aspect « gestion de configuration » a été intégré à l’outil par la suite. L’outil est développé en Python, tout module que l’on souhaite intégrer doit donc être réalisé dans ce langage. On peut choisir lors de l’installation 2 protocoles de transport : ZeroMQ ou RAET (Reliable Asynchronous Event Transport). Par défaut, Salt utilisera ZeroMQ, si rien n’est spécifié. On peut modifier cela à tout moment par la suite. Comme les précédents outils étudiés, Salt fonctionne sur un principe client/serveur, appelé ici master/minion. L’authentification repose ici sur une paire de clés RSA, le serveur doit accepter la clé publique du client avant que ce dernier puisse dialoguer avec le serveur (en encryptant les échanges avec sa clé privée par la suite, donc !).

La grande différence de Salt avec les précédents outils évoqués réside dans le « sens » des communications. En effet, c’est le serveur qui va ici « pousser » les configurations sur les clients.

Salt en quelques lignes :
 * Pas de langage dédié, nos descriptions seront au format YAML ou Python
 * Une configuration client-serveur, avec un ou des serveurs dits « masters » qui vont centraliser les descriptions des configurations des clients. Chaque machine devra être équipée en conséquence du package « serveur » ou « client » de Salt.
 * Cet outil d’orchestration est multiplateforme.
 * Paradigme : descriptif, mais également impératif, selon l'utilisation
 * Prix : environ 100$ / nœud /an pour le support “standard”
 * Les communications entre le serveur et le client s’effectuent via ZeroMQ ou RAET. Ces protocoles offrent des performances intéressantes dans les infrastructures conséquentes.

Un système de « schedule » dans la description des tâches va permettre leur répétition à intervalle régulier sur les clients. Afin d’assurer la cohérence des configurations, on devra jouer sur le « schedule » aussi bien au niveau des minions que du master : une tache déployée sur un client s’effectuera par exemple chaque jour à minuit. Par défaut, une seule version de la tache peut tourner à la fois. En cas de modification de la tache sur le master, il suffira alors de redéployer cette dernière sur les minions pour que ces derniers exécutent la dernière version. La notion de version prend ici une importance toute particulière.

On peut assez facilement mettre en place plusieurs masters, afin d'assurer une montée en charge (exemple ici).

Exemple de code
Encore une fois, nous allons chercher à réaliser le même exemple : installer Apache, et configurer un hôte virtuel (exemple ici). Pour cela, la configuration voulue sera décrite ainsi dans Salt :

Soit un fichier "state" apache-vhost.sls :

/etc/httpd/extra/httpd-vhosts.conf: file.managed: - source: salt://webserver/httpd-vhosts.conf apache: pkg.installed: [] service.running: - watch: - file: /etc/httpd/extra/httpd-vhosts.conf - require: - pkg: apache

Bien entendu, le fichier salt://webserver/httpd-vhosts.conf (stoké sur le server master) devra être un fichier valide. En effet, à l'exécution sur le minion, ce dernier va comparer son fichier /etc/httpd/extra/httpd-vhosts.conf avec celui présent sur le serveur : salt://webserver/httpd-vhosts.conf. On a donc ici décrit assez simplement un état voulu.

Pour déployer cette configuration sur l'ensemble de nos clients, cela est réalisé assez simplement :

salt '*' state.sls apache-vhost

Cette commande va pousser cette configuration sur l'ensemble des minions matchant la regex (tous ici...).

Présentation
La première version d’Ansible est publiée en 2012. Comme pour Salt, cet outil est développé en Python. Tout comme Salt, Ansible va chercher à pousser une configuration vers des clients. Mais à la différence de tous les autres outils d’orchestration évoquée plus tôt, ce dernier ne nécessite pas de client spécifique, seulement un démon SSH présent sur le client.

Les modules pourront être développés dans n’importe quel langage tant que la sortie est valide (format de données : JSON).

Ansible en quelques lignes :
 * Pas de langage dédié, nos descriptions seront au format YAML
 * Pas de client-serveur ici, simplement un serveur « ansible » et des clients avec un démon SSH.
 * Cet outil d’orchestration est multiplateforme.
 * Paradigme : impératif
 * Prix : environ 75$ / nœud /an pour le support “standard »
 * Les communications sont réalisées via SSH

Bien que les « playbook » d’Ansible soit en YAML (qui est descriptif), l’exécution est réalisée en séquence, d’où le paradigme impératif.

Le serveur initiant la connexion SSH vers les clients, pour des facilités de connexion, il est nécessaire d'utiliser l'authentification par clé publique.

Exemple de code
Comme précédemment, nous allons chercher à réaliser le même exemple (installation d'Apache avec un hôte virtuel). Voici un exemple, tiré de ce tutoriel :

Soit un fichier apache.yml

--- - hosts: apache sudo: yes vars: http_port: 80 domain: example.com tasks: - name: install apache2 apt: name=apache2 update_cache=yes state=latest - name: enabled mod_rewrite apache2_module: name=rewrite state=present notify: - restart apache2 - name: apache2 listen on port lineinfile: dest=/etc/apache2/ports.conf regexp="^Listen " line="Listen " state=present notify: - restart apache2 - name: apache2 virtualhost on port lineinfile: dest=/etc/apache2/sites-available/000-default.conf regexp="^" notify: - restart apache2 - name: create virtual host file template: src=virtualhost.conf dest=/etc/apache2/sites-available/.conf - name: a2ensite command: a2ensite args: creates: /etc/apache2/sites-enabled/.conf notify: - restart apache2 handlers: - name: restart apache2 service: name=apache2 state=restarted

Ce fichier de configuration est associé à un groupe (du même nom) de machines cibles, décrit dans la configuration d'Ansible. On peut également remarquer que cette configuration fait appel à plusieurs templates. Par exemple, le template virtualhost.conf a la forme suivante :

 ServerAdmin webmaster@ ServerName ServerAlias www. DocumentRoot /var/www/ ErrorLog ${APACHE_LOG_DIR}/error.log CustomLog ${APACHE_LOG_DIR}/access.log combined 

Cette configuration sera exécutée et appliquée sur les machines distantes ainsi :

ansible-playbook apache.yml --ask-sudo-pass

Conclusion
Chacun des différents outils présentés ici fournit globalement les mêmes fonctionnalités. Comment orienter notre choix alors ?

Il faut d’abord tenir compte des contraintes qui nous sont imposées, tel que la présence d’un autre outil d’orchestration.

Ensuite, nos préférences personnelles interviennent. Des développeurs seront probablement plus à l’aise avec Puppet ou Chef, pour peu qu’ils aient une connaissance du Ruby. Les administrateurs système auront peut-être une préférence pour Salt ou Ansible à l’inverse.

Enfin, le support de la communauté peut être un facteur déterminant. En effet, les outils d’orchestration les plus anciens ont une communauté plus ancienne, et donc une plus grande quantité de modules proposés par la communauté.

Références

 * CFEngine
 * Puppet Labs
 * Chef
 * Salt
 * Ansible
 * "Infrastructure as Code" - DevOps
 * Automatisation vs Orchestration
 * Détail des communications HTTPS client-serveur Puppet (attention, le diagramme décrit un fonctionnement qui n'est plus tout à fait l'actuel)
 * Documentation API Puppet
 * Puppet avec un ENC...
 * Documentation du module apache pour Puppet
 * Documentation module apache2 pour Chef
 * Documentation module ssl-config pour Chef
 * Création d'un cookbook complet avec Chef - apache2 + vhost
 * Protocol ZeroMQ
 * Protocole RAET
 * Exemple serveur apache + vhost avec Salt
 * Scalability & Redundancy with Salt
 * Ansible vs Puppet
 * Tutorial Ansible Ubuntu - Apache