Ansible : Automatiser la gestion de serveurs



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



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

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

Il est tout à fait possible d'avoir Ansible installé sur une machine Calculate Linux, 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 : http://docs.ansible.com/list_of_all_modules.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 :
 
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 state=present' 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) <epel@fedoraproject.org>\"\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 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 :

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"
}
 


Par exemple, pour mettre à jour les serveurs rhel :

Code BASH :
ansible -m yum -a 'name=* state=latest' rhel



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 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


  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-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


  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 :
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
 


  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


On voit bien dans le dernier point que le NOTIFIED ne s'applique qu'aux hôtes dont un changement a eu lieu...
Cette page a été vue 41191 fois