Gestion de configuration et IaC
Comparer les approches de gestion de configuration (Ansible) et d'infrastructure as code (Terraform) et leurs garanties d'idempotence.
À retenir
- Ansible configure des systèmes existants, Terraform provisionne l'infrastructure elle-même.
- L'idempotence n'est garantie que par des modules déclaratifs, pas par shell/command bruts.
- Terraform détecte la dérive (drift) via son fichier d'état et le plan avant apply.
- Le lint et la revue de code sont indispensables avant toute application en production.
Deux familles d'outils, deux objectifs
La gestion de configuration (Ansible, Puppet, Chef) configure l'état interne de machines déjà existantes. L'infrastructure as code (Terraform, Pulumi, OpenTofu) déclare et provisionne les ressources d'infrastructure elles-mêmes (VM, réseaux, bases managées). Les deux se combinent en pratique : Terraform crée la VM, Ansible la configure.
Idempotence : le principe non négociable
Un playbook ou un module doit produire le même état final qu'il soit exécuté une fois ou dix fois. Ansible fournit des modules déclaratifs (package, service, copy, template) conçus pour vérifier l'état courant avant d'agir.
# playbook.yml — exemple idempotent avec Ansible
- name: Configurer le service nginx
hosts: web
become: true
tasks:
- name: Installer nginx
ansible.builtin.package:
name: nginx
state: present
- name: Déployer la configuration
ansible.builtin.template:
src: templates/nginx.conf.j2
dest: /etc/nginx/nginx.conf
owner: root
group: root
mode: "0644"
notify: Recharger nginx
- name: S'assurer que le service est actif
ansible.builtin.service:
name: nginx
state: started
enabled: true
handlers:
- name: Recharger nginx
ansible.builtin.service:
name: nginx
state: reloaded
Point clé
un module comme ansible.builtin.command ou shell n'est PAS idempotent par défaut : il réexécute la commande à chaque run. Il faut ajouter une condition (creates:, when:) ou préférer un module déclaratif natif.
Terraform : état déclaratif et plan avant apply
Terraform maintient un fichier d'état qui reflète les ressources réellement provisionnées. La commande terraform plan calcule le différentiel entre l'état désiré (code) et l'état réel avant toute modification.
# main.tf — exemple de ressource idempotente
resource "aws_instance" "web" {
ami = "ami-0abcdef1234567890"
instance_type = "t3.micro"
tags = {
Name = "web-prod-01"
ManagedBy = "terraform"
Environment = "production"
}
lifecycle {
prevent_destroy = true
}
}
Attention
modifier une ressource manuellement dans la console cloud après un terraform apply crée une dérive (drift) entre l'état réel et l'état Terraform ; le prochain plan peut alors proposer de revenir en arrière et écraser la modification manuelle, parfois de façon destructive.
Comparatif rapide
| Critère | Ansible | Terraform |
|---|---|---|
| Paradigme | Impératif ordonné, mais modules déclaratifs | Déclaratif avec état |
| Cible typique | Configuration de systèmes existants | Provisioning de ressources cloud |
| Idempotence | Dépend du module utilisé | Native via le state |
| Rollback | Manuel (nouveau playbook) | terraform plan + apply ciblé |
Revue et tests avant application
Toute modification d'un playbook ou d'un module Terraform doit passer par une revue de code (pull request), un lint (ansible-lint, terraform validate), et idéalement un test en environnement isolé avant application en production.
ansible-lint playbook.yml
terraform fmt -check
terraform validate
terraform plan -out=tfplan
Sur le terrain
un incident fréquent survient lorsqu'un terraform apply est lancé sans relire le plan généré, notamment après une mise à jour de provider qui modifie silencieusement des attributs par défaut (ex. type de volume, politique de suppression) — la relecture systématique du plan est la meilleure protection.
Astuce
verrouillez les versions de providers Terraform et de collections Ansible dans un fichier de lock (.terraform.lock.hcl, requirements.yml avec versions épinglées) pour éviter qu'une mise à jour silencieuse ne change le comportement en production.