5.2 : Templates Jinja2 : générer des configs dynamiques

Dans la leçon précédente, on a copié un fichier de configuration Apache tel quel, avec le module copy. Mais ce fichier était statique : identique pour tous les serveurs. Que faire si chaque serveur web de Nordika doit avoir un nom de domaine différent, ou un port différent ? On ne va pas écrire un fichier .conf par serveur à la main — c’est exactement le genre de répétition que les templates Jinja2 éliminent.

Le principe : un gabarit, pas un fichier figé

Un template est un fichier qui ressemble à s’y méprendre à un fichier de configuration normal, sauf qu’il contient des zones dynamiques, remplacées par la valeur des variables au moment de l’exécution.

templates/nordika.conf.j2 :

<VirtualHost *:{{ apache_port }}>
    ServerName {{ server_domain }}
    DocumentRoot /var/www/{{ server_domain }}

    <Directory /var/www/{{ server_domain }}>
        AllowOverride All
        Require all granted
    </Directory>

    ErrorLog ${APACHE_LOG_DIR}/{{ server_domain }}-error.log
    CustomLog ${APACHE_LOG_DIR}/{{ server_domain }}-access.log combined
</VirtualHost>

Remarquez l’extension .j2 : c’est une convention (pas une obligation stricte), qui indique clairement « ceci est un template Jinja2 », et non un fichier de configuration à copier tel quel.

Le module template

- name: Déployer le VirtualHost à partir du template
  ansible.builtin.template:
    src: templates/nordika.conf.j2
    dest: /etc/apache2/sites-available/nordika.conf
  vars:
    apache_port: 80
    server_domain: "nordika.local"
  notify: Redémarrer Apache

À l’exécution, Ansible lit le template, remplace {{ apache_port }} par 80 et {{ server_domain }} par nordika.local, et dépose le résultat final sur la machine cible. Le fichier .j2 lui-même ne bouge jamais — c’est un gabarit réutilisable, pas un fichier de sortie.

Templater pour plusieurs serveurs différents, sans dupliquer le fichier .j2

C’est là que la vraie puissance apparaît : le même template peut produire un résultat différent pour chaque hôte, en combinant avec host_vars (vu en section 2) :

# host_vars/nrd-web1.yml
server_domain: "site-client-a.nordika.local"
apache_port: 80
# host_vars/nrd-web2.yml
server_domain: "site-client-b.nordika.local"
apache_port: 8080
- name: Déployer le VirtualHost à partir du template
  ansible.builtin.template:
    src: templates/nordika.conf.j2
    dest: /etc/apache2/sites-available/nordika.conf
  notify: Redémarrer Apache

Un seul fichier .j2, un seul playbook, et pourtant chaque serveur reçoit une configuration adaptée à sa propre identité — exactement l’esprit « un ordre, plusieurs avions » qu’on a posé depuis le début de cette formation.

La logique Jinja2 : conditions et boucles dans un template

Jinja2 ne se limite pas à remplacer des variables : on peut aussi y écrire des conditions et des boucles, avec une syntaxe entre {% %} (à distinguer de {{ }}, réservé à l’affichage d’une valeur) :

<VirtualHost *:{{ apache_port }}>
    ServerName {{ server_domain }}

{% if enable_ssl %}
    SSLEngine on
    SSLCertificateFile /etc/ssl/certs/{{ server_domain }}.crt
{% endif %}

{% for alias in server_aliases %}
    ServerAlias {{ alias }}
{% endfor %}
</VirtualHost>
vars:
  server_domain: "nordika.local"
  apache_port: 80
  enable_ssl: true
  server_aliases:
    - "www.nordika.local"
    - "intranet.nordika.local"

Le bloc {% if %} n’apparaît dans le fichier final que si enable_ssl est vrai. Le bloc {% for %} génère une ligne ServerAlias par élément de la liste server_aliases — la même logique de boucle qu’on a vue en 4.4 avec loop, mais appliquée cette fois à l’intérieur d’un fichier de configuration plutôt qu’à une liste de tâches.

Vérifier le rendu avant de déployer

Comme pour n’importe quelle tâche, --check --diff (vu en 3.4) est particulièrement parlant avec template : il affiche directement les lignes qui changeraient dans le fichier final, sans le déployer réellement.

ansible-playbook playbook_apache.yaml -i inventaire.yaml --check --diff

Ce qu’il faut retenir

  • Un template (.j2) est un gabarit réutilisable ; le module template génère le fichier final en y injectant les variables.
  • {{ }} affiche une valeur, {% %} exécute de la logique (conditions, boucles) — deux syntaxes Jinja2 différentes à ne pas confondre.
  • Combiné à host_vars, un seul template peut produire une configuration différente pour chaque machine.
  • --check --diff reste le meilleur réflexe avant un déploiement de configuration en production.

Dans la prochaine leçon, on compare concrètement template avec un autre module qu’on n’a fait qu’effleurer : lineinfile — pour savoir lequel choisir selon la situation.