Un premier playbook

1. Source

Source : https://github.com/goffinet/guide-ansible-playbooks/tree/master/ansible-linux/09-un-premier-playbook

2. Variables

Il est de bonne pratique d’organiser ses procédures avec des variables. Les variables Ansible peuvent être déclarées à différents endroits.

Dans l’inventaire ou dans les group_vars/’ ou ‘host_vars/. Mais aussi dans le livre de jeu, sous forme de :

  • valorisation directe
  • en référence à un fichier
  • en incluant des variables d’environnement
  • par “inclusion”
  • sont générés ou récoltées dynamiquement (facter)
  • viennent de l’inventaire
  • sont définies par défaut dans un rôle

Les variables sont applées en format Jinja2 sous la forme : {{ interface }} ou encore {{ ipv4.address }}.

Les guillemets sont nécessaires dans l’appel aux variables dans les paramètres car on appelle sa valeur. Par contre dans les opérations logiques telles que les conditions cette mise en guillemets n’est pas nécessaire.

Ansible est capable de récupérer des métadonnées sous forme de variables et comporte aussi des variables “dynamiques” ansible_*

Ansible-Vault permet de protéger ses variables.

3. Structure d’un playbook

---
- name: "PLAY 1"
  hosts: hosts
  vars:
    variable_x: value
  tasks:
    - name: "TASK 1"
      module_x:
        parameter_1: value
        parameter_2: value
    - name: "TASK 2"
      module_y:
        parameter_1: "{{ variable_x }}"
        parameter_2: value
- name: "PLAY 2"
  hosts: other_hosts
  tasks:
    - name: "TASK 3"
      module_z:
        parameter_1: value
        parameter_2: value

Voici un livre de jeu constitué de 2 séances de jeux “PLAY 1” et “PLAY2”. Le premier jeu “PLAY 1” opère contre le groupe “hosts” d’un inventaire et comprend deux tâches “TASK 1” et “TASK2”. Le second jeu “PLAY2” opère contre un autre groupe de l’inventaire et comprend une tâche “TASK 3”. Chaque tâche est nommée et fait appel à un module différent. Chaque module comprend des paramètres qui définissent les opérations.

Si vous êtes familier avec les techniques de scripting bash, il est facile d’imaginer qu’une commande et ses paramètres correspond à l’usage d’un module. Une indentation obligatoire présente les actions de manière élégante.

Remarquez également la définition et l’appel à la variable variable_x.

Enfin, à des fins de diagnostic et de documentation, on conseillera de dénommer ses jeux et ses tâches (avec la clé name:).

4. Un premier livre de jeu

On trouvera plus bas deux exemples de playbooks d’installation d’un serveur Web Nginx sous Ubuntu. Il ne s’agit là que d’un premier exemple simple inspiré de : Ansible: Up and Running, 2nd Edition, chap 2, A Very Simple Playbook.

Si on devait installer un service Nginx sous Debian/Ubuntu, la procédure pourrait ressembler à un script comme celui-ci web-notls.sh :

#!/bin/bash
sudo apt-get update
sudo apt-get -y install nginx
sudo cp /etc/nginx/sites-available/default nginx.conf
sed -i -e '/^\s*#.*$/d' -e '/^\s*$/d' nginx.conf
sudo sed -i 's/root \/var\/www\/html\;/root \/usr\/share\/nginx\/html\;/g' nginx.conf
sudo cp nginx.conf /etc/nginx/sites-available/default
cat << EOF > index.html
<html><head><title>Debian Ubuntu Nginx Installation</title></head>
<body><h1>Nginx Installed</h1><p>If you can see this, nginx is successfully installed.</p></body></html>
EOF
sudo cp index.html /usr/share/nginx/html/index.html
sudo chmod 644 /usr/share/nginx/html/index.html
sudo systemctl restart nginx
sudo apt -y install curl
curl http://localhost

Voici un jeu correspondant qui installe et démarre un service Web Nginx sur une machine Debian.

---
- name: Configure webserver with nginx
  hosts: webservers
  become: True
  become_method: sudo
  tasks:
    - name: install nginx
      apt:
        name: nginx
        update_cache: yes
    - name: copy nginx config file
      copy:
        src: files/nginx.conf
        dest: /etc/nginx/sites-available/default
    - name: enable configuration
      file:
        dest: /etc/nginx/sites-enabled/default
        src: /etc/nginx/sites-available/default
        state: link
    - name: copy index.html
      template:
        src: templates/index.html.j2
        dest: /usr/share/nginx/html/index.html
        mode: 0644
    - name: restart nginx
      service:
        name: nginx
        state: restarted

Ce fichier web-notls.yml est écrit en YAML, il commence par une ligne d’en-tête avec trois “dash” : ---.

Il comporte un seul jeu appelé “Configure webserver with nginx” qui porte sur les machines identifiées dans l’inventaire sous le nom “webservers”. Les actions du jeu, les “tasks” seront accomplies en tant qu’utilisateur privilégié (become: True). Le jeu comporte cinq tâches, chacune faisant appel à un module (apt, copy, file, template, service dans l’exemple) qui comporte des arguments.

On remarque l’indentation en liste de jeux et puis en liste de tâches.

Voici un second exemple d’un jeu appelé web-tls.yml qui implémente le même serveur en HTTPS.

---
- name: Configure webserver with nginx and tls
  hosts: webservers
  become: True
  become_method: sudo
  vars:
    key_file: /etc/nginx/ssl/nginx.key
    cert_file: /etc/nginx/ssl/nginx.crt
    conf_file: /etc/nginx/sites-available/default
    server_name: localhost
  tasks:
    - name: Install nginx
      apt:
        name: nginx
        update_cache: yes
        cache_valid_time: 3600
    - name: create directories for TLS certificates
      file:
        path: /etc/nginx/ssl
        state: directory
    - name: copy TLS key
      copy:
        src: files/nginx.key
        dest: {{ key_file }}
        owner: root
        mode: 0600
      notify: restart nginx
    - name: copy TLS certificate
      copy:
        src: files/nginx.crt
        dest: {{ cert_file }}
      notify: restart nginx
    - name: copy nginx config file
      template:
        src: templates/nginx.conf.j2
        dest: {{ conf_file }}
      notify: restart nginx
    - name: enable configuration
      file:
        dest: /etc/nginx/sites-enabled/default
        src: {{ conf_file }}
        state: link
      notify: restart nginx
    - name: copy index.html
      template:
        src: templates/index.html.j2
        dest: /usr/share/nginx/html/index.html
        mode: 0644
  handlers:
    - name: restart nginx
      service:
        name: nginx
        state: restarted

En regard du premier exemple, on trouvera ici l’usage de variables et le concept de “handlers”.

Les variables sont utilisées dans le jeu lui-même et dans des fichiers de modèle en format Jinja2, comme par exemple le modèle templates/nginx.conf.j2 : {{ server_name }}, {{ cert_file }}, {{ key_file }}.

server {
        listen 80 default_server;
        listen [::]:80 default_server ipv6only=on;

        listen 443 ssl;

        root /usr/share/nginx/html;
        index index.html index.htm;

        server_name {{ server_name }};
        ssl_certificate {{ cert_file }};
        ssl_certificate_key {{ key_file }};

        location / {
                try_files $uri $uri/ =404;
        }
}

Un “handler” est une sorte de tâche qui est appelée à la suite d’une notification dans une tâche (action notify). Dans le dernier exemple, l’action notify: restart nginx dans plusieurs des tâches appelle le “handler” du même nom.

Ces actions de “notification” sont déclenchées à la fin de chaque bloc de tâches dans un jeu et ne seront déclenchées qu’une seule fois, même si elles sont notifiées par plusieurs tâches différentes. Par exemple, plusieurs ressources peuvent indiquer qu’Apache doit être redémarré car elles ont modifié un fichier de configuration, mais apache ne sera relancé qu’une seule fois pour éviter les redémarrages inutiles.

4. Tester la syntaxe de son livre de jeu

ansible-lint est un utilitaire qui permet de tester la qualité des livres de jeu en proposant des suggestions de bonne pratique.

4.1. Installation de ansible-lint

pip install ansible-lint

4.2. Exemple ansible-lint

ansible-lint web-notls-new.yml
[201] Trailing whitespace
web-notls-new.yml:12
      copy:

5. Nourrir le livre de jeu

5.1. Améliorations

  • Mise en variables

5.2. Certificats auto-signés.

5.3. Let’s Encrypt