Comment lire cette page. Dix étapes, une commande à la fois. Pour chacune : la commande à taper, la sortie exacte de la machine du cours (Terraform 1.12.2), et ce qu'il faut regarder dedans. Tape toi-même chaque commande (pas de copier-coller) : c'est en écrivant
init,plan,apply,stateque les mots rentrent. Les blocs « Pour bien comprendre » sont facultatifs ; ouvre-les si une étape te laisse un doute. Les commandesterraform …sont identiques sous Windows, Linux et macOS ; quand une commande dépend du système (créer, lire, lister un fichier), les deux versions sont données, l'une sous l'autre. Si Terraform n'est pas installé ou si le kit n'est pas cloné, retourne au projet 01, section En bref (kit :https://github.com/hrhouma2/aiopsatlas-terraform-labo-fr).
Le projet 01 t'a fait dérouler treize commandes sur un main.tf de quinze lignes, avec un bloc terraform, un bloc provider et un bloc resource. Tu as vu les phrases défiler, mais quinze lignes, c'est déjà beaucoup pour savoir ce qui est indispensable. Ici, tu repars de zéro avec trois lignes utiles : un seul bloc resource, sans rien autour. Tu vas voir Terraform refuser de travailler sans init, puis lui faire écrire son devis, l'exécuter, et lire ce qu'il a noté dans son relevé. À la fin, tu sais ce qu'est un bloc, un plan et un state parce que tu les as fabriqués toi-même, l'un après l'autre.
Reprends l'architecte de la leçon 01. Un bloc resource est une ligne du plan de l'architecte : « ici, un fichier, avec ce nom et ce contenu ». Le plan (la commande) est le devis : ce que Terraform ferait pour que le réel ressemble au dessin. Le state est le relevé : ce que Terraform a effectivement construit, sous quel identifiant, avec quelles valeurs. Trois objets, trois commandes pour les voir : le bloc se lit dans main.tf, le devis avec terraform plan, le relevé avec terraform state show.
| Terraform | Ce que c'est | Dans cet atelier |
|---|---|---|
bloc resource "type" "nom" | une chose à gérer, décrite dans un fichier .tf | resource "local_file" "bonjour" |
| type de ressource | ce que c'est, fourni par un provider | local_file (un fichier sur le disque) |
| nom local | comment tu l'appelles dans ton code | bonjour |
| adresse | type . nom, pour en parler ailleurs | local_file.bonjour |
| argument | une valeur que tu écris dans le bloc | filename, content |
| attribut | une valeur que le provider calcule | id, content_md5 |
| plan | le devis : ce qui manque entre le code et le réel | Plan: 1 to add, 0 to change, 0 to destroy. |
| state | le relevé : ce que Terraform a construit | terraform.tfstate, lu par state list et state show |
Un terminal (PowerShell sous Windows ; bash ou zsh sous Linux, macOS, WSL 2 ou Git Bash), ouvert à la racine du kit lab-terraform, celle qui contient labo.ps1 et labo.sh. Et VS Code pour écrire le fichier. Les commandes terraform … s'écrivent exactement de la même façon partout ; seules les commandes pour créer, lire ou lister un fichier changent, et elles sont données dans les deux versions à chaque fois.
Windows (PowerShell) :
.\labo.ps1 nouveau atelier-1
cd travail\atelier-1Linux, macOS, WSL 2, Git Bash :
./labo.sh nouveau atelier-1
cd travail/atelier-1Dossier travail/atelier-1 créé (ignoré par Git). Tapez :
cd travail/atelier-1Ce que la commande demande : crée-moi un dossier de travail vide, travail/atelier-1, que Git ignorera (sous Windows le script écrit travail\atelier-1, avec la barre oblique inverse).
À regarder : le dossier est vide. Rien n'est encore un projet Terraform : c'est main.tf, puis init, qui vont le rendre tel.
Dans VS Code (code . depuis le dossier), crée un fichier main.tf et tape exactement :
resource "local_file" "bonjour" {
filename = "${path.module}/bonjour.txt"
content = "Bonjour Terraform"
}Ce que le fichier demande : « Terraform, gère pour moi un fichier sur le disque (local_file), que j'appelle bonjour ; il s'appelle bonjour.txt, dans ce dossier, et il contient Bonjour Terraform. »
À regarder : il n'y a ni bloc terraform, ni bloc provider. Rien que la ressource. Terraform va déduire tout le reste du mot local_file. Vérifie que le fichier est bien là et bien nommé :
Windows (PowerShell) :
Get-ChildItem
Get-Content .\main.tfLinux, macOS, WSL 2, Git Bash :
ls -la
cat main.tfUne seule entrée, main.tf, et les quatre lignes du fichier. Si tu vois main.tf.txt, renomme-le.
"local_file" puis "bonjour" : le type, puis le nom. Le type est imposé par le provider (local_file existe ; local_fichier n'existe pas, tu aurais Error: Invalid resource type). Le nom est à toi : bonjour, message, mon_fichier. Ensemble, ils forment l'adresse local_file.bonjour que tu retrouveras dans le plan et dans le state.filename et content sont des arguments : des valeurs que tu donnes. Pour local_file, content est obligatoire (sans lui : Error: Invalid Attribute Combination), filename aussi.${path.module} vaut « le dossier où se trouve ce fichier .tf » ; Terraform l'affichera ./bonjour.txt. Sans lui, filename = "bonjour.txt" marcherait aussi ici ; le projet 01 explique pourquoi on prend l'habitude de l'écrire.= sont alignés (filename =, content =) : c'est le style de terraform fmt. Ça ne change rien au sens.terraform planError: Inconsistent dependency lock file
The following dependency selections recorded in the lock file are
inconsistent with the current configuration:
- provider registry.terraform.io/hashicorp/local: required by this configuration but no version is selected
To make the initial dependency selections that will initialize the dependency
lock file, run:
terraform initCe que la commande demande : « Dis-moi ce que tu ferais pour que le réel ressemble à mon code. »
À regarder : Terraform refuse, et explique. Il a lu local_file, en a déduit qu'il lui faut le provider registry.terraform.io/hashicorp/local, et constate qu'il ne l'a pas (no version is selected). La dernière ligne est la solution : terraform init. C'est l'erreur que tout débutant rencontre une fois ; maintenant tu sais la lire.
terraform initInitializing the backend...
Initializing provider plugins...
- Finding latest version of hashicorp/local...
- Installing hashicorp/local v2.9.1...
- Installed hashicorp/local v2.9.1 (signed by HashiCorp)
Terraform has created a lock file .terraform.lock.hcl to record the provider
selections it made above. Include this file in your version control repository
so that Terraform can guarantee to make the same selections by default when
you run "terraform init" in the future.
Terraform has been successfully initialized!
You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.
…Ce que la commande demande : « Télécharge les providers que mon code réclame et prépare ce dossier. »
À regarder : Finding latest version of hashicorp/local... : sans bloc required_providers, Terraform prend la version la plus récente (v2.9.1 sur la machine du cours ; chez toi, peut-être plus). Dans le projet 01, la même ligne disait Finding hashicorp/local versions matching "~> 2.5"... parce que le code fixait une contrainte. Puis la phrase à attendre : Terraform has been successfully initialized!
Liste le dossier, avec les fichiers cachés :
Windows (PowerShell) :
Get-ChildItem -ForceLinux, macOS, WSL 2, Git Bash :
ls -laTrois entrées : .terraform (un dossier, le provider téléchargé), .terraform.lock.hcl (la version choisie, notée) et ton main.tf. Pas encore de bonjour.txt, pas encore de terraform.tfstate : init n'a rien construit.
init ne touche jamais à tes ressources. Tu peux le relancer autant de fois que tu veux. Il ne fait que préparer le dossier..terraform/ est lourd et se retélécharge (environ 18 Mo ici) : il ne va jamais dans Git. .terraform.lock.hcl est léger et précieux : il va dans Git, pour que ton collègue obtienne la même version du provider.v2.9.1 ; dans six mois, v3.0.0 avec un comportement différent. Le bloc required_providers du projet 01 (version = "~> 2.5") évite la surprise. Pour un atelier de vingt minutes, on s'en passe.terraform planTerraform used the selected providers to generate the following execution
plan. Resource actions are indicated with the following symbols:
+ create
Terraform will perform the following actions:
# local_file.bonjour will be created
+ resource "local_file" "bonjour" {
+ content = "Bonjour Terraform"
+ content_base64sha256 = (known after apply)
+ content_base64sha512 = (known after apply)
+ content_md5 = (known after apply)
+ content_sha1 = (known after apply)
+ content_sha256 = (known after apply)
+ content_sha512 = (known after apply)
+ directory_permission = "0777"
+ file_permission = "0777"
+ filename = "./bonjour.txt"
+ id = (known after apply)
}
Plan: 1 to add, 0 to change, 0 to destroy.
─────────────────────────────────────────────────────────────────────────────
Note: You didn't use the -out option to save this plan, so Terraform can't
guarantee to take exactly these actions if you run "terraform apply" now.Ce que la commande demande : la même qu'à l'étape 3. Cette fois Terraform a son provider, et il répond.
À regarder, ligne par ligne, parce que c'est la sortie que tu liras le plus souvent de toute ta vie avec Terraform :
| Ligne | Ce qu'elle dit |
|---|---|
+ create | La légende du devis : un seul symbole utilisé, +, créer. |
# local_file.bonjour will be created | L'adresse de ta ressource et son sort. Ce n'est pas encore fait : will be. |
+ resource "local_file" "bonjour" { | Ton bloc, recopié avec un + devant : tout est nouveau. |
+ content = "Bonjour Terraform" | Un argument que tu as écrit. Terraform en connaît la valeur. |
+ content_md5 = (known after apply) | Un attribut que tu n'as pas écrit et que le provider calculera après avoir créé le fichier : son empreinte. Terraform ne peut pas la connaître avant. |
+ directory_permission = "0777" | Un attribut que tu n'as pas écrit et dont le provider a une valeur par défaut. |
+ filename = "./bonjour.txt" | Ton ${path.module}/bonjour.txt, résolu : . est le dossier courant. |
+ id = (known after apply) | L'identifiant de la ressource, connu seulement après création. |
Plan: 1 to add, 0 to change, 0 to destroy. | La ligne à lire en premier. Une chose à ajouter, rien à changer, rien à détruire. |
Rien n'a été créé. Vérifie : bonjour.txt n'existe toujours pas dans le dossier.
local_file, pas seulement ce que tu lui as donné. Apprends à repérer tes arguments et à survoler les attributs, sauf la ligne Plan:.(known after apply) est la phrase la plus importante à comprendre pour la suite : quand une ressource B utilise l'id d'une ressource A pas encore créée, B affiche (known after apply) pour cette valeur, et Terraform sait qu'il doit créer A d'abord. C'est le graphe de dépendances de la leçon 02, vu depuis le plan.Note: You didn't use the -out option : ce devis n'est pas enregistré dans un fichier ; apply en recalculera un identique. -out sert quand un pipeline doit appliquer exactement le plan qui a été relu, plus loin dans le cours.terraform applyTerraform used the selected providers to generate the following execution
plan. Resource actions are indicated with the following symbols:
+ create
Terraform will perform the following actions:
# local_file.bonjour will be created
+ resource "local_file" "bonjour" {
+ content = "Bonjour Terraform"
…
+ filename = "./bonjour.txt"
+ id = (known after apply)
}
Plan: 1 to add, 0 to change, 0 to destroy.
Do you want to perform these actions?
Terraform will perform the actions described above.
Only 'yes' will be accepted to approve.
Enter a value: yes
local_file.bonjour: Creating...
local_file.bonjour: Creation complete after 0s [id=fd9aee5556589b4d797e6d49f8ec894e29e57713]
Apply complete! Resources: 1 added, 0 changed, 0 destroyed.Ce que la commande demande : « Recalcule le devis, montre-le-moi, attends mon accord, puis fais-le. »
À regarder : le même plan qu'à l'étape 5, puis la question. Tape yes, en entier, puis Entrée. Ensuite Creating..., Creation complete after 0s [id=fd9aee55…] : l'id qui était (known after apply) est maintenant connu. Et la phrase à attendre : Apply complete! Resources: 1 added, 0 changed, 0 destroyed. Les trois nombres sont ceux du plan.
Si tu tapes y au lieu de yes, Terraform répond Apply cancelled. et ne fait rien. Essaie une fois, pour l'avoir vu ; puis relance avec yes.
Windows (PowerShell) :
Get-Content .\bonjour.txt
Get-ChildItem -ForceLinux, macOS, WSL 2, Git Bash :
cat bonjour.txt
ls -laBonjour Terraformtotal 14
drwxr-xr-x 1 rehou 197609 0 sept. 15 14:55 .
drwxr-xr-x 1 rehou 197609 0 sept. 15 14:55 ..
drwxr-xr-x 1 rehou 197609 0 sept. 15 14:55 .terraform
-rw-r--r-- 1 rehou 197609 1228 sept. 15 14:55 .terraform.lock.hcl
-rw-r--r-- 1 rehou 197609 17 sept. 15 14:55 bonjour.txt
-rw-r--r-- 1 rehou 197609 111 sept. 15 14:55 main.tf
-rw-r--r-- 1 rehou 197609 1634 sept. 15 14:55 terraform.tfstate(Listing ls -la de la machine du cours ; Get-ChildItem -Force affiche les mêmes cinq noms, avec d'autres colonnes.)
Ce que les commandes demandent : « Montre-moi le contenu de bonjour.txt, puis tout ce qu'il y a dans le dossier, fichiers cachés compris. »
À regarder : Bonjour Terraform, 17 octets, exactement ton content, sans retour à la ligne final (sous bash, ton invite peut apparaître collée au texte : c'est normal). Et deux nouveautés dans le dossier depuis l'étape 4 : bonjour.txt, la ressource, et terraform.tfstate, le state. C'est apply qui a créé les deux, en même temps : le fichier sur le disque, et la note « je l'ai créé » dans le relevé.
terraform state listlocal_file.bonjourCe que la commande demande : « Liste tout ce que tu gères dans ce dossier. »
À regarder : une ligne, une ressource, désignée par son adresse local_file.bonjour, la même que dans le plan. C'est la preuve que Terraform a relié ton bloc au fichier réel. Avant l'étape 6, la même commande aurait répondu No state file was found! : il n'y avait pas encore de relevé.
terraform state show local_file.bonjour# local_file.bonjour:
resource "local_file" "bonjour" {
content = "Bonjour Terraform"
content_base64sha256 = "SvXkP5Iqo1rJKHgTVJnjanxfsNVGhb+r52mzUqZJYyg="
content_base64sha512 = "r3+PevYNJRFsHMz4H4U1DK+lg89nhO9SLJZMAqqtzPKiIv3ilrmbx5sYh2JCW9o5EF0NXanYmuxMvI2QN4Z1Ag=="
content_md5 = "ff3a967c227a58691a3d34a931d3eeb5"
content_sha1 = "fd9aee5556589b4d797e6d49f8ec894e29e57713"
content_sha256 = "4af5e43f922aa35ac92878135499e36a7c5fb0d54685bfabe769b352a6496328"
content_sha512 = "af7f8f7af60d25116c1cccf81f85350cafa583cf6784ef522c964c02aaadccf2a222fde296b99bc79b188762425bda39105d0d5da9d89aec4cbc8d9037867502"
directory_permission = "0777"
file_permission = "0777"
filename = "./bonjour.txt"
id = "fd9aee5556589b4d797e6d49f8ec894e29e57713"
}Ce que la commande demande : « Montre-moi tout ce que tu sais de local_file.bonjour. »
À regarder : la même forme que le plan de l'étape 5, mais sans aucun + et sans aucun (known after apply) : tout est connu, tout est noté. L'id est l'empreinte SHA-1 du contenu (fd9aee55…), identique à content_sha1 et à l'[id=…] affiché par apply. Tes deux arguments (filename, content) sont là, avec les neuf attributs calculés par le provider. C'est ta réponse-livrable : garde-la.
terraform.tfstate, dans ton dossier. Ouvre-le dans VS Code pour le lire : une liste "resources" avec un élément, et dedans exactement les valeurs que state show affiche. Ne le modifie jamais à la main : une virgule déplacée et Terraform ne reconnaît plus ce qu'il a construit.terraform.tfstate, bonjour.txt reste sur le disque, mais Terraform ne sait plus qu'il est à lui : au prochain plan, il proposera de le créer à nouveau. Le state est la seule mémoire de Terraform.terraform planlocal_file.bonjour: Refreshing state... [id=fd9aee5556589b4d797e6d49f8ec894e29e57713]
No changes. Your infrastructure matches the configuration.
Terraform has compared your real infrastructure against your configuration
and found no differences, so no changes are needed.Ce que la commande demande : la même qu'aux étapes 3 et 5.
À regarder : deux nouveautés par rapport à l'étape 5. Refreshing state... [id=…] : avant de comparer, Terraform est allé relire le fichier réel pour vérifier qu'il correspond encore au relevé. Puis No changes. Your infrastructure matches the configuration. : le code, le relevé et le réel disent la même chose, le devis est vide. C'est l'idempotence de la leçon 01, dans le terminal : relancer ne fait rien de plus.
Ne détruis rien. L'atelier fondamental 2 repart exactement de ce dossier, avec ce fichier et ce state. Si tu ne l'enchaînes pas tout de suite, laisse le dossier tel quel : rien n'est facturé, rien ne bouge. (Si tu veux vraiment tout effacer maintenant : terraform destroy, yes, et tu referas l'atelier 1 avant le 2.)
Remonte à la racine du kit et lance le compteur :
Windows (PowerShell) :
cd ..\..
.\labo.ps1 etatLinux, macOS, WSL 2, Git Bash :
cd ../..
./labo.sh etattravail atelier-1 : 1 ressource dans le state
Ressources encore gérées : 1 (0 attendu à la fin d'une séance).Réponse attendue : 1 ressource dans le state. Le (0 attendu à la fin d'une séance) est le rappel du kit ; ici il est normal d'être à 1, puisque l'atelier 2 va détruire cette ressource.
main.tf d'un seul bloc, sans terraform {} ni provider {}, et il a suffi.Error: Inconsistent dependency lock file et tu sais que la solution est dans la dernière ligne.init a créé .terraform/ et .terraform.lock.hcl, et rien d'autre.+ create, will be created, (known after apply), Plan: 1 to add, 0 to change, 0 to destroy.apply a demandé yes, créé bonjour.txt et terraform.tfstate.state list rend local_file.bonjour ; state show rend le bloc complet avec un id de quarante caractères.plan rend No changes.terraform state show local_file.bonjour (étape 9) comme livrable.terraform : Le terme «terraform» n'est pas reconnu… ou bash: terraform: command not found → Terraform n'est pas installé ou pas dans le PATH. Projet 01, annexe A.1 ou B.1..\labo.ps1 ou ./labo.sh : fichier introuvable → Tu n'es pas à la racine du kit. cd vers le dossier lab-terraform (celui qui contient labo.ps1, labo.sh, projets).Le dossier travail\atelier-1 existe déjà. Tapez : → Tu as déjà lancé nouveau atelier-1. Fais le cd indiqué ; si le dossier contient un ancien essai, supprime-le et relance nouveau.Error: Invalid resource type … does not support resource type "local_fichier" → Le type est local_file, en anglais, avec un tiret bas.Error: Unsupported argument … Did you mean "content"? → Faute de frappe dans un nom d'argument ; Terraform propose le bon.Error: Unclosed configuration block → L'accolade fermante } de la dernière ligne manque.Error: Unterminated template string → Un guillemet " manque en fin de valeur.terraform plan répond Error: No configuration files → Le fichier ne s'appelle pas main.tf (souvent main.tf.txt), ou tu n'es pas dans travail/atelier-1. Vérifie avec Get-ChildItem ou ls -la.Apply cancelled. → Tu as tapé autre chose que yes. Relance, tape yes en entier.terraform state list répond No state file was found! → Aucun apply n'a réussi dans ce dossier. Reprends à l'étape 6.terraform state show répond No instance found for the given address! → L'adresse est mal tapée ; terraform state list te donne la bonne (local_file.bonjour).