Cómo leer esta página. Diez pasos, un comando a la vez. Para cada uno: el comando que hay que escribir, la salida exacta de la máquina del curso (Terraform 1.12.2), y qué hay que mirar en ella. Escribe tú mismo cada comando (sin copiar y pegar): es escribiendo
init,plan,apply,stateque las palabras se asientan. Los bloques «Para entender bien» son opcionales; ábrelos si un paso te deja una duda. Los comandosterraform …son idénticos en Windows, Linux y macOS; cuando un comando depende del sistema (crear, leer, listar un archivo), se dan las dos versiones, una debajo de la otra. Si Terraform no está instalado o si el kit no está clonado, vuelve al proyecto 01, sección En resumen (kit:https://github.com/hrhouma2/aiopsatlas-terraform-labo-fr).
El proyecto 01 te hizo recorrer trece comandos sobre un main.tf de quince líneas, con un bloque terraform, un bloque provider y un bloque resource. Viste las frases desfilar, pero quince líneas ya son muchas para saber qué es indispensable. Aquí partes de cero con tres líneas útiles: un solo bloque resource, sin nada alrededor. Vas a ver a Terraform negarse a trabajar sin init, luego hacerle escribir su presupuesto, ejecutarlo, y leer lo que anotó en su registro. Al final, sabes qué es un bloque, un plan y un state porque los fabricaste tú mismo, uno tras otro.
Retoma al arquitecto de la lección 01. Un bloque resource es una línea del plano del arquitecto: «aquí, un archivo, con este nombre y este contenido». El plan (el comando) es el presupuesto: lo que Terraform haría para que lo real se parezca al dibujo. El state es el registro: lo que Terraform efectivamente construyó, bajo qué identificador, con qué valores. Tres objetos, tres comandos para verlos: el bloque se lee en main.tf, el presupuesto con terraform plan, el registro con terraform state show.
| Terraform | Qué es | En este taller |
|---|---|---|
bloque resource "tipo" "nombre" | algo que gestionar, descrito en un archivo .tf | resource "local_file" "bonjour" |
| tipo de recurso | qué es, proporcionado por un provider | local_file (un archivo en el disco) |
| nombre local | cómo lo llamas en tu código | bonjour |
| dirección | tipo . nombre, para referirse a él en otro lugar | local_file.bonjour |
| argumento | un valor que escribes en el bloque | filename, content |
| atributo | un valor que el provider calcula | id, content_md5 |
| plan | el presupuesto: lo que falta entre el código y lo real | Plan: 1 to add, 0 to change, 0 to destroy. |
| state | el registro: lo que Terraform construyó | terraform.tfstate, leído con state list y state show |
Una terminal (PowerShell en Windows; bash o zsh en Linux, macOS, WSL 2 o Git Bash), abierta en la raíz del kit lab-terraform, la que contiene labo.ps1 y labo.sh. Y VS Code para escribir el archivo. Los comandos terraform … se escriben exactamente igual en todas partes; solo cambian los comandos para crear, leer o listar un archivo, y se dan en las dos versiones cada vez.
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-1Lo que pide el comando: créame una carpeta de trabajo vacía, travail/atelier-1, que Git ignorará (en Windows el script escribe travail\atelier-1, con barra invertida).
Qué mirar: la carpeta está vacía. Nada es todavía un proyecto Terraform: es main.tf, luego init, lo que lo va a convertir en tal.
En VS Code (code . desde la carpeta), crea un archivo main.tf y escribe exactamente:
resource "local_file" "bonjour" {
filename = "${path.module}/bonjour.txt"
content = "Bonjour Terraform"
}Lo que pide el archivo: «Terraform, gestiona para mí un archivo en el disco (local_file), que llamo bonjour; se llama bonjour.txt, en esta carpeta, y contiene Bonjour Terraform.»
Qué mirar: no hay bloque terraform, ni bloque provider. Solo el recurso. Terraform va a deducir todo el resto a partir de la palabra local_file. Verifica que el archivo esté ahí y bien nombrado:
Windows (PowerShell):
Get-ChildItem
Get-Content .\main.tfLinux, macOS, WSL 2, Git Bash:
ls -la
cat main.tfUna sola entrada, main.tf, y las cuatro líneas del archivo. Si ves main.tf.txt, renómbralo.
"local_file" luego "bonjour": el tipo, luego el nombre. El tipo lo impone el provider (local_file existe; local_fichier no existe, tendrías Error: Invalid resource type). El nombre es tuyo: bonjour, message, mon_fichier. Juntos forman la dirección local_file.bonjour que encontrarás en el plan y en el state.filename y content son argumentos: valores que tú das. Para local_file, content es obligatorio (sin él: Error: Invalid Attribute Combination), filename también.${path.module} significa «la carpeta donde está este archivo .tf»; Terraform lo mostrará como ./bonjour.txt. Sin él, filename = "bonjour.txt" también funcionaría aquí; el proyecto 01 explica por qué se toma la costumbre de escribirlo.= están alineados (filename =, content =): es el estilo de terraform fmt. No cambia nada el sentido.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 initLo que pide el comando: «Dime qué harías para que lo real se parezca a mi código.»
Qué mirar: Terraform se niega, y explica. Leyó local_file, dedujo que necesita el provider registry.terraform.io/hashicorp/local, y comprueba que no lo tiene (no version is selected). La última línea es la solución: terraform init. Es el error que todo principiante encuentra una vez; ahora sabes leerlo.
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.
…Lo que pide el comando: «Descarga los providers que reclama mi código y prepara esta carpeta.»
Qué mirar: Finding latest version of hashicorp/local...: sin bloque required_providers, Terraform toma la versión más reciente (v2.9.1 en la máquina del curso; en la tuya, quizá más reciente). En el proyecto 01, la misma línea decía Finding hashicorp/local versions matching "~> 2.5"... porque el código fijaba una restricción. Luego la frase que hay que esperar: Terraform has been successfully initialized!
Lista la carpeta, con los archivos ocultos:
Windows (PowerShell):
Get-ChildItem -ForceLinux, macOS, WSL 2, Git Bash:
ls -laTres entradas: .terraform (una carpeta, el provider descargado), .terraform.lock.hcl (la versión elegida, anotada) y tu main.tf. Todavía no hay bonjour.txt, todavía no hay terraform.tfstate: init no construyó nada.
init nunca toca tus recursos. Puedes relanzarlo tantas veces como quieras. Solo prepara la carpeta..terraform/ es pesado y se vuelve a descargar (unos 18 MB aquí): nunca va a Git. .terraform.lock.hcl es ligero y valioso: va a Git, para que tu colega obtenga la misma versión del provider.v2.9.1; en seis meses, v3.0.0 con un comportamiento diferente. El bloque required_providers del proyecto 01 (version = "~> 2.5") evita la sorpresa. Para un taller de veinte minutos, se puede omitir.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.Lo que pide el comando: lo mismo que en el paso 3. Esta vez Terraform tiene su provider, y responde.
Qué mirar, línea por línea, porque es la salida que leerás con más frecuencia en toda tu vida con Terraform:
| Línea | Qué dice |
|---|---|
+ create | La leyenda del presupuesto: un solo símbolo usado, +, crear. |
# local_file.bonjour will be created | La dirección de tu recurso y su destino. Todavía no está hecho: will be. |
+ resource "local_file" "bonjour" { | Tu bloque, copiado con un + delante: todo es nuevo. |
+ content = "Bonjour Terraform" | Un argumento que escribiste. Terraform conoce su valor. |
+ content_md5 = (known after apply) | Un atributo que no escribiste y que el provider calculará después de crear el archivo: su huella. Terraform no puede conocerla antes. |
+ directory_permission = "0777" | Un atributo que no escribiste y del que el provider tiene un valor por defecto. |
+ filename = "./bonjour.txt" | Tu ${path.module}/bonjour.txt, resuelto: . es la carpeta actual. |
+ id = (known after apply) | El identificador del recurso, conocido solo después de la creación. |
Plan: 1 to add, 0 to change, 0 to destroy. | La línea que hay que leer primero. Una cosa por añadir, nada por cambiar, nada por destruir. |
Nada se ha creado. Verifica: bonjour.txt todavía no existe en la carpeta.
local_file, no solo lo que le diste. Aprende a reconocer tus argumentos y a pasar por encima de los atributos, excepto la línea Plan:.(known after apply) es la frase más importante para entender lo que sigue: cuando un recurso B usa el id de un recurso A todavía no creado, B muestra (known after apply) para ese valor, y Terraform sabe que debe crear A primero. Es el grafo de dependencias de la lección 02, visto desde el plan.Note: You didn't use the -out option: este presupuesto no se guarda en un archivo; apply calculará uno idéntico. -out sirve cuando un pipeline debe aplicar exactamente el plan que fue releído, más adelante en el curso.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.Lo que pide el comando: «Recalcula el presupuesto, muéstramelo, espera mi aprobación, y luego hazlo.»
Qué mirar: el mismo plan que en el paso 5, luego la pregunta. Escribe yes, completo, luego Enter. Después Creating..., Creation complete after 0s [id=fd9aee55…]: el id que era (known after apply) ahora se conoce. Y la frase que hay que esperar: Apply complete! Resources: 1 added, 0 changed, 0 destroyed. Los tres números son los del plan.
Si escribes y en lugar de yes, Terraform responde Apply cancelled. y no hace nada. Pruébalo una vez, para haberlo visto; luego vuelve a lanzar con 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(Listado ls -la de la máquina del curso; Get-ChildItem -Force muestra los mismos cinco nombres, con otras columnas.)
Lo que piden los comandos: «Muéstrame el contenido de bonjour.txt, luego todo lo que hay en la carpeta, incluidos los archivos ocultos.»
Qué mirar: Bonjour Terraform, 17 bytes, exactamente tu content, sin salto de línea final (en bash, tu indicador puede aparecer pegado al texto: es normal). Y dos novedades en la carpeta desde el paso 4: bonjour.txt, el recurso, y terraform.tfstate, el state. Fue apply quien creó ambos, al mismo tiempo: el archivo en el disco, y la nota «lo creé» en el registro.
terraform state listlocal_file.bonjourLo que pide el comando: «Lista todo lo que gestionas en esta carpeta.»
Qué mirar: una línea, un recurso, designado por su dirección local_file.bonjour, la misma que en el plan. Es la prueba de que Terraform vinculó tu bloque con el archivo real. Antes del paso 6, el mismo comando habría respondido No state file was found!: todavía no había registro.
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"
}Lo que pide el comando: «Muéstrame todo lo que sabes de local_file.bonjour.»
Qué mirar: la misma forma que el plan del paso 5, pero sin ningún + y sin ningún (known after apply): todo se conoce, todo está anotado. El id es la huella SHA-1 del contenido (fd9aee55…), idéntico a content_sha1 y al [id=…] que muestra apply. Tus dos argumentos (filename, content) están ahí, con los nueve atributos calculados por el provider. Esta es tu respuesta-entregable: guárdala.
terraform.tfstate, en tu carpeta. Ábrelo en VS Code para leerlo: una lista "resources" con un elemento, y dentro exactamente los valores que muestra state show. Nunca lo modifiques a mano: una coma desplazada y Terraform ya no reconoce lo que construyó.terraform.tfstate, bonjour.txt permanece en el disco, pero Terraform ya no sabe que es suyo: en el siguiente plan, propondrá crearlo de nuevo. El state es la única memoria 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.Lo que pide el comando: lo mismo que en los pasos 3 y 5.
Qué mirar: dos novedades respecto al paso 5. Refreshing state... [id=…]: antes de comparar, Terraform fue a releer el archivo real para verificar que todavía corresponde al registro. Luego No changes. Your infrastructure matches the configuration.: el código, el registro y lo real dicen lo mismo, el presupuesto está vacío. Es la idempotencia de la lección 01, en la terminal: relanzar no hace nada más.
No destruyas nada. El taller fundamental 2 retoma exactamente esta carpeta, con este archivo y este state. Si no lo encadenas de inmediato, deja la carpeta tal cual: nada se factura, nada se mueve. (Si de verdad quieres borrar todo ahora: terraform destroy, yes, y tendrás que repetir el taller 1 antes del 2.)
Vuelve a la raíz del kit y lanza el contador:
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).Respuesta esperada: 1 ressource dans le state. El (0 attendu à la fin d'une séance) es el recordatorio del kit; aquí es normal estar en 1, ya que el taller 2 va a destruir este recurso.
main.tf de un solo bloque, sin terraform {} ni provider {}, y fue suficiente.Error: Inconsistent dependency lock file y sabes que la solución está en la última línea.init creó .terraform/ y .terraform.lock.hcl, y nada más.+ create, will be created, (known after apply), Plan: 1 to add, 0 to change, 0 to destroy.apply pidió yes, creó bonjour.txt y terraform.tfstate.state list devuelve local_file.bonjour; state show devuelve el bloque completo con un id de cuarenta caracteres.plan devuelve No changes.terraform state show local_file.bonjour (paso 9) como entregable.terraform : Le terme «terraform» n'est pas reconnu… o bash: terraform: command not found → Terraform no está instalado o no está en el PATH. Proyecto 01, anexo A.1 o B.1..\labo.ps1 o ./labo.sh: archivo no encontrado → No estás en la raíz del kit. cd hacia la carpeta lab-terraform (la que contiene labo.ps1, labo.sh, projets).Le dossier travail\atelier-1 existe déjà. Tapez : → Ya lanzaste nouveau atelier-1. Haz el cd indicado; si la carpeta contiene un intento anterior, elimínala y vuelve a lanzar nouveau.Error: Invalid resource type … does not support resource type "local_fichier" → El tipo es local_file, en inglés, con guión bajo.Error: Unsupported argument … Did you mean "content"? → Error de tipeo en un nombre de argumento; Terraform propone el correcto.Error: Unclosed configuration block → Falta la llave de cierre } de la última línea.Error: Unterminated template string → Falta una comilla " al final de un valor.terraform plan responde Error: No configuration files → El archivo no se llama main.tf (a menudo main.tf.txt), o no estás en travail/atelier-1. Verifica con Get-ChildItem o ls -la.Apply cancelled. → Escribiste algo distinto de yes. Vuelve a lanzar, escribe yes completo.terraform state list responde No state file was found! → Ningún apply tuvo éxito en esta carpeta. Retoma en el paso 6.terraform state show responde No instance found for the given address! → La dirección está mal escrita; terraform state list te da la correcta (local_file.bonjour).