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 deux systèmes différents : Calculate Linux et CentOS7.
Je décris ici l'installation des deux systèmes.
Il est nécessaire d'installer les dépôts EPEL.
Ensuite, installer Ansible via
Ansible est disponible directement, et installable via
Si on souhaite la toute dernière version en date, on peut ajouter la ligne qui va bien dans le ficher keywords avant d'installer Ansible :
S'assurer que les serveurs SSH comprennent la ligne suivante et peuvent se connecter avec l'utilisateur root, et avec une clé :
Sous Calculate Linux 64bits par exemple :
Sur la machine qui possède Ansible, configurer le fichier /etc/hosts avec le nom des hôtes :
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 3 groupes, un rhel avec les hôtes rhelsrv1 et rhelsrv2 et le groupe cluster avec cluster1 et cluster2 etc...
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 rhelsrv2 en utilisant le module yum:
La console affiche l'état des opérations :
On peut aussi tester sur Calculate Linux 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 :
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 :
Plus d'infos sur les modules : http://docs.ansible.com/list_of_all_modules.html
Voici une illustration avec un playbook "test" pour installer htop sous Calculate Linux :
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.
Ci-dessous, un playbook que j'ai réalisé, pour installer LAMP sur Calculate Linux :
Cette fois-ci, il n'y a pas que des installations ...
Le fichier lamp-calculate.yml.portage.use.php contient ceci :
Si on souhaite modifier un USE, on édite le fichier lamp-calculate.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. Cette section permet notamment de déclarer les éventuelles notifications.
Ici, cela correspond à l'étape 7, étape notify, restart httpd
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 deux Debian.
A noter qu'il est déjà installé et configuré sur un des deux serveurs; 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 :
On voit bien dans le dernier point que le NOTIFIED ne s'applique qu'aux hôtes dont un changement a eu lieu...
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 deux systèmes différents : Calculate Linux et CentOS7.
Je décris ici l'installation des deux systèmes.
CentOS
Il est nécessaire d'installer les dépôts EPEL.
Ensuite, installer Ansible via
Code BASH :
yum install ansible
Calculate Linux
Ansible est disponible directement, et installable via
Code BASH :
emerge -qv ansible
Si on souhaite la toute dernière version en date, on peut ajouter la ligne qui va bien dans le ficher keywords avant d'installer Ansible :
Code BASH :
echo "app-admin/ansible" >> /etc/portage/package.keywords/ansible
S'assurer que les serveurs SSH comprennent la ligne suivante et peuvent se connecter avec l'utilisateur root, et avec une clé :
Code BASH :
Subsystem sftp /cheminvers/sftp-server
Sous Calculate Linux 64bits par exemple :
Code BASH :
Subsystem sftp /usr/lib64/misc/sftp-server
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 :
Code BASH :
infra ~ # cat /etc/hosts
127.0.0.1 localhost.localdomain localhost
10.21.27.11 cluster1.adrien.lan cluster1
10.21.27.12 cluster2.adrien.lan cluster2
10.21.27.125 rhelsrv1
10.21.27.127 rhelsrv2
10.21.27.130 debsrv1
10.21.27.121 debsrv2
Partie SSH
On génère ensuite une paire de clés SSH :
Code BASH :
infra ~ # ssh-keygen Generating public/private rsa key pair. Enter file in which to save the key (/root/.ssh/id_rsa): Created directory '/root/.ssh'. Enter passphrase (empty for no passphrase): Enter same passphrase again: Your identification has been saved in /root/.ssh/id_rsa. Your public key has been saved in /root/.ssh/id_rsa.pub. The key fingerprint is: d8:de:8e:f9:a4:44:07:a7:ec:dc:ed:81:10:ef:1e:b8 root@rhelsrv1 The key's randomart image is: +--[ RSA 2048]----+ | | | | | o . | | + * | | . S o | | = B o | | * B o | | . O o . | | E.+ . | +-----------------+
Puis on copie notre clé sur chaque serveur :
Code BASH :
infra ~ # ssh-copy-id rhelsrv1 infra ~ # ssh-copy-id rhelsrv2 infra ~ # ssh-copy-id cluster1 infra ~ # ssh-copy-id cluster2 infra ~ # ssh-copy-id debsrv1 infra ~ # ssh-copy-id debsrv2
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 :
[rhel] rhelsrv1 rhelsrv2 [cluster] cluster1 cluster2 [sambaservers] debsrv1 debsrv2
Entre crochet, on trouve les groupes d'hôtes, avec les hôtes concernés en dessous.
Ici, j'ai donc 3 groupes, un rhel avec les hôtes rhelsrv1 et rhelsrv2 et le groupe cluster avec cluster1 et cluster2 etc...
Utiliser Ansible
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 :
cluster1 | success >> { "changed": false, "ping": "pong" } cluster2 | success >> { "changed": false, "ping": "pong" } rhelsrv2 | success >> { "changed": false, "ping": "pong" } rhelsrv1 | success >> { "changed": false, "ping": "pong" } debsrv2 | success >> { "changed": false, "ping": "pong" } debsrv1 | success >> { "changed": false, "ping": "pong" }
En mode "on-liner"
Pour tester le bon fonctionnement, on va installer htop sur rhelsrv2 en utilisant le module yum:
Code BASH :
ansible -m yum -a 'name=htop' rhelsrv2
La console affiche l'état des opérations :
Code BASH :
rhelsrv2 | success >> { "changed": true, "msg": "warning: /var/cache/yum/x86_64/7/epel/packages/htop-1.0.3-3.el7.x86_64.rpm: Header V3 RSA/SHA256 Signature, key ID 352c64e5: NOKEY\nImporting GPG key 0x352C64E5:\n Userid : \"Fedora EPEL (7) <[email protected]>\"\n Fingerprint: 91e9 7d7c 4a5e 96f1 7f3e 888f 6a2f aea2 352c 64e5\n Package : epel-release-7-2.noarch (@extras)\n From : /etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-7\n", "rc": 0, "results": [ "Loaded plugins: fastestmirror, langpacks\nLoading mirror speeds from cached hostfile\n * base: mirror.ate.info\n * epel: epel.mirrors.ovh.net\n * extras: mirror.ate.info\n * updates: mirror.skylink-datacenter.de\nResolving Dependencies\n--> Running transaction check\n---> Package htop.x86_64 0:1.0.3-3.el7 will be installed\n--> Finished Dependency Resolution\n\nDependencies Resolved\n\n================================================================================\n Package Arch Version Repository Size\n================================================================================\nInstalling:\n htop x86_64 1.0.3-3.el7 epel 87 k\n\nTransaction Summary\n================================================================================\nInstall 1 Package\n\nTotal download size: 87 k\nInstalled size: 181 k\nDownloading packages:\nPublic key for htop-1.0.3-3.el7.x86_64.rpm is not installed\nRetrieving key from file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-7\nRunning transaction check\nRunning transaction test\nTransaction test succeeded\nRunning transaction\n Installing : htop-1.0.3-3.el7.x86_64 1/1 \n Verifying : htop-1.0.3-3.el7.x86_64 1/1 \n\nInstalled:\n htop.x86_64 0:1.0.3-3.el7 \n\nComplete!\n" ] }
On peut aussi tester sur Calculate Linux en installant aussi htop sur les 2 machines du groupe cluster en utilisant le module portage:
Code BASH :
ansible -m portage -a 'name=htop' 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 :
Code BASH :
ansible -m apt -a 'name=htop' debsrv1
Code BASH :
debsrv1 | success >> { "changed": true, "stderr": "", "stdout": "Reading package lists...\nBuilding dependency tree...\nReading state information...\nSuggested packages:\n strace ltrace\nThe following NEW packages will be installed:\n htop\n0 upgraded, 1 newly installed, 0 to remove and 0 not upgraded.\nNeed to get 74.9 kB of archives.\nAfter this operation, 216 kB of additional disk space will be used.\nGet:1 http://ftp.fr.debian.org/debian/ wheezy/main htop amd64 1.0.1-1 [74.9 kB]\nFetched 74.9 kB in 0s (286 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 ... 40200 files and directories currently installed.)\r\nUnpacking htop (from .../htop_1.0.1-1_amd64.deb) ...\r\nProcessing triggers for menu ...\r\nProcessing triggers for man-db ...\r\nSetting up htop (1.0.1-1) ...\r\nProcessing triggers for menu ...\r\n" }
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
Plus d'infos sur les modules : http://docs.ansible.com/list_of_all_modules.html
Un exemple simple
Voici une illustration avec un playbook "test" pour installer htop sous Calculate Linux :
Code BASH :
# htop.yml --- - 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.
Installer LAMP sur Calculate Linux
Ci-dessous, un playbook que j'ai réalisé, pour installer LAMP sur Calculate Linux :
Cette fois-ci, il n'y a pas que des installations ...
Code BASH :
# lamp-calculate.yml --- - 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-calculate.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-calculate.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 :
infra ansible # ansible-playbook lamp-calculate.yml 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. Cette section permet notamment de déclarer les éventuelles notifications.
Ici, cela correspond à l'étape 7, étape notify, restart httpd
Et pour pimenter les choses, l'étape 3 installe plusieurs paquets d'un coup.
Code BASH :
# lamp-centos.yml --- - hosts: rhel 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 :
infra ansible# ansible-playbook lamp-centos.yml PLAY [rhel] ******************************************************************* GATHERING FACTS *************************************************************** ok: [rhelsrv1] ok: [rhelsrv2] TASK: [1. Installation Apache] ************************************************ changed: [rhelsrv1] changed: [rhelsrv2] TASK: [2. Installation PHP] *************************************************** changed: [rhelsrv1] changed: [rhelsrv2] TASK: [3. Installation extensions PHP] **************************************** changed: [rhelsrv2] => (item=php-pdo,php-mysql,php-soap,php-gd,php-pear-MDB2-Driver-mysqli) changed: [rhelsrv1] => (item=php-pdo,php-mysql,php-soap,php-gd,php-pear-MDB2-Driver-mysqli) TASK: [4. Installation de MariaDB] ******************************************** changed: [rhelsrv1] changed: [rhelsrv2] TASK: [5. Démarrage Apache] *************************************************** changed: [rhelsrv2] changed: [rhelsrv1] TASK: [6. Démarrage MariaDB] ************************************************** changed: [rhelsrv1] changed: [rhelsrv2] TASK: [7. Installation index] ************************************************* changed: [rhelsrv1] changed: [rhelsrv2] TASK: [8. Ajout de la règle de pare-feu] ************************************** changed: [rhelsrv2] changed: [rhelsrv1] TASK: [9. Redémarrer le pare-feu] ********************************************* changed: [rhelsrv2] changed: [rhelsrv1] NOTIFIED: [restart httpd] ***************************************************** changed: [rhelsrv2] changed: [rhelsrv1] PLAY RECAP ******************************************************************** rhelsrv1 : ok=11 changed=10 unreachable=0 failed=0 rhelsrv2 : ok=11 changed=10 unreachable=0 failed=0
Installer et Configurer SAMBA, sous Debian
Cette fois-ci un playbook d'installation de SAMBA sur deux Debian.
A noter qu'il est déjà installé et configuré sur un des deux serveurs; comme le montrera l'exécution du playbook.
Le playbook : samba-debian.yml
Code BASH :
# samba-debian.yml --- - hosts: sambaservers 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 :
infra ansible # ansible-playbook samba-debian.yml
La console affiche :
Code BASH :
PLAY [sambaservers] *********************************************************** GATHERING FACTS *************************************************************** ok: [debsrv1] ok: [debsrv2] TASK: [1. Installer samba] **************************************************** ok: [debsrv1] changed: [debsrv2] TASK: [2. Démarrer service samba] ********************************************* ok: [debsrv1] ok: [debsrv2] TASK: [3. Création du dossier public] ***************************************** changed: [debsrv1] changed: [debsrv2] TASK: [4. Correction des droits] ********************************************** ok: [debsrv1] ok: [debsrv2] TASK: [5. Modification du fichier smb.conf] *********************************** ok: [debsrv1] changed: [debsrv2] TASK: [6 Copier le fichier personnalisé de samba] ***************************** ok: [debsrv1] changed: [debsrv2] NOTIFIED: [restart samba] ***************************************************** changed: [debsrv2] PLAY RECAP ******************************************************************** debsrv1 : ok=7 changed=1 unreachable=0 failed=0 debsrv2 : ok=8 changed=5 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
On voit bien dans le dernier point que le NOTIFIED ne s'applique qu'aux hôtes dont un changement a eu lieu...