Ansible est l’outil de déploiement incontournable qui vaut le détour. Nous parcourrons les bases de l’outil et les bonnes pratiques au travers de cet article.
Nous apportons beaucoup d’importance à cette technologie et avons écrit une Refcard pour bien débuter.
Un peu d’histoire
Ansible c’est quoi ?
Ansible est un outil de gestion de configuration (Configuration Management) qui permet le déploiement et l’automatiser d’actions sur les serveurs distants.
Ansible se base sur la syntaxe YAML pour décrire très simplement les actions et clarifier indéniablement leur contenu. Il s’utilise avec une simple connexion SSH et n’embarque aucun agent à installer sur les serveurs distants.
Les sources Ansible sont disponibles sur GitHub : https://github.com/ansible/ansible
Le site officiel renferme une documentation claire et détaillée : https://docs.ansible.com/ansible/latest/index.html
Qui contribue ?
Ansible a été créé par Michael DeHaan et publié pour la première fois en 2012. La société Ansible a été rachetée par RedHat en 2015, qui est l’un des plus gros contributeurs aux sources de l’outil.
La communauté Ansible est très présente sur internet, tant par leur contribution aux sources que par leurs nombreuses questions/réponses aux problématiques exposées sur StackOverFlow.
Les concepts de base
Ansible est peut-être simple d’utilisation, il est néanmoins nécessaire de connaitre les quelques concepts de base qu’impose l’outil.
Le mode de connexion
Ansible se veut “agentless” et ne nécessite qu’une connexion SSH pour se connecter aux serveurs distants.
Les agents posent des problèmes d’exploitation et de maintenabilité.
Il suffit de créer un utilisateur (commun) sur les serveurs distants et de procéder à l’ouverture du tunnel SSH. La connexion aux hôtes peut se faire de 2 façons : par mot de passe ou par partage de clés publique. Je vous incite fortement à utiliser le partage de clé publique pour pérenniser la connexion et limiter les risques d’intrusion.
N’oubliez pas que protéger un serveur par login/password est aussi efficace qu’installer une porte d’entrée en carton : un coup d’épaule et on est à l’intérieur…
Les objets de base
Ansible vient avec une multitude d’objets et de termes que vous découvrirez avec plaisir en pratiquant l’outil.
Je me dois d’amorcer votre apprentissage avec les objets incontournables (avec les termes en anglais) :
- Une tâche (task) sont une action décrite en YAML qui formalise une action à appliquer,
- Un hôte (host) représente un serveur distant,
- Un inventaire (inventory) est une collection d’hôte qui forme très souvent un parc applicatif ou un environnement,
- Un playbook (playbook ^^) constitue la convergence des hôtes et des tâches (à appliquer sur les hôtes),
- Un rôle (role) est l’agrégation de tâches et de fichiers qui forme un composant consistant réutilisable,
- Une variable (var, host_var, group_var, role_var, extra_var) est une variable =) mais elle comporte une portée différente selon l’endroit où elle est définie (host, group, role, external).
Passons à la pratique
L’article a été écrit à l’aide du système d’exploitation CentOS 7.
Rester à jour est important
Ne vous basez pas sur les repos de base de CentoS/RHEL, vous risquerez d’être déçu de la version d’Ansible disponible. Installez le repo EPEL qui vous permettra de récupérer la dernière version disponible.
La version d’Ansible avec les repos de base :
yum list ansible
Etendons les repos CentOS/RHEL :
yum install -y epel-release
La version d’Ansible avec les repos étendus :
yum list ansible
Ca va tout de suite mieux !!!
Install party !
C’est parti pour installer Ansible, vous allez voir, c’est compliqué :
yum install -y ansible
Et c’est tout !
Un peu de configuration
Fichiers de configuration
Ansible se configure à plusieurs niveaux :
- Système :
- Fichier
/etc/ansible/ansible.cfg
- Valable pour toute exécution depuis le serveur,
- Fichier
- Répertoire :
- Fichier
$PWD/ansible.cfg
- Toutes les exécutions réalisées dans le répertoire courant,
- Fichier
- Exécution :
- Options fixées dans les playbooks Ansible du projet
- Toutes les exécutions en lien avec les fichiers chargés
La configuration se surcharge en privilégiant celle au plus près de la commande exécutée.
Options de base
La configuration de base vous permet d’utiliser Ansible simplement. Les seules subtilités à connaitre sont les suivantes :
Port de connexion
La connexion sur l’hôte distant se fait par connexion SSH sur le port 22
.
Utilisateur distant
La connexion sur l’hôte distant se fait nativement avec le même utilisateur que l’hôte d’origine.
Exemple : root@source > root@destination
Test de connexion
A chaque action réalisée par Ansible se la machine distante, un test de connexion est réalisé en plusieurs étapes :
- Test de connexion sur le port distant,
- Test de transfert d’un fichier sur l’hôte distant,
- Test d’exécution d’une librairie de base d’Ansible sur l’hôte distant,
- Test de retour d’état de la commande sur l’émetteur de la commande.
Le transfert de fichier sur le serveur distant se fait maintenant en SCP. Jusqu’en version 2.4, le transfert était initialement configuré en FTP.
Structure de base
Pour bien démarrer Ansible, mettons en places quelques bonnes pratiques de setup et de mises en place.
Si vous travaillez sur des plateformes mutualisées, vous avez intérêt à rassembler tous vos travaux Ansible dans un même répertoire. C’est lui qui vous offrira la puissance de gestion de votre parc technique et applicatif. Au contraire, si les projets n’ont rien en commun, séparez vos répertoires Ansible par projet applicatif, vous n’aurez à penser qu’à votre périmètre technique et applicatif ; ceci vous évitera de tirer des dépendances techniques et organisationnelles d’autres équipes qui gèrent les briques communes… *boring*
KISS = Keep It Stupid and Simple : Ne vous ajoutez pas d’obstacles inutiles !
Répertoire projet
Pour bien démarrer, construisez votre arborescence de répertoire de travail. Je me baserai dessus tout au long de l’article.
mkdir -p ansible-playbooks/{inventories,roles,{host,group}_vars}
ansible-playbooks/ ├── inventories/ ├── roles/ ├── group_vars/ ├── host_vars/ │ └── ansible.cfg
Et rendons-nous dans le répertoire de base.
cd ansible-playbooks/
A partir de maintenant, toutes les commandes proviendront de ce répertoire.
Premier projet Ansible
Pour démarrer, nous allons commencer petit mais efficace, nous allons réaliser 2 tâches simples comme l’installation d’un paquet système (Apache) et l’exécution d’une commande système (echo).
Ansible permet de déployer des tâches sur des serveurs, nous allons donc créer les objets suivants :
- Un inventaire qui comportera notre serveurs,
- Un Playbook qui comportera les tâches à appliquer.
Notre premier playbook comportera 2 tâches simples qui s’appliqueront sur des machines catégorisées “centos”. Mais avant ça, il nous faut identifier les machines cibles.
Premier inventaire
Notre premier inventaire comportera un serveur pour commencer.
Dans les bonnes pratiques, l’inventaire est composé de 2 parties, les serveurs et les groupes, permettant de facilement et rapidement identifier tous les serveurs que l’inventaire comporte.
Autre point, les serveurs sont identifiés par des alias (et non pas par leur IP ou DNS), ce qui permet de cibler le serveur en question sans dépendre de son IP qui peut changer dans le temps ; l’alias lui ne changera jamais.
Au programme, nous allons catégoriser notre serveur dans plusieurs groupes successivement : le serveur centos01.ineat-conseil.fr
appartient au groupe centos
(logique non?), qui appartient au groupe linux
(logique aussi n’est-ce pas?), qui appartient au groupe all
.
Le groupe all
est le plus grand groupe attribuable. Il faut différencier les “groupes de serveurs” et les “groupes de groupes”.
vi inventories/premier
# Les serveurs centos01 ansible_host=centos01.ineat-conseil.fr # Les groupes [centos] centos01 [linux:children] centos # Le groupe global [all:children] linux
Séparez les serveurs et les groupes dans votre inventaire, vous visualiserez rapidement les serveurs lié à votre application.
Le groupe “all” peut être omis de l’inventaire car tous les serveurs et tous les groupes appartiennent nativement au groupe “all”.
Premier Playbook
Une fois votre inventaire prêt, vous devez définir les actions à appliquer.
Un playbook est constitué d’une liste de tâches (tasks) à appliquer sur une liste de serveurs (inventories). Nous allons faire simple dans ce premier jet avec l’installation du middleware Apache sur les serveurs tagués “centos” et l’écriture d’une chaîne de caractère dans un fichier.
Nous visons donc tous les serveurs appartenant au groupe “centos”, et nous allons installer le paquet “httpd” (serveur RedHat-like oblige).
Nous en profitons pour ajouter une tâche un peu particulière (et pourtant si naturelle) au sens Ansible, une commande bash.
L’identification des serveurs se fait grâce à l’attribut “hosts”, qui peut être un serveur défini par son nom ou son alias (centos01
pour nous) ou par une liste de serveur à l’aide du nom du groupe (centos
pour nous). Le choix d’un serveur se fait en appelant directement son nom, tandis que l’appel d’un groupe nécessite des crochets “[nom_du_groupe]” ([centos]
pour nous).
Pour ce jet rapide, j’exécute toutes mes commandes avec des droits “root” (haaann c’est pas bien !!), et je vous montre par la même occasion son utilisation. De base, toutes les commandes sont exécutées avec l’utilisateur courant sur le serveur distant (user ansible
par exemple). Si vous voulez changer cet utilisateur dans votre playbook, utilisez la notion become, l’activation avec l’attribut become
, le choix de l’utilisation avec become_user
, et la commande d’élévation appelée avec become_method
.
L’identification des tâches se fait grâce à l’attribut “tasks” qui est une liste au sens Yaml. L’appel des tâches ansible se fait à l’aide des modules ansible disponibles sur le site.
L’installation du paquet httpd se fait à l’aide du module yum. Les attributs nécessaires sont name
pour le nom du paquet à cibler, et state
pour définir l’action avec au choix installed
, latest
ou absent
.
Les commande bash se fait à l’aide du module shell. Beaucoup plus basique, le module lui même attend une valeur qui sera la commande bash à lancer sur les serveurs cibles. Ecrivons “Good Job!” dans le fichier /tmp/shell_module
.
Créons notre premier playbook appelé premier.yaml.
vi premier.yaml
--- - hosts: [centos] become: true tasks: - yum: name: httpd state: installed - shell: echo 'Good job!' >> /tmp/shell_module
Lancement du playbook
On a le playbook, on a l’inventaire ! on a le playbook, on a l’inventaire ! (top top top 50 !!!)
Lançons maintenant nos actions sur les serveurs respectifs. L’exécution de playbook se fait à l’aide de la commande ansible-playbook
et prend en paramètre le playbook à lancer mon-playbook.yaml
et l’inventaire sur lequel appliquer les actions avec -i <inventaire>
.
ansible-playbook -i inventories/premier premier.yaml
Output :
PLAY [centos] ******************************************************************************************** TASK [Gathering Facts] *********************************************************************************** ok: [centos01] TASK [yum] *********************************************************************************************** changed: [centos01] TASK [shell] ********************************************************************************************* changed: [centos01] PLAY RECAP *********************************************************************************************** centos01 : ok=3 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
L’exécution du playbook affiche l’état des actions vis-à-vis de chaque serveur. Vous remarquez les état [changed]
apparaître. Et on peut constater sur le serveur centos01
que les actions ont bien été réalisées.
yum list installed httpd cat /tmp/shell_module
Bingo !!!
Ansible offre bien plus que le simple fait de lancer des actions à distance.
Idempotence du playbook
Idempotence ? Vous avez dit idempotence ?!
Que se passe-t-il si on relance le playbook sur ce même serveur ? On va tous casser ? C’est ici que l’idempotence intervient.
L’une des forces de Ansible est de n’appliquer les actions uniquement si elles n’ont pas déjà été appliquées, c’est ça l’idempotence.
Néanmoins, toutes les actions et tous les modules ne sont pas sujets à l’idempotence, c’est ici que les premières limites apparaissent. Mais ces limites peuvent être gérées différemment pour pleinement intégrer l’idempotence sur ces modules un peu particuliers.
Relançons notre playbook sur le même inventaire. Que se passe-t-il ?
PLAY [centos] ******************************************************************************************** TASK [Gathering Facts] *********************************************************************************** ok: [centos01] TASK [yum] *********************************************************************************************** ok: [centos01] TASK [shell] ********************************************************************************************* changed: [centos01] PLAY RECAP *********************************************************************************************** centos01 : ok=3 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Le module yum affiche [ok]
, l’idempotence du module a joué son rôle.
Le module shell affiche [changed]
à nouveau, c’est effectivement difficile pour ansible de déceler le caractère idempotent d’une commande bash qui peut, au final, être n’importe quelle commande Linux.
On comprend maintenant mieux pourquoi les modules ont des comportements différents.
Conclusion
Dans ce “rapide” tutoriel, nous avons vu les points suivants :
- Création de tâches
- Création d’un playbook de tâches
- Utilisation de modules
- Module yum
- Module shell
Vous savez utiliser ansible et commencez enfin à voir ses capacités =)
Un article spécial sera dédié au contournement des limites d’Ansible et au travail de l’idempotence des modules.
Vous pouvez d’ors-et-déjà lire l’article sur Ansible et Vagrant disponible sur le blog.