RousselTMLEARNING

Article · Ansible : de la découverte à l'expertise

Fichiers dynamiques : Jinja2 et facts

1. Le moteur de templates Jinja2 #

Variables, expressions, filtres.

Principe #

Ansible s'appuie sur Jinja2 : tout texte entre {{ ... }} est évalué comme une expression, tout bloc entre {% ... %} est une instruction (boucle, condition). Le module template rend un fichier .j2 sur le contrôleur, puis le copie sur l'hôte : chaque machine reçoit un fichier adapté à ses variables et à ses facts.

Génération d'un fichier à partir d'un template Jinja2
Le même template produit un fichier différent pour chaque hôte.

Les facts : informations sur la machine #

ansible web1.lab -m setup -a "filter=ansible_distribution*"
ansible web1.lab -m setup -a "filter=ansible_memtotal_mb"
ansible web1.lab -m setup -a "filter=ansible_default_ipv4"

# Dans un playbook
- ansible.builtin.debug:
    msg: "{{ ansible_hostname }} - {{ ansible_distribution }} {{ ansible_distribution_version }} - {{ ansible_memtotal_mb }} Mo" 

Les facts les plus utilisés : ansible_hostname, ansible_fqdn, ansible_default_ipv4.address, ansible_os_family, ansible_processor_vcpus, ansible_memtotal_mb, ansible_mounts.

Bonne Pratique : Désactivez la collecte (gather_facts: false) sur les plays qui n'en ont pas besoin ou limitez-la avec gather_subset: ['!all', 'network'] pour gagner plusieurs secondes par hôte.

2. Écrire un template utile #

Boucles, conditions et filtres.

Exemple : configuration d'un reverse proxy #

# templates/upstream.conf.j2
# {{ ansible_managed }}
upstream backend {
{% for host in groups['webservers'] %}
    server {{ hostvars[host]['ansible_default_ipv4']['address'] }}:{{ app_port | default(8080) }}{% if loop.first %} weight=2{% endif %};
{% endfor %}
}

server {
    listen {{ proxy_port | default(80) }};
{% if enable_tls | default(false) %}
    listen 443 ssl;
    ssl_certificate /etc/ssl/{{ inventory_hostname }}.crt;
{% endif %}
    server_name {{ ansible_fqdn }};
    location / {
        proxy_pass http://backend;
        proxy_set_header X-Env "{{ env | upper }}";
    }
}
- name: Configurer le reverse proxy
  ansible.builtin.template:
    src: upstream.conf.j2
    dest: /etc/nginx/conf.d/upstream.conf
    mode: "0644"
    validate: nginx -t -c %s     # %s = fichier temporaire à valider
  notify: Recharger nginx
À savoir : La variable magique ansible_managed insère un commentaire « fichier géré par Ansible » : utile pour éviter les modifications manuelles.

Les filtres les plus utiles #

FiltreExempleRésultat
default{{ port | default(80) }}Valeur de repli
upper / lower{{ env | upper }}PROD
join{{ ['a','b'] | join(',') }}a,b
to_json / to_nice_yaml{{ cfg | to_nice_yaml }}Sérialisation
regex_replace{{ ver | regex_replace('^v','') }}Nettoyage
ipaddr{{ ip | ansible.utils.ipaddr('network') }}Calcul réseau
b64encode / hash{{ pwd | password_hash('sha512') }}Encodage et hash
int / float / bool{{ '8' | int + 1 }}9

3. Boucles, conditions et lookups #

Rendre les playbooks dynamiques.

loop, when et register #

- name: Créer plusieurs utilisateurs
  ansible.builtin.user:
    name: "{{ item.name }}"
    groups: "{{ item.groups | default(omit) }}"
  loop:
    - { name: alice, groups: sudo }
    - { name: bob }
  when: ansible_os_family == "Debian"

- name: Lire la version installée
  ansible.builtin.command: nginx -v
  register: nginx_version
  changed_when: false
  failed_when: nginx_version.rc not in [0, 1]

- ansible.builtin.debug:
    msg: "{{ nginx_version.stderr }}" 

Les lookups : lire des données externes #

vars:
  db_password: "{{ lookup('env', 'DB_PASSWORD') }}"
  ssh_key:     "{{ lookup('file', '~/.ssh/id_ed25519.pub') }}"
  today:       "{{ lookup('pipe', 'date +%F') }}"
  tokens:      "{{ query('community.general.random_string', length=24) }}"
  secret:      "{{ lookup('community.hashi_vault.hashi_vault', 'secret=kv/app:password') }}" 

Tester un template sans le déployer #

# Rendre un template localement pour vérifier le résultat
ansible web1.lab -m template -a "src=templates/upstream.conf.j2 dest=/tmp/upstream.conf" --check --diff
ansible localhost -m ansible.builtin.template -a "src=app.conf.j2 dest=/tmp/app.conf" -e @vars.yml
cat /tmp/app.conf
Erreur Courante : N'oubliez pas validate: sur les fichiers critiques (nginx, sshd, sudoers) : un template invalide déployé en production peut vous enfermer hors du serveur.

📄 Ansible : générer des fichiers dynamiques avec Jinja2 et les facts →

Mon suivi

  • ⏱ Durée estimée : ≈ 10 min

Connectez-vous pour suivre votre progression et prendre des notes. Se connecter

✉️ Poser une question

Articles recommandés

Linux vs Unix : Le Guide Complet des Commandes et Distributions

Comprenez les différences entre Linux et Unix, explorez les distributions (serveur, desktop, ligh...

Ansible : l'inventaire (statique, dynamique, groupes et variables)

Comprendre et maîtriser l'inventaire Ansible : fichiers INI et YAML, groupes, variables d'hôte et...

Ansible : les commandes Ad-Hoc

Exécuter des actions immédiates sur un parc de serveurs avec ansible : modules ping, command, she...

Ansible : structurer son code avec les rôles

Créer, organiser et réutiliser des rôles Ansible : arborescence, defaults, tasks, handlers, templ...

Ansible : gérer la sécurité (Vault, SSH, privilèges et secrets)

Sécuriser Ansible : Ansible Vault, authentification SSH par clés, become et sudo, no_log, durciss...

Ansible : gérer son infrastructure avec des playbooks (Infrastructure as Code)

Écrire des playbooks de production : structure d'un projet, plays, handlers, tags, strategy seria...

Ansible : piloter ses automatisations avec une interface graphique (AWX, Semaphore, AAP)

Comparer et installer les interfaces graphiques d'Ansible : AWX, Ansible Automation Platform, Sem...

Ansible : aller plus loin (tests, qualité, CI/CD et performance)

Industrialiser Ansible : ansible-lint, yamllint, Molecule, intégration continue, collections, exe...

Bonnes pratiques Vagrant : des environnements reproductibles et rapides

Bonnes pratiques Vagrant : Vagrantfile versionné, boxes épinglées, provisioning idempotent, multi...