Services et serveurs

Ansible : Automatiser la gestion de serveurs

Cet article a été mis à jour, vous consultez ici une archive de cet article!
Table des matières

ansible



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



Pour plus de facilité, je me rend dans le dossier ansible :

Code BASH :
cd /etc/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...

Il est tout à fait possible d'avoir Ansible installé sur une machine Gentoo, et d'installer des paquets sur une distribution Linux autre (CentOS, Debian ...)

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


  1. Installation d'un paquet.
  2. Copie d'un fichier vers le serveur cible.
  3. Installation d'un paquet.
  4. Installation d'un paquet.
  5. Vérification d'un service sur la position "démarré"
  6. Exécution d'une commande sur la machine cible, en l'exécutant depuis le répertoire /usr
  7. 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


  1. Installation d'un paquet.
  2. Installation d'un paquet.
  3. Illustration de l'installation de plusieurs paquets dans une même tâche.
  4. Installation d'un paquet.
  5. Vérification d'un service sur la position "démarré"
  6. Vérification d'un service sur la position "démarré"
  7. 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.
  8. Exécution d'une commande sur la machine cible
  9. 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
 


  1. Installation d'un paquet.
  2. Démarrage d'un service.
  3. Exécution d'une commande.
  4. Modification de droits.
  5. Ajout d'une ligne dans un fichier.
  6. 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à.