Ansible® est un outil Open Source d'automatisation informatique qui automatise le provisionnement, la gestion des configurations, le déploiement des applications, l'orchestration et bien d'autres processus informatiques manuels.
Ici, on a seulement notre hôte physique (localhost) faisant fonctionner une machine virtuelle (ipv4: 192.168.122.243). Bien entendu, notre hôte physique Fedora a le paquet RPM ansible installé.
dnf install ansible
Notre machine virtuelle est une CentOS fraichement installée (minimal), sans utilisateur (pour l'instant).
On va, dans un premier temps essayé de contacter notre machine virtuelle avec un simple ping.
ansible 192.168.122.243 -m ping
[WARNING]: Could not match supplied host pattern, ignoring: all
[WARNING]: provided hosts list is empty, only localhost is available
[WARNING]: Could not match supplied host pattern, ignoring: 192.168.122.243
[WARNING]: No hosts matched, nothing to do
Cela ne fonctionne pas.
En effet, Ansible ne connait pas notre cible et refuse de communiquer avec elle. De plus notre utilisateur n'existe pas sur la cible
Il nous faudrait déclarer l'hôte distant dans le fichier /etc/ansible/hosts pour que ça fonctionne. Mais comme on n'est pas le super-utilisateur, on va faire autrement, et en suivant le guide ansible des bonnes pratiques petit à petit.
On va créer deux répertoires, le nom peut-être ce que vous voulez, il faudra juste adapter les commandes pour utiliser ces répertoires:
et dans chaque répertoire on va créer un fichier nommé hosts, où l'on définira des groupes dans lesquels on déclarera nos hôtes. Ce fichier est au format INI, mais il peut aussi être au format YAML.
Dans l'exemple suivant, on déclare notre machine virtuelle dans le groupe server et notre hôte local dans le groupe ansible.
Fichier staging/hosts
[server]
192.168.122.243
[ansible]
localhost
Et au lancement de la commande, on va spécifier le répertoire de notre environnement avec l'option -i, et pour utiliser le super-utilisateur sur notre cible, on le spéficie (avec demande de mot de passe)
ansible -i staging 192.168.122.243 --user root --ask-pass -m ping
192.168.122.243 | SUCCESS => {
"changed": false,
"failed": false,
"ping": "pong"
}
Cette fois ça fonctionne. Essayons maintenant une commande
ansible -i staging 192.168.122.243 --user root --ask-pass -a whoami
192.168.122.243 | SUCCESS | rc=0 >>
root
Par défaut Ansible utilise le même utilisateur sur l'hôte distant. On s'assure donc que celui existe sur notre machine virtuelle ou que l'on spécifie l'utilisateur à utiliser dans la ligne de commande.
Le fichier permettant de lister les commande à lancer s'appelle un playbook. Il peut être monolithique ou divisé en plusieurs parties. Ansible recommande la séparation par rôle, ce qui permet de réutiliser les commandes d'un playbook et de les partager facilement avec la communauté.
Il est important de bien réfléchir à la séparation des différents rôles que devra comporter notre serveur, afin d'avoir la meilleur modularité possible.
On va prendre l'exemple d'un serveur personnel (vps), qui comporterait un blog (wordpress), un outil d'analyse du trafic web (piwik alias matomo) et tout le monitoring nécessaire à tous cela. On arrive à ce stade à 3 rôles. Mais sachant que le blog et piwik ont tous les deux besoin d'un serveur web et d'une base de données, que le système à besoin d'être mis à jour, que certaines actions seront nécessaires à plusieurs rôles (ex: redémarrer le service httpd après un changement), on arrive à
Rôles de notre serveur:
On remarque que le changement d'un élément ne perturbe pas (ou peu) les autres rôles. Ainsi le changement de produit n'est pas une tâche trop difficile. Le changement de piwik par awstats sera transparent pour les autres rôles, mais le changement du serveur web ou de la base de données impactera les rôles du blog et de l'outil d'analyse web.
Un playbook est un fichier texte au format YAML.
Il s'agit dune succession de tâches à accomplir. L'erreur sur l'une d'entre elle entraine l'arrêt du processus (par défaut). Il existe un très grand nombre de modules et la documentation officielle des modules Ansible les explique tous.
L'exemple suivant se sert de deux modules:
et effectue les tâches suivantes:
pour chaque hôte membre du groupe server (fichier hosts du répertoire production ou staging).
Fichier site.yml
- hosts: server
tasks:
- name: Ensure epel repository is set
yum:
name: epel-release
state: latest
become: true
# System update
- name: Ensure all pkgs are up-to-date
yum:
name: '*'
state: latest
become: true
tags: update
# Install packages
- name: Ensure system RPMs are installed and up-to-date
yum:
pkg: "{{ item }}"
state: latest
become: true
with_items:
- git
- postfix
- chrony
- mlocate
- screen
- vim-enhanced
- yum-utils
- bzip2
- unzip
- bind-utils
- man-pages
- net-tools
- etckeeper
# Manage etckeeper
- name: Ensure etc is versionned
shell: "etckeeper init"
args:
executable: /bin/bash
creates: /etc/.git
chdir: /etc
become: true
- name: Ensure first commit is done for etc
shell: "etckeeper commit 'First commit'"
args:
executable: /bin/bash
creates: /etc/.git/refs/heads/master
chdir: /etc
become: true
Quelques remarques sur les tâches:
Le playbook se lance ainsi:
ansible-playbook -i staging --ask-become-pass site.yml
SUDO password:
PLAY [server] ******************************************************************
TASK [Gathering Facts] *********************************************************
ok: [192.168.122.243]
TASK [Ensure epel repository is set] *******************************************
changed: [192.168.122.243]
TASK [Ensure all pkgs are up-to-date] ******************************************
changed: [192.168.122.243]
TASK [Ensure system RPMs are installed and up-to-date] *************************
changed: [192.168.122.243] => (item=[u'git', u'postfix', u'chrony', u'mlocate', u'screen', u'vim-enhanced', u'yum-utils', u'bzip2', u'unzip', u'bind-utils', u'man-pages', u'net-tools', u'etckeeper'])
TASK [Ensure etc is versionned] ************************************************
changed: [192.168.122.243]
TASK [Ensure first commit is done for etc] *************************************
changed: [192.168.122.243]
PLAY RECAP *********************************************************************
192.168.122.243 : ok=6 changed=5 unreachable=0 failed=0
Si on relance le même playbook, les tâches déjà effectuées ne seront pas relancées.
Et c'est une règle d'or des playbooks, ils peuvent être relancé n'importe quand et le résultat sera toujours prévisible (idempotent), c'est à dire qu'il n'y aura pas d'effet de bord, en cas de doublon par exemple.
En effet, dans notre exemple, on ne peut pas initialiser le dépôt git d'etckeeper plusieurs fois et c'est au playbook de gérer cette situation (en posant un fichier et en testant sa présence).
ansible-playbook -i staging --ask-become-pass site.yml
SUDO password:
PLAY [server] ******************************************************************
TASK [Gathering Facts] *********************************************************
ok: [192.168.122.243]
TASK [Ensure epel repository is set] *******************************************
ok: [192.168.122.243]
TASK [Ensure all pkgs are up-to-date] ******************************************
ok: [192.168.122.243]
TASK [Ensure system RPMs are installed and up-to-date] *************************
ok: [192.168.122.243] => (item=[u'git', u'postfix', u'chrony', u'mlocate', u'screen', u'vim-enhanced', u'yum-utils', u'bzip2', u'unzip', u'bind-utils', u'man-pages', u'net-tools', u'etckeeper'])
TASK [Ensure etc is versionned] ************************************************
ok: [192.168.122.243]
TASK [Ensure first commit is done for etc] *************************************
ok: [192.168.122.243]
PLAY RECAP *********************************************************************
192.168.122.243 : ok=6 changed=0 unreachable=0 failed=0
Si l'utilisateur courant n'a pas besoin de mot de passe pour les commandes sudo, on ne sera pas obligé de spécifier l'option --ask-become-pass.
Si Ansible s'avère bien pratique pour gérer les hôtes distants, il apparait que certaines pratiques sont dangereuses au niveau de la sécurité. En effet comment affecter un mot de passe à l'utilisateur MySQL root et en même temps commiter les fichiers Ansibles sur un dépôt public distant, sans compromettre la sécurité. Ansible a résolu le problème avec vault (coffre).
Ansible-vault encode les données avec l’algorithme AES256
Il y a deux manière de l'utiliser:
Prenons comme exemple un fichier de variable host_vars/server qui contiendrait l'entrée suivante:
mysql_root_password: "monsupermotdepasse"
On créé notre fichier chiffré et on inscrit notre variable une fois le fichier ouvert par l'éditeur par défaut (variable EDITOR) avec la commande
ansible-vault create host_vars/server
New Vault password:
Confirm New Vault password:
On pourra éditer notre fichier chiffré, avec l'éditeur par défaut
ansible-vault edit host_vars/server
Alternativement, on peut créer un fichier en clair et le chiffrer par la suite
echo 'mysql_root_password: "monsupermotdepasse"' > host_vars/server
ansible-vault encrypt host_vars/server
Ce qui donnera le fichier suivant
Fichier host_vars/server
$ANSIBLE_VAULT;1.1;AES256
61346330393736306566356131633264323234353664653034646239326439633261643630393162
6633646264326134373230343935636361353033313262630a356566336261623261343233666135
33333635353331663434366137653934633238633561346463626130633063663636373330663031
3738363239663635380a326532386133343732306535393466393433306434323265366336323037
39356531316631366161376161633166336562366330313038343961626261333237356237333062
3830373337656561653364313064353866306132653864623834
On chiffre la valeur avec la commande idoine
ansible-vault encrypt_string --vault-id @prompt 'monsupermotdepasse' --name 'mysql_root_password' >> host_vars/server
New vault password (default):
Confirm vew vault password (default):
Encryption successful
Ce qui donnera le fichier suivant
Fichier host_vars/server
mysql_root_password: !vault |
$ANSIBLE_VAULT;1.1;AES256
65343663373236316433393833616164353236303666663437613438306630336135353238326137
3566333939353435613539613066373463323231656635320a666633366637343738653634396137
33316530396338316638303765636165363132363934376234316430633432613632663439326661
3530613339653038640a396436373763363332313336623061313834353238613766393662396533
30653531653265623165333037396539396632393535636166646538646638373261
Les bases sont posées et un exemple concret sera bientôt disponible dans la deuxième partie: Premier playbook avec les rôles.