Taller fundamental 1 — Terraform: un bloque, un plan, un state

Práctica guiada15 min
Duración
20 min
Módulo
1/7
Prerrequisitos
Terraform instalado (terraform version responde) y el kit clonado en lab-terraform (proyecto 01, anexo A.1 a A.4 o B.1 a B.4)
Vas a construir
un proyecto Terraform reducido al mínimo, un solo bloque de tres líneas, un archivo bonjour.txt creado por Terraform, y un state que vas a leer
Entregable
la salida de terraform state show local_file.bonjour del paso 9

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, state que las palabras se asientan. Los bloques «Para entender bien» son opcionales; ábrelos si un paso te deja una duda. Los comandos terraform … 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).

Objetivo

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.

El vocabulario en una imagen

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.

TerraformQué esEn este taller
bloque resource "tipo" "nombre"algo que gestionar, descrito en un archivo .tfresource "local_file" "bonjour"
tipo de recursoqué es, proporcionado por un providerlocal_file (un archivo en el disco)
nombre localcómo lo llamas en tu códigobonjour
direccióntipo . nombre, para referirse a él en otro lugarlocal_file.bonjour
argumentoun valor que escribes en el bloquefilename, content
atributoun valor que el provider calculaid, content_md5
planel presupuesto: lo que falta entre el código y lo realPlan: 1 to add, 0 to change, 0 to destroy.
stateel registro: lo que Terraform construyóterraform.tfstate, leído con state list y state show

Dónde escribir

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.

Paso 1 — Crear una carpeta vacía

Windows (PowerShell):

powershell
.\labo.ps1 nouveau atelier-1
cd travail\atelier-1

Linux, macOS, WSL 2, Git Bash:

bash
./labo.sh nouveau atelier-1
cd travail/atelier-1
text
Dossier travail/atelier-1 créé (ignoré par Git). Tapez :
  cd travail/atelier-1

Lo 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.

Paso 2 — Escribir un bloque, tres líneas

En VS Code (code . desde la carpeta), crea un archivo main.tf y escribe exactamente:

hcl
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):

powershell
Get-ChildItem
Get-Content .\main.tf

Linux, macOS, WSL 2, Git Bash:

bash
ls -la
cat main.tf

Una sola entrada, main.tf, y las cuatro líneas del archivo. Si ves main.tf.txt, renómbralo.

Para entender bien
  • "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.
  • Los espacios antes de = están alineados (filename =, content =): es el estilo de terraform fmt. No cambia nada el sentido.

Paso 3 — Pedir un plan demasiado pronto

text
terraform plan
text
Error: 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 init

Lo 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.

Paso 4 — Abrir la obra

text
terraform init
text
Initializing 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):

powershell
Get-ChildItem -Force

Linux, macOS, WSL 2, Git Bash:

bash
ls -la

Tres 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.

Para entender bien
  • 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.
  • Por qué «latest» es una trampa en equipo. Hoy 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.

Paso 5 — Leer el presupuesto

text
terraform plan
text
Terraform 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íneaQué dice
+ createLa leyenda del presupuesto: un solo símbolo usado, +, crear.
# local_file.bonjour will be createdLa 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.

Para entender bien
  • Dos líneas que escribiste, nueve que no escribiste. El plan muestra todo lo que el provider sabe de un 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.

Paso 6 — Hacer ejecutar el presupuesto

text
terraform apply
text
Terraform 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.

Paso 7 — Leer el archivo, listar la carpeta

Windows (PowerShell):

powershell
Get-Content .\bonjour.txt
Get-ChildItem -Force

Linux, macOS, WSL 2, Git Bash:

bash
cat bonjour.txt
ls -la
text
Bonjour Terraform
text
total 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.

Paso 8 — Leer el registro: la lista

text
terraform state list
text
local_file.bonjour

Lo 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.

Paso 9 — Leer el registro: el detalle

text
terraform state show local_file.bonjour
text
# 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.

Para entender bien
  • El state es un archivo JSON, 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ó.
  • Por qué Terraform necesita este registro. Si eliminas 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.
  • El state puede contener secretos. Aquí, el texto de un archivo. En otros casos, una contraseña de base de datos pasada como argumento. No va a Git, no se comparte por mensaje.

Paso 10 — Volver a pedir un plan: nada que hacer

text
terraform plan
text
local_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.)

Verificación final

Vuelve a la raíz del kit y lanza el contador:

Windows (PowerShell):

powershell
cd ..\..
.\labo.ps1 etat

Linux, macOS, WSL 2, Git Bash:

bash
cd ../..
./labo.sh etat
text
travail 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.

  • Escribiste un main.tf de un solo bloque, sin terraform {} ni provider {}, y fue suficiente.
  • Viste 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.
  • Sabes leer un plan: + 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.
  • Un segundo plan devuelve No changes.
  • Guardaste la salida de terraform state show local_file.bonjour (paso 9) como entregable.

Si algo se traba

Mostrar los casos frecuentes
  • 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 typedoes not support resource type "local_fichier" → El tipo es local_file, en inglés, con guión bajo.
  • Error: Unsupported argumentDid 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).