Ansible : Automatiser la gestion de serveurs
Table des matières
Ansible est un logiciel de déploiement/configuration à distance, créé par M. De Hann ( Redhat : Cobbler et Func) et est écrit en python. Il utilise seulement SSH et ne nécessite pas de serveur : une simple station de travail peut suffire. Il est bon de noter qu'il fonctionne en mode push (de Ansible vers le serveur cible). La machine hébergeant Ansible ne nécessite que python 2.4+, et Ansible est extensible en n'importe quel langage.
Cette solution est plutôt dédiée à un usage professionnel.
J'ai mis en œuvre Ansible sur plusieurs systèmes différents : Gentoo et CentOS.
Je décris ici l'installation des deux systèmes.
Il est nécessaire d'installer les dépôts EPEL.
Vous pouvez aussi installer le paquet centos-release-ansible pour activer le dépôt Ansible
Ensuite, installer Ansible via
CentOS 7 :
CentOS 8 :
Ansible est disponible directement, et installable via
Sur la machine qui possède Ansible, configurer le fichier /etc/hosts avec le nom des hôtes (si DNS non fonctionnel) :
On génère ensuite une paire de clés SSH :
Puis on copie notre clé sur chaque serveur :
On peut vérifier le bon fonctionnement en se connectant à chacune des machines...
Tout se passe dans le fichier /etc/ansible/hosts. On édite le fichier. Voici un exemple :
Entre crochet, on trouve les groupes d'hôtes, avec les hôtes concernés en dessous.
Ici, j'ai donc 5 groupes, un rhel7 avec les hôtes samba et lamp01 et le groupe cluster avec cluster1 et cluster2 etc...
Ansible s'articule autour de modules.
Plus d'infos sur les modules : https://docs.ansible.com/ansible/latest/collections/all_plugins.html
Pour tester la communication, on peut utiliser le module ping d'Ansible :
all ici signifie tous les hôtes :
Pour tester le bon fonctionnement, on va installer htop sur inf en utilisant le module dnf:
La console affiche l'état des opérations :
On peut aussi tester sur Gentoo en installant aussi htop sur les 2 machines du groupe cluster en utilisant le module portage:
La console affiche moins de choses, puisque les paquets sont déjà installés :
Et un test sur debian, avec le module apt, installons htop :
Par exemple, pour mettre à jour les serveurs rhel :
Un playbook est une sorte de mégascript qui va automatiser des tâches de manière séquentielle.
Globalement, un playbook est composé de tâches comme ceci :
Voici une illustration avec un playbook "test" pour installer htop sous Gentoo :
Ici, je vise les hôtes du groupe cluster, et le playbook ne comporte qu'une seule tâche.
On lance le playbook via la commande
Une autre expérience intéressante consiste à relancer l’exécution du playbook
Tout devrait aller beaucoup plus vite, et à la place de "changed" après chaque instruction, on lit "ok".
Ce qui veut dire qu’un playbook est plus intelligent qu’un bête script, et ne se contente pas d’exécuter des instructions.
Ansible va garantir quel tel service soit bien actif et qu’il utilise bien le dernier fichier de conf. Ce qui en fait l’outil parfait pour tester vos systèmes automatiquement.
On peut aussi ajouter une section handlers. Elle permet d'effectuer des actions quand il y a eu un changement. Exemple ici de redémarrage sur RHEL du service httpd :
Ci-dessous, un playbook que j'ai réalisé, pour installer LAMP sur Gentoo :
Cette fois-ci, il n'y a pas que des installations ...
Le fichier lamp-gentoo.yml.portage.use.php contient ceci :
Si on souhaite modifier un USE, on édite le fichier lamp-gentoo.yml.portage.use.php et on relance le playbook. Ce fichier sera mis à jour automatiquement sur les serveurs cible, et php recompilé. Apache par exemple n'étant pas modifié, il ne sera pas recompilé.
Voici l'illustration de l'exécution du playbook :
Ci-dessous, un playbook que j'ai réalisé, pour installer LAMP sur CentOS.
A noter l'apparition d'une nouvelle section nommée handlers comme expliquée précédemment.
Et pour pimenter les choses, l'étape 3 installe plusieurs paquets d'un coup.
Ce playbook est donc bien complet.
Voici une illustration d'exécution du playbook :
Cette fois-ci un playbook d'installation de SAMBA sur Debian.
A noter qu'il est déjà installé sur le serveur connex, comme le montrera l'exécution du playbook.
Le playbook : samba-debian.yml
Le fichier samba-debian.yml.smb.conf.ansible
On exécute ensuite le playbook :
La console affiche :
Cette fois-ci un playbook pour mettre à jour CentOS 7.
Le playbook : maj-rhel7.yml
On exécute ensuite le playbook :
La console affiche :
lamp01 a été mis à jour (changed) et l'autre l'était déjà.
Introduction
Ansible est un logiciel de déploiement/configuration à distance, créé par M. De Hann ( Redhat : Cobbler et Func) et est écrit en python. Il utilise seulement SSH et ne nécessite pas de serveur : une simple station de travail peut suffire. Il est bon de noter qu'il fonctionne en mode push (de Ansible vers le serveur cible). La machine hébergeant Ansible ne nécessite que python 2.4+, et Ansible est extensible en n'importe quel langage.
Cette solution est plutôt dédiée à un usage professionnel.
Installer Ansible
J'ai mis en œuvre Ansible sur plusieurs systèmes différents : Gentoo et CentOS.
Je décris ici l'installation des deux systèmes.
CentOS
Il est nécessaire d'installer les dépôts EPEL.
Vous pouvez aussi installer le paquet centos-release-ansible pour activer le dépôt Ansible
Ensuite, installer Ansible via
CentOS 7 :
Code BASH :
yum install ansible
CentOS 8 :
Code BASH :
dnf install ansible
Gentoo
Ansible est disponible directement, et installable via
Code BASH :
emerge -av app-admin/ansible
Préparer le terrain
Configurer le "serveur" Ansible
Sur la machine qui possède Ansible, configurer le fichier /etc/hosts avec le nom des hôtes (si DNS non fonctionnel) :
Code BASH :
infra ~ # cat /etc/hosts
127.0.0.1 localhost.localdomain localhost
192.168.21.11 cluster1.adrien.lan cluster1
192.168.21.12 cluster2.adrien.lan cluster2
192.168.21.13 inf
192.168.21.14 samba
192.168.21.15 lamp01
192.168.21.16 sftp
192.168.21.17 zabbix
192.168.21.18 ocs
192.168.21.19 glpi
192.168.21.21 cluster1
192.168.21.22 cluster2
192.168.21.23 connex
Partie SSH
On génère ensuite une paire de clés SSH :
Code BASH :
ssh-keygen -t ecdsa -b 384
Puis on copie notre clé sur chaque serveur :
Code BASH :
ssh-copy-id cluster1 ssh-copy-id cluster2 ssh-copy-id zabbix ssh-copy-id ocs
On peut vérifier le bon fonctionnement en se connectant à chacune des machines...
Configuration des hôtes Ansible
Tout se passe dans le fichier /etc/ansible/hosts. On édite le fichier. Voici un exemple :
Code BASH :
[test] inf [rhel7] samba lamp01 [rhel8] sftp zabbix ocs glpi [cluster] cluster1 cluster2 [deb] connex
Entre crochet, on trouve les groupes d'hôtes, avec les hôtes concernés en dessous.
Ici, j'ai donc 5 groupes, un rhel7 avec les hôtes samba et lamp01 et le groupe cluster avec cluster1 et cluster2 etc...
Utiliser Ansible
Ansible s'articule autour de modules.
Plus d'infos sur les modules : https://docs.ansible.com/ansible/latest/collections/all_plugins.html
Tester la communication
Pour tester la communication, on peut utiliser le module ping d'Ansible :
Code BASH :
ansible -m ping all
all ici signifie tous les hôtes :
Code BASH :
inf | success >> { "changed": false, "ping": "pong" } cluster1 | success >> { "changed": false, "ping": "pong" } cluster2 | success >> { "changed": false, "ping": "pong" } samba | success >> { "changed": false, "ping": "pong" } lamp01 | success >> { "changed": false, "ping": "pong" } sftp | success >> { "changed": false, "ping": "pong" } zabbix | success >> { "changed": false, "ping": "pong" } ocs | success >> { "changed": false, "ping": "pong" } glpi | success >> { "changed": false, "ping": "pong" } connex | success >> { "changed": false, "ping": "pong" }
En mode "on-liner"
Pour tester le bon fonctionnement, on va installer htop sur inf en utilisant le module dnf:
Code BASH :
ansible -m dnf -a 'name=htop state=present' inf
La console affiche l'état des opérations :
Code BASH :
inf | CHANGED => { "ansible_facts": { "discovered_interpreter_python": "/usr/bin/python" }, "changed": true, "msg": "", "rc": 0, "results": [ "Installed: htop-3.0.5-4.fc34.x86_64" ] }
On peut aussi tester sur Gentoo en installant aussi htop sur les 2 machines du groupe cluster en utilisant le module portage:
Code BASH :
ansible -m portage -a 'name=htop state=present' cluster
La console affiche moins de choses, puisque les paquets sont déjà installés :
Code BASH :
cluster1 | success >> { "changed": false, "msg": "Packages already present." } cluster2 | success >> { "changed": false, "msg": "Packages already present." }
Et un test sur debian, avec le module apt, installons htop :
Code BASH :
ansible -m apt -a 'name=htop' connex
Code BASH :
connex | CHANGED => { "ansible_facts": { "discovered_interpreter_python": "/usr/bin/python" }, "cache_update_time": 1618833826, "cache_updated": false, "changed": true, "stderr": "", "stderr_lines": [], "stdout": "Reading package lists...\nBuilding dependency tree...\nReading state information...\nThe following packages were automatically installed and are no longer required:\n linux-image-4.19.0-5-amd64 linux-image-4.19.0-9-amd64\nUse 'apt autoremove' to remove them.\nSuggested packages:\n strace\nThe following NEW packages will be installed:\n htop\n0 upgraded, 1 newly installed, 0 to remove and 26 not upgraded.\nNeed to get 92.8 kB of archives.\nAfter this operation, 230 kB of additional disk space will be used.\nGet:1 http://ftp.fr.debian.org/debian buster/main amd64 htop amd64 2.2.0-1+b1 [92.8 kB]\nFetched 92.8 kB in 0s (838 kB/s)\nSelecting previously unselected package htop.\r\n(Reading database ... \r(Reading database ... 5%\r(Reading database ... 10%\r(Reading database ... 15%\r(Reading database ... 20%\r(Reading database ... 25%\r(Reading database ... 30%\r(Reading database ... 35%\r(Reading database ... 40%\r(Reading database ... 45%\r(Reading database ... 50%\r(Reading database ... 55%\r(Reading database ... 60%\r(Reading database ... 65%\r(Reading database ... 70%\r(Reading database ... 75%\r(Reading database ... 80%\r(Reading database ... 85%\r(Reading database ... 90%\r(Reading database ... 95%\r(Reading database ... 100%\r(Reading database ... 46372 files and directories currently installed.)\r\nPreparing to unpack .../htop_2.2.0-1+b1_amd64.deb ...\r\nUnpacking htop (2.2.0-1+b1) ...\r\nSetting up htop (2.2.0-1+b1) ...\r\nProcessing triggers for mime-support (3.62) ...\r\nProcessing triggers for man-db (2.8.5-2) ...\r\n", "stdout_lines": [ "Reading package lists...", "Building dependency tree...", "Reading state information...", "The following packages were automatically installed and are no longer required:", " linux-image-4.19.0-5-amd64 linux-image-4.19.0-9-amd64", "Use 'apt autoremove' to remove them.", "Suggested packages:", " strace", "The following NEW packages will be installed:", " htop", "0 upgraded, 1 newly installed, 0 to remove and 26 not upgraded.", "Need to get 92.8 kB of archives.", "After this operation, 230 kB of additional disk space will be used.", "Get:1 http://ftp.fr.debian.org/debian buster/main amd64 htop amd64 2.2.0-1+b1 [92.8 kB]", "Fetched 92.8 kB in 0s (838 kB/s)", "Selecting previously unselected package htop.", "(Reading database ... ", "(Reading database ... 5%", "(Reading database ... 10%", "(Reading database ... 15%", "(Reading database ... 20%", "(Reading database ... 25%", "(Reading database ... 30%", "(Reading database ... 35%", "(Reading database ... 40%", "(Reading database ... 45%", "(Reading database ... 50%", "(Reading database ... 55%", "(Reading database ... 60%", "(Reading database ... 65%", "(Reading database ... 70%", "(Reading database ... 75%", "(Reading database ... 80%", "(Reading database ... 85%", "(Reading database ... 90%", "(Reading database ... 95%", "(Reading database ... 100%", "(Reading database ... 46372 files and directories currently installed.)", "Preparing to unpack .../htop_2.2.0-1+b1_amd64.deb ...", "Unpacking htop (2.2.0-1+b1) ...", "Setting up htop (2.2.0-1+b1) ...", "Processing triggers for mime-support (3.62) ...", "Processing triggers for man-db (2.8.5-2) ..." ] }
Par exemple, pour mettre à jour les serveurs rhel :
Code BASH :
ansible -m yum -a 'name=* state=latest' rhel7
Utiliser les playbooks
Un playbook est une sorte de mégascript qui va automatiser des tâches de manière séquentielle.
Globalement, un playbook est composé de tâches comme ceci :
Code BASH :
- name: Texte qui décris votre tâche
module: option=value
Un exemple simple
Voici une illustration avec un playbook "test" pour installer htop sous Gentoo :
Code BASH :
vi htop.yml
Code BASH :
--- - hosts: cluster tasks: - name: 1. install htop portage: name=htop state=present
Ici, je vise les hôtes du groupe cluster, et le playbook ne comporte qu'une seule tâche.
On lance le playbook via la commande
Code BASH :
ansible-playbook htop.yml
Code BASH :
PLAY [cluster] **************************************************************** GATHERING FACTS *************************************************************** ok: [cluster2] ok: [cluster1] TASK: [1. install htop] ******************************************************* changed: [cluster1] changed: [cluster2] PLAY RECAP ******************************************************************** cluster1 : ok=2 changed=1 unreachable=0 failed=0 cluster2 : ok=2 changed=1 unreachable=0 failed=0
Une autre expérience intéressante consiste à relancer l’exécution du playbook
Code BASH :
PLAY [cluster] **************************************************************** GATHERING FACTS *************************************************************** ok: [cluster2] ok: [cluster1] TASK: [1. install htop] ******************************************************* ok: [cluster1] ok: [cluster2] PLAY RECAP ******************************************************************** cluster1 : ok=2 changed=0 unreachable=0 failed=0 cluster2 : ok=2 changed=0 unreachable=0 failed=0
Tout devrait aller beaucoup plus vite, et à la place de "changed" après chaque instruction, on lit "ok".
Ce qui veut dire qu’un playbook est plus intelligent qu’un bête script, et ne se contente pas d’exécuter des instructions.
Ansible va garantir quel tel service soit bien actif et qu’il utilise bien le dernier fichier de conf. Ce qui en fait l’outil parfait pour tester vos systèmes automatiquement.
On peut aussi ajouter une section handlers. Elle permet d'effectuer des actions quand il y a eu un changement. Exemple ici de redémarrage sur RHEL du service httpd :
Code BASH :
--- - hosts: rhel8 tasks: - name: 1. MàJ dnf: name=* state=latest handlers: - name: Restart apache service: name=httpd state=restarted
Exemples de Playbook
Installer LAMP sur Gentoo
Ci-dessous, un playbook que j'ai réalisé, pour installer LAMP sur Gentoo :
Cette fois-ci, il n'y a pas que des installations ...
Code BASH :
vi lamp-gentoo.yml
Code BASH :
--- - hosts: cluster tasks: - name: 1. Installation Apache portage: name=www-servers/apache state=present - name: 2. Installation fichier des USE copy: src=lamp-calculate.yml.portage.use.php dest=/etc/portage/package.use/php - name: 3. Installation PHP portage: name=dev-lang/php state=present - name: 4. Installation de MySQL portage: name=dev-db/mysql - name: 5. Démarrage Apache service: name=apache2 state=running enabled=yes - name: 6. Initialisation MySQL command: /usr/share/mysql/scripts/mysql_install_db chdir=/usr - name: 7. Démarrage MySQL service: name=mysql state=running enabled=yes
- Installation d'un paquet.
- Copie d'un fichier vers le serveur cible.
- Installation d'un paquet.
- Installation d'un paquet.
- Vérification d'un service sur la position "démarré"
- Exécution d'une commande sur la machine cible, en l'exécutant depuis le répertoire /usr
- Démarrage d'un service.
Le fichier lamp-gentoo.yml.portage.use.php contient ceci :
Code BASH :
dev-lang/php gd apache2 mysqli pdo zip soap app-admin/eselect-php apache2
Si on souhaite modifier un USE, on édite le fichier lamp-gentoo.yml.portage.use.php et on relance le playbook. Ce fichier sera mis à jour automatiquement sur les serveurs cible, et php recompilé. Apache par exemple n'étant pas modifié, il ne sera pas recompilé.
Voici l'illustration de l'exécution du playbook :
Code BASH :
ansible-playbook lamp-gentoo.yml
Code BASH :
PLAY [cluster] **************************************************************** GATHERING FACTS *************************************************************** ok: [cluster2] ok: [cluster1] TASK: [1. Installation Apache] ************************************************ changed: [cluster2] changed: [cluster1] TASK: [2. Installation fichier des USE] *************************************** changed: [cluster1] changed: [cluster2] TASK: [3. Installation PHP] *************************************************** changed: [cluster2] changed: [cluster1] TASK: [4. Installation de MySQL] ********************************************** changed: [cluster2] changed: [cluster1] TASK: [5. Démarrage Apache] *************************************************** changed: [cluster2] changed: [cluster1] TASK: [6. Initialisation MySQL] *********************************************** changed: [cluster2] changed: [cluster1] TASK: [7. Démarrage MySQL] **************************************************** changed: [cluster2] changed: [cluster1] PLAY RECAP ******************************************************************** cluster1 : ok=8 changed=7 unreachable=0 failed=0 cluster2 : ok=8 changed=7 unreachable=0 failed=0
Installer LAMP, sous CentOS
Ci-dessous, un playbook que j'ai réalisé, pour installer LAMP sur CentOS.
A noter l'apparition d'une nouvelle section nommée handlers comme expliquée précédemment.
Et pour pimenter les choses, l'étape 3 installe plusieurs paquets d'un coup.
Code BASH :
vi lamp-centos.yml
Code BASH :
--- - hosts: lamp01 handlers: - name: restart httpd service: name=httpd state=restarted tasks: - name: 1. Installation Apache yum: name=httpd state=present - name: 2. Installation PHP yum: name=php state=present - name: 3. Installation extensions PHP yum: name={{item}} state=present with_items: - php-pdo - php-mysql - php-soap - php-gd - php-pear-MDB2-Driver-mysqli - name: 4. Installation de MariaDB yum: name=mariadb-server - name: 5. Démarrage Apache service: name=httpd state=running enabled=yes - name: 6. Démarrage MariaDB service: name=mariadb state=running enabled=yes - name: 7. Installation index copy: src=lamp-centos.yml.index.php dest=/var/www/html/index.php notify: - restart httpd - name: 8. Ajout de la règle de pare-feu action: command /usr/bin/firewall-cmd --permanent --add-port=80/tcp - name: 9. Redémarrer le pare-feu service: name=firewalld state=restarted
- Installation d'un paquet.
- Installation d'un paquet.
- Illustration de l'installation de plusieurs paquets dans une même tâche.
- Installation d'un paquet.
- Vérification d'un service sur la position "démarré"
- Vérification d'un service sur la position "démarré"
- Copier Coller d'un fichier du "serveur Ansible" vers le serveur cible. Avec une fois l'opération effectuée un redémarrage du service.
- Exécution d'une commande sur la machine cible
- Redémarrage d'un service.
Ce playbook est donc bien complet.
Voici une illustration d'exécution du playbook :
Code BASH :
vi ansible-playbook lamp-centos.yml
Code BASH :
PLAY [lamp01] ******************************************************************* GATHERING FACTS *************************************************************** ok: [lamp01] TASK: [1. Installation Apache] ************************************************ changed: [lamp01] TASK: [2. Installation PHP] *************************************************** changed: [lamp01] TASK: [3. Installation extensions PHP] **************************************** changed: [lamp01] => (item=php-pdo,php-mysql,php-soap,php-gd,php-pear-MDB2-Driver-mysqli) TASK: [4. Installation de MariaDB] ******************************************** changed: [lamp01] TASK: [5. Démarrage Apache] *************************************************** changed: [lamp01] TASK: [6. Démarrage MariaDB] ************************************************** changed: [lamp01] TASK: [7. Installation index] ************************************************* changed: [lamp01] TASK: [8. Ajout de la règle de pare-feu] ************************************** changed: [lamp01] TASK: [9. Redémarrer le pare-feu] ********************************************* changed: [lamp01] NOTIFIED: [restart httpd] ***************************************************** changed: [lamp01] PLAY RECAP ******************************************************************** lamp01 : ok=11 changed=10 unreachable=0 failed=0
Installer et Configurer SAMBA, sous Debian
Cette fois-ci un playbook d'installation de SAMBA sur Debian.
A noter qu'il est déjà installé sur le serveur connex, comme le montrera l'exécution du playbook.
Le playbook : samba-debian.yml
Code BASH :
vi samba-debian.yml
Code BASH :
--- - hosts: connex handlers: - name: restart samba service: name=samba state=restarted tasks: - name: 1. Installer samba apt: name=samba state=present - name: 2. Démarrer service samba service: name=samba state=running enabled=yes - name: 3. Création du dossier public command: mkdir -p /srv/samba/commun - name: 4. Correction des droits file: path=/srv/samba/commun owner=root group=users mode=0777 - name: 5. Modification du fichier smb.conf lineinfile: dest=/etc/samba/smb.conf backup=yes line="include /etc/samba/smb.conf.ansible" - name: 6 Copier le fichier personnalisé de samba copy: src=samba-debian.yml.smb.conf.ansible dest=/etc/samba/smb.conf.ansible notify: - restart samba
Le fichier samba-debian.yml.smb.conf.ansible
Code BASH :
[commun] comment = Partage de fichiers commun browseable = yes public = yes path = /srv/samba/commun writable = yes
On exécute ensuite le playbook :
Code BASH :
ansible-playbook samba-debian.yml
La console affiche :
Code BASH :
PLAY [connex] *********************************************************** GATHERING FACTS *************************************************************** ok: [connex] TASK: [1. Installer samba] **************************************************** ok: [connex] TASK: [2. Démarrer service samba] ********************************************* ok: [connex] TASK: [3. Création du dossier public] ***************************************** changed: [connex] TASK: [4. Correction des droits] ********************************************** ok: [connex] TASK: [5. Modification du fichier smb.conf] *********************************** changed: [connex] TASK: [6 Copier le fichier personnalisé de samba] ***************************** changed: [connex] NOTIFIED: [restart samba] ***************************************************** changed: [connex] PLAY RECAP ******************************************************************** connex : ok=8 changed=4 unreachable=0 failed=0
- Installation d'un paquet.
- Démarrage d'un service.
- Exécution d'une commande.
- Modification de droits.
- Ajout d'une ligne dans un fichier.
- Copie de fichier + notification
Mettre à jour CentOS
Cette fois-ci un playbook pour mettre à jour CentOS 7.
Le playbook : maj-rhel7.yml
Code BASH :
vi maj-rhel7.yml
Code BASH :
--- - hosts: rhel7 tasks: - name: Mise a jour yum: name=* state=latest
On exécute ensuite le playbook :
Code BASH :
ansible-playbook maj-rhel7.yml
La console affiche :
Code BASH :
PLAY [rhel7] ********************* TASK [Gathering Facts] ********************* ok: [samba] ok: [lamp01] TASK [Mise a jour] ********************* ok: [samba] changed: [lamp01] PLAY RECAP ********************* samba : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 lamp01 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
lamp01 a été mis à jour (changed) et l'autre l'était déjà.