cursus.

Cours 4 · Infrastructure as CodeLeçon 1 sur 2

Provisionnement déclaratif

6 h de lecture9 sections Version PDF

À la fin de cette leçon, vous saurez

Infrastructure immuable ; Terraform : ressources, état, plan et application ; idempotence, modules et réutilisation, gestion de l'état partagé en équipe.

Il existe, dans presque toutes les organisations, un serveur que personne n'ose redémarrer. Il a été installé il y a quatre ans, configuré à la main, ajusté une dizaine de fois par des personnes qui ont depuis changé d'équipe. Il fonctionne. Nul ne sait exactement pourquoi, ni comment le reconstruire si le matériel lâche.

On l'appelle un serveur flocon : unique, et impossible à reproduire. Il est le symptôme d'un problème plus général, la dérive de configuration — l'écart qui se creuse entre ce qu'on croit avoir déployé et ce qui tourne réellement.

Ce chapitre supprime cette catégorie de problème en changeant l'objet qu'on manipule : on ne configure plus des machines, on décrit une infrastructure dans des fichiers versionnés.

Immuable plutôt que réparé

Deux façons de faire évoluer une machine.

La mutation : on se connecte, on met à jour un paquet, on modifie un fichier de configuration. Chaque intervention éloigne un peu plus la machine de son état d'origine, et deux serveurs installés le même jour finissent différents.

L'immuabilité : on ne modifie jamais une machine en service. On construit une nouvelle image, on déploie de nouvelles instances, on retire les anciennes. C'est exactement le conteneur du chapitre 3, à l'échelle de l'infrastructure — et c'est le même déploiement progressif qu'au chapitre 6.

La formule consacrée : on traite les serveurs comme du bétail, pas comme des animaux de compagnie. Un animal de compagnie a un nom, on le soigne quand il est malade. Un troupeau se compte : un animal malade est remplacé.

Trois bénéfices en découlent. Plus de dérive : l'état d'une machine est entièrement déterminé par l'image dont elle vient. Retour arrière trivial : redéployer l'image précédente. Et recette fidèle : le même code produit un environnement identique, ce qui est la condition posée au chapitre 6.

Déclaratif plutôt qu'impératif

C'est le second renversement, et il structure aussi le chapitre 9.

Un script impératif décrit les étapes : créer le réseau, puis la machine, puis la règle de pare-feu. Il suppose un état de départ connu, et devient faux dès que quelque chose existe déjà — il faut alors ajouter partout des « si cela n'existe pas ».

Une description déclarative énonce l'état voulu : il doit exister un réseau, deux machines et une règle. L'outil compare cette description au monde réel et calcule lui-même ce qu'il faut faire — créer, modifier, détruire, ou ne rien faire.

resource "aws_instance" "serveur_web" {  ami           = "ami-0c55b159"  instance_type = "t3.micro"  tags = { Name = "web-production" }} resource "aws_security_group" "web" {  ingress {    from_port   = 443    to_port     = 443    protocol    = "tcp"    cidr_blocks = ["0.0.0.0/0"]  }}

Ce fichier ne dit pas comment créer une machine : il dit qu'il doit en exister une, de ce type, avec ce nom. Le comment appartient à l'outil.

Plan, puis application

Terraform travaille en deux temps, et c'est ce qui le rend utilisable en équipe.

terraform plan     compare la description au monde réel                   et affiche CE QUI VA CHANGER, sans rien changer terraform apply    exécute ce plan

Le plan est l'artefact le plus important du chapitre. Il se lit avant d'agir, il se relit en demande de fusion, et il est le seul moyen de répondre à la question qui compte : « qu'est-ce que cette modification va détruire ? »

Terraform will perform the following actions:   + aws_instance.serveur_web_2      will be created  ~ aws_security_group.web          will be updated in-place  - aws_instance.ancien_serveur     will be destroyed-/+ aws_db_instance.principale      must be REPLACED

La dernière ligne est celle qu'il faut savoir repérer. Certaines modifications ne peuvent pas être appliquées sur place : changer la zone d'une machine, ou un paramètre immuable d'une base, implique de détruire puis recréer. Sur une base de production, c'est la perte des données — et le plan est le seul endroit où l'on peut s'en apercevoir avant.

D'où la règle de conduite : on lit le plan, ligne à ligne, et l'on cherche les - et les -/+. Un apply lancé sans avoir lu son plan est l'équivalent d'un rm -rf sans regarder le chemin.

L'état, et pourquoi c'est le point dur

Pour calculer un plan, Terraform a besoin de savoir ce qu'il a déjà créé. C'est le rôle du fichier d'état : la correspondance entre les ressources décrites dans le code et les objets réels chez le fournisseur.

   description (code)  ←──  état  ──→  monde réel

Trois écarts sont donc possibles, et ils ne se traitent pas de la même façon.

Le code a changé : c'est le cas normal, le plan propose les modifications.

Le monde réel a changé sans passer par Terraform — quelqu'un a modifié une règle depuis la console web. C'est la dérive, et le plan la révèle en proposant de revenir à ce qui est décrit. La bonne réaction n'est pas d'accepter la dérive mais de comprendre pourquoi quelqu'un a eu besoin de contourner le code.

L'état est perdu ou faux : Terraform ne sait plus ce qui lui appartient. Il proposera de recréer des ressources qui existent déjà, ce qui échouera — ou pire, réussira en double. C'est le scénario catastrophe du chapitre.

D'où trois règles, non négociables. L'état ne va jamais dans Git : il contient des valeurs sensibles en clair — mots de passe générés, clés — et deux personnes qui le versionnent produisent des conflits inextricables. Il vit dans un stockage distant partagé. Et ce stockage doit fournir un verrou : sans lui, deux apply simultanés écrivent chacun leur version de l'état, et la dernière écriture efface l'autre. On se retrouve avec des ressources créées que plus rien ne référence — invisibles, facturées, et impossibles à détruire proprement.

Idempotence et modules

L'idempotence est la propriété qui rend tout cela sûr : appliquer deux fois produit le même résultat qu'appliquer une fois. Puisque l'outil compare l'état voulu au réel, un second apply sans modification ne fait rien — No changes. C'est ce qui permet de relancer sans crainte après une interruption, et c'est ce que le chapitre 8 retrouvera avec Ansible.

Les modules évitent la duplication : un module « environnement applicatif » paramétré par le nom et la taille, instancié trois fois pour le développement, la recette et la production. C'est la même motivation que la fonction en programmation — et le même piège, un module trop paramétré devenant plus difficile à comprendre que le code qu'il factorise.

Quiz · vérifiez votre compréhension Sans réponse

Un plan Terraform affiche « -/+ aws_db_instance.principale must be replaced ». Que signifie cette ligne ?

Quiz · vérifiez votre compréhension Sans réponse

Deux ingénieurs lancent terraform apply en même temps sur un état stocké dans un simple fichier partagé, sans verrou. Que se passe-t-il ?

À vous

L'exercice construit un Terraform miniature, et c'est le seul moyen de voir ce que l'outil fait réellement.

Vous écrirez le calcul du plan : comparer la description, l'état et le monde réel, et en déduire les créations, modifications, remplacements et destructions. Le jeu de données contient un attribut immuable, pour que le -/+ apparaisse et qu'il faille le repérer.

Ensuite l'idempotence : appliquer, puis réappliquer, et vérifier qu'il ne se passe plus rien. Puis la dérive : quelqu'un modifie le monde réel sans passer par le code, et vous verrez le plan proposer de revenir en arrière.

La dernière partie simule deux applications concurrentes, avec et sans verrou. Vous compterez les ressources orphelines produites dans le premier cas.

Exercice · JavaScript · à vous de jouer

Calculez un plan avec remplacements et destructions, vérifiez l'idempotence, puis provoquez une dérive et une course.

En attente
// ── Trois sources de vérité ───────────────────────────────────────────────
const IMMUABLES = ["zone", "moteur"];   // modifier cela impose un remplacement

// Ce que le code décrit.
const CODE = {
  "instance.web":     { type: "t3.small", zone: "eu-west-1a" },
  "instance.web2":    { type: "t3.micro", zone: "eu-west-1b" },
  "securite.web":     { port: 443 },
  "base.principale":  { taille: 100, moteur: "postgres16" },
};

// Ce que l'outil croit avoir créé.
const ETAT = {
  "instance.web":     { type: "t3.micro", zone: "eu-west-1a" },
  "securite.web":     { port: 443 },
  "base.principale":  { taille: 100, moteur: "postgres15" },
  "instance.ancienne": { type: "t3.micro", zone: "eu-west-1a" },
};

// Ce qui existe réellement chez le fournisseur.
const REEL = { ...ETAT };

function plan(code, etat) {
  const actions = [];
  for (const [nom, voulu] of Object.entries(code)) {
    const connu = etat[nom];
    if (!connu) { actions.push({ signe: "+", nom, quoi: "sera créée" }); continue; }
    const differents = Object.keys(voulu).filter((k) => voulu[k] !== connu[k]);
    if (differents.length === 0) continue;
    // ← à écrire : si un attribut IMMUABLE change, c'est un remplacement
    actions.push({ signe: "~", nom, quoi: "modifiée sur place : " + differents.join(", ") });
  }
  // ← à écrire : ce qui est dans l'état mais plus dans le code sera détruit
  return actions;
}

function afficher(actions) {
  if (!actions.length) { console.log("      No changes. Infrastructure is up-to-date."); return; }
  for (const a of actions) {
    console.log("      " + a.signe.padStart(3) + " " + a.nom.padEnd(20) + a.quoi);
  }
}

// ── À VOUS ────────────────────────────────────────────────────────────────
// 1. Complétez plan() : remplacement sur attribut immuable, et destruction.
//    Repérez la ligne -/+ : que se passerait-il si l'on appliquait ?
// 2. Appliquez, puis replanifiez : vérifiez l'idempotence.
// 3. Simulez une DÉRIVE — quelqu'un modifie le monde réel depuis la console.
// 4. Simulez deux applications concurrentes sans verrou, puis avec.

afficher(plan(CODE, ETAT));

Console de sortie
Le résultat s'affiche dans la console

En travaux pratiques

Travaux pratiques 7 · sur machine

Décrire l'infrastructure, sans un centime d'hébergement

Écrire, planifier et appliquer une infrastructure réelle avec Terraform — en pilotant Docker en local, ce qui donne un vrai état, une vraie dérive et un vrai verrou.

3 h
Avant de commencer
  • Terraform ou OpenTofu installé
  • Docker en fonctionnement
  • Les images du TP 3 disponibles localement
  1. 1. Décrire la pile

    Avec le fournisseur Docker, décrivez un réseau, un volume, un conteneur de base et un conteneur applicatif. Lancez un plan et LISEZ-LE avant d'appliquer.

  2. 2. Éprouver l'idempotence

    Appliquez, puis replanifiez sans rien modifier. Notez ce qu'affiche le plan, et expliquez pourquoi.

  3. 3. Provoquer une dérive

    Arrêtez un conteneur à la main avec Docker, sans passer par Terraform. Replanifiez. Que propose l'outil, et pourquoi ?

  4. 4. Repérer un remplacement

    Modifiez un attribut modifiable sur place, puis un attribut immuable. Comparez les deux plans et repérez le symbole qui distingue une modification d'un remplacement.

  5. 5. Factoriser en module

    Transformez la description en module paramétré par le nom de l'environnement et le nombre d'exemplaires, puis instanciez-le deux fois : recette et production.

  6. 6. Casser l'état, et le réparer

    Faites une copie de sauvegarde du fichier d'état, puis supprimez-le. Replanifiez. Que propose Terraform ? Restaurez ensuite la sauvegarde.

  7. 7. La course

    À deux, sur le même état partagé sans verrou, lancez une application simultanément. Comparez ensuite le contenu de l'état et la liste réelle des conteneurs.

C'est réussi quand
  • Un second plan sans modification affiche « no changes »
  • Vous savez repérer un remplacement dans un plan et dire ce qu'il détruirait
  • Le module s'instancie deux fois sans duplication de code
  • Vous pouvez nommer au moins une ressource orpheline produite par la course

Ce que la suite en fait

Le chapitre 8 traite ce que celui-ci laisse de côté. Terraform crée une machine ; il ne dit pas ce qui tourne dessus. Ansible installe, configure, déploie — et l'on verra que la frontière entre les deux est moins nette qu'il n'y paraît, l'infrastructure immuable réduisant beaucoup le besoin de configuration.

Le chapitre 9 poussera le déclaratif jusqu'au bout : Kubernetes est une boucle de réconciliation permanente là où Terraform en exécute une à la demande. C'est la même idée, avec un contrôleur qui ne s'arrête jamais.

À retenir

Flashcards · 1 / 5Toucher pour retourner
Fin de la leçon

Vous avez parcouru les 9 sections.

Marquez-la terminée pour faire avancer votre parcours, ou revenez sur un point avant de passer à la suite.