Proyecto 01 — Terraform local

Práctica guiada44 min
Duración
60 a 90 min (incluidos 30 min de preparación del equipo la primera vez)
Módulo
1/7
Vas a construir
un primer proyecto Terraform completo en tu máquina, un archivo message.txt creado, modificado y luego destruido por Terraform, y un equipo listo para los proyectos cloud (Terraform, AWS CLI, cuenta AWS de laboratorio)
Entregable
la carpeta projet-01-local con su main.tf, la salida de terraform state list antes y después de destroy, y tres líneas propias sobre el rol de terraform.tfstate
Costo
ninguno, el provider local no llama a ninguna API cloud

Cómo leer esta página. Cada sección está plegada bajo su título: haz clic en «Mostrar…» para abrirla, ciérrala cuando termines. Orden de lectura: Objetivo, luego En resumen (todos los comandos, para copiar en orden), luego El código (el archivo main.tf explicado línea por línea), luego Terraform, en la terminal (T1 a T13, un comando a la vez con su salida real). El paso a paso detallado, con la instalación de las herramientas, la preparación de la cuenta AWS y la salida esperada de cada gesto, está en el anexo: anexo A para Windows (PowerShell), anexo B para Linux, macOS, WSL 2 y Git Bash. Abre un solo anexo, el de tu sistema. El anexo C, común, agrupa los casos en los que algo se traba.

Objetivo

Llegas a un equipo que gestiona toda su infraestructura con Terraform. Antes de dejarte tocar la cuenta AWS, tu jefa te pide una cosa: «Muéstrame que dominas el ciclo completo en tu máquina. Un archivo es suficiente. Quiero ver el plan antes del apply, el state después, la modificación detectada, y una carpeta limpia al final.» Es exactamente este proyecto. El provider local escribe un archivo de texto en tu disco en lugar de crear un servidor, pero los comandos, las frases mostradas y los archivos producidos son los mismos que para un bucket S3 o un repositorio GitHub. Todo lo que lees aquí lo volverás a leer en los ocho proyectos siguientes.

Los diez pasos de este esquema se detallan, con la salida esperada de cada comando, en el anexo A (Windows) o el anexo B (Linux, macOS, WSL 2, Git Bash) al final de la página. Los comandos de Terraform en sí, idénticos en todos los sistemas, se explican uno por uno en Terraform, en la terminal.

En resumen: los comandos del proyecto

Mostrar los comandos

Kit del curso: https://github.com/hrhouma2/aiopsatlas-terraform-labo-fr

Clonas el kit en una carpeta lab-terraform, verificas tus herramientas, creas una carpeta de trabajo vacía, escribes tú mismo main.tf en ella, luego recorres el ciclo: init, fmt, validate, plan, apply, verificación, state, modificación, destroy. Al final, terraform state list ya no muestra nada y etat dice Ressources encore gérées : 0 (0 attendu à la fin d'une séance). El kit contiene el corregido en projets/01-terraform-local/, para abrir solo si te quedas atascado: el objetivo es escribir el archivo a mano.

Windows (PowerShell)

powershell
git clone https://github.com/hrhouma2/aiopsatlas-terraform-labo-fr.git lab-terraform
cd lab-terraform
dir                                  # explorer : labo.ps1, labo.sh, README.md, projets\
.\labo.ps1 prerequis                 # attendu : Prérequis : 4 outils requis présents sur 4.
.\labo.ps1 nouveau projet-01-local   # crée travail\projet-01-local
cd travail\projet-01-local
code .                               # VS Code : créer main.tf, coller le code de la section « Le code »
terraform init                       # attendu : Terraform has been successfully initialized!
terraform fmt
terraform validate                   # attendu : Success! The configuration is valid.
terraform plan                       # attendu : Plan: 1 to add, 0 to change, 0 to destroy.
terraform apply                      # répondre yes ; attendu : Apply complete! Resources: 1 added, 0 changed, 0 destroyed.
Get-Content .\message.txt            # attendu : Bonjour, ce fichier a été créé avec Terraform.
Get-ChildItem -Force                 # .terraform, .terraform.lock.hcl, main.tf, message.txt, terraform.tfstate
terraform state list                 # attendu : local_file.message
terraform state show local_file.message
# modifier la ligne content dans main.tf (voir T10), puis :
terraform plan                       # attendu : Plan: 1 to add, 0 to change, 1 to destroy.
terraform apply                      # répondre yes ; attendu : Apply complete! Resources: 1 added, 0 changed, 1 destroyed.
Get-Content .\message.txt            # attendu : Deuxième version du fichier créée avec Terraform.
terraform destroy                    # répondre yes ; attendu : Destroy complete! Resources: 1 destroyed.
terraform state list                 # attendu : rien
cd ..\..
.\labo.ps1 etat                      # attendu : Ressources encore gérées : 0 (0 attendu à la fin d'une séance).

Si PowerShell rechaza .\labo.ps1 («la ejecución de scripts está deshabilitada en este sistema»): Set-ExecutionPolicy -Scope CurrentUser RemoteSigned, responde O, vuelve a lanzar.

Linux, macOS, WSL 2, Git Bash

bash
git clone https://github.com/hrhouma2/aiopsatlas-terraform-labo-fr.git lab-terraform
cd lab-terraform
ls                                   # explorer : labo.ps1, labo.sh, README.md, projets/
./labo.sh prerequis                  # attendu : Prérequis : 4 outils requis présents sur 4.
./labo.sh nouveau projet-01-local    # crée travail/projet-01-local
cd travail/projet-01-local
code .                               # VS Code : créer main.tf, coller le code de la section « Le code »
terraform init                       # attendu : Terraform has been successfully initialized!
terraform fmt
terraform validate                   # attendu : Success! The configuration is valid.
terraform plan                       # attendu : Plan: 1 to add, 0 to change, 0 to destroy.
terraform apply                      # répondre yes ; attendu : Apply complete! Resources: 1 added, 0 changed, 0 destroyed.
cat message.txt                      # attendu : Bonjour, ce fichier a été créé avec Terraform.
ls -la                               # .terraform, .terraform.lock.hcl, main.tf, message.txt, terraform.tfstate
terraform state list                 # attendu : local_file.message
terraform state show local_file.message
# modifier la ligne content dans main.tf (voir T10), puis :
terraform plan                       # attendu : Plan: 1 to add, 0 to change, 1 to destroy.
terraform apply                      # répondre yes ; attendu : Apply complete! Resources: 1 added, 0 changed, 1 destroyed.
cat message.txt                      # attendu : Deuxième version du fichier créée avec Terraform.
terraform destroy                    # répondre yes ; attendu : Destroy complete! Resources: 1 destroyed.
terraform state list                 # attendu : rien
cd ../..
./labo.sh etat                       # attendu : Ressources encore gérées : 0 (0 attendu à la fin d'une séance).

Si ./labo.sh responde Permission denied: chmod +x labo.sh, una sola vez.

El código: archivo por archivo

Mostrar el archivo main.tf y su explicación línea por línea

El proyecto cabe en un solo archivo, main.tf, que debes crear en travail/projet-01-local/. Escríbelo o pégalo exactamente así (es palabra por palabra el corregido del kit, projets/01-terraform-local/main.tf):

hcl
terraform {
  required_providers {
    local = {
      source  = "hashicorp/local"
      version = "~> 2.5"
    }
  }
}

provider "local" {}

resource "local_file" "message" {
  filename = "${path.module}/message.txt"
  content  = "Bonjour, ce fichier a été créé avec Terraform."
}

Tres bloques, de lo más general a lo más concreto.

LíneaQué le dice a Terraform
terraform { … }Los ajustes de Terraform mismo para esta carpeta.
required_providers { local = { … } }«Este proyecto necesita un plugin llamado local
source = "hashicorp/local"Dónde descargarlo: el provider local publicado por HashiCorp en el Terraform Registry.
version = "~> 2.5"Qué versión aceptar: 2.5 o más reciente, pero no 3.0. En la máquina del curso, init eligió v2.9.1.
provider "local" {}«Activa este provider.» Las llaves están vacías porque el provider local no tiene nada que configurar (sin región, sin cuenta).
resource "local_file" "message" { … }«Gestiona un objeto de tipo local_file, que llamo message en mi código.» El tipo viene del provider (local_ + file); el nombre es tuyo. Juntos forman la dirección local_file.message.
filename = "${path.module}/message.txt"Dónde escribir el archivo. path.module es la carpeta que contiene este main.tf; Terraform lo mostrará como ./message.txt.
content = "Bonjour, ce fichier a été créé avec Terraform."El texto que se escribirá dentro. Es esta línea la que cambiarás en el paso T10.
Para entender bien: ¿por qué `${path.module}` y no simplemente `message.txt`?

Terraform lanza los comandos desde la carpeta actual. Si escribes filename = "message.txt", el archivo se crea donde escribes terraform apply, lo que generalmente es la carpeta correcta, pero no siempre (cuando el código se llama como módulo desde otra carpeta, en el módulo 5). path.module designa siempre la carpeta del archivo .tf, sin importar desde dónde se lance Terraform. La sintaxis ${…} inserta el valor de una expresión en una cadena de caracteres: "${path.module}/message.txt" se convierte en "./message.txt".

Para entender bien: ¿y si quito el bloque `terraform { required_providers … }`?

Funciona igual: Terraform deduce del tipo local_file que necesita el provider hashicorp/local, y init muestra Finding latest version of hashicorp/local... en lugar de Finding hashicorp/local versions matching "~> 2.5".... Es lo que hacen los dos talleres fundamentales de este módulo, para ir más rápido. Pero sin restricción de versión, dos colegas que lancen init con seis meses de diferencia pueden obtener dos versiones distintas del provider. En un proyecto real, siempre se escribe el bloque.

Terraform, en la terminal

Mostrar los 13 comandos de Terraform (T1 a T13)

Los comandos de esta sección se escriben en la carpeta travail/projet-01-local, una vez escrito main.tf. Son idénticos en Windows, Linux y macOS: Terraform es el mismo programa en todas partes. Las salidas son las de la máquina del curso (Terraform 1.12.2, Windows 11), capturadas tal cual; solo los identificadores (id=ff6b93dc…) y las huellas cambian de una máquina a otra. Los comandos que sí dependen del sistema (leer el archivo, listar la carpeta) están en tu anexo.

Una imagen para conservar durante toda la sección: la lección 01 te presentó al arquitecto. Cada comando a continuación es uno de sus gestos. init abre la obra, plan escribe el presupuesto, apply lo hace ejecutar, state relee el registro, destroy desmonta todo.

La regla: una sola novedad por comando. Se empieza con el comando que no toma ningún parámetro y no toca nada.

T1. ¿Qué versión de Terraform?

text
terraform version
text
Terraform v1.12.2
on windows_amd64

Lo que pide el comando: «Terraform, ¿qué versión eres, y en qué sistema?» Ningún parámetro, ningún archivo leído, nada modificado. Si este comando falla (terraform : Le terme «terraform» n'est pas reconnu… o command not found), nada más funcionará: es la instalación o el PATH, ver el anexo A.1 o B.1. En la máquina del curso, Terraform a veces añade dos líneas Your version of Terraform is out of date!: es información, no un error.

El equivalente conocido: aws --version, git --version, python --version. Mismo gesto, mismo propósito.

T2. Abrir la obra

text
terraform init
text
Initializing the backend...
Initializing provider plugins...
- Finding hashicorp/local versions matching "~> 2.5"...
- 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: «Lee mi main.tf, descarga los providers que necesita, y prepara esta carpeta para trabajar.»

Una sola novedad: la carpeta se convierte en un proyecto Terraform. Lee la salida línea por línea:

LíneaQué ocurrió
Initializing the backend...El backend es el lugar donde se guardará el state. Nada se especifica en main.tf, así que será un archivo local, terraform.tfstate.
Finding hashicorp/local versions matching "~> 2.5"...Terraform leyó tu restricción de versión y busca en el Registry.
Installing hashicorp/local v2.9.1...Eligió la más reciente que respeta ~> 2.5, y la descarga en .terraform/.
(signed by HashiCorp)El plugin está firmado: tienes el provider real.
Terraform has created a lock file .terraform.lock.hclLa versión elegida se anota en un archivo que hay que guardar en Git: el próximo init, en casa de un colega, tomará la misma.
Terraform has been successfully initialized!La frase que hay que esperar.

Aparecieron dos cosas en tu carpeta: el directorio oculto .terraform/ (el provider descargado, unos 18 MB en la máquina del curso, que nunca debe subirse a Git) y el archivo .terraform.lock.hcl (22 líneas, que sí debe subirse a Git). Los verás en el anexo, paso A.6 o B.6.

El equivalente conocido: npm install o pip install -r requirements.txt. Se lee una lista de dependencias, se descarga, se fijan las versiones (package-lock.json).

Para entender bien: ¿qué pasa si olvido `init`?

Terraform se niega a continuar y te dice qué hacer. terraform plan sin init responde:

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

y terraform validate sin init:

text
Error: Missing required provider

This configuration requires provider registry.terraform.io/hashicorp/local,
but that provider isn't available. You may be able to install it
automatically by running:
  terraform init

En ambos casos, la última línea es la solución. init puede relanzarse sin riesgo tantas veces como quieras; nunca toca tus recursos.

T3. Poner el código en orden

text
terraform fmt
text

Lo que pide el comando: «Realinea los espacios y la indentación de mis archivos .tf según el estilo oficial.»

Una sola novedad: la salida vacía. fmt muestra el nombre de cada archivo que modificó; si pegaste el código tal cual, no tiene nada que corregir y no muestra nada. No es un error, es la mejor respuesta posible. Si hubieras indentado mal una línea, habría mostrado main.tf y reescrito el archivo.

El equivalente conocido: prettier --write, black, gofmt. El kit verifica este punto con terraform fmt -check -recursive, que no modifica nada y sale en error (código 3) si un archivo no está en el formato correcto.

T4. Verificar la sintaxis

text
terraform validate
text
Success! The configuration is valid.

Lo que pide el comando: «Relee mis bloques. ¿Existen los nombres de argumentos, están cerradas las llaves, apuntan las referencias a algo?»

Una sola novedad: Terraform consulta al provider para conocer los argumentos válidos de un local_file. Por eso validate exige init antes. No lee el state, no contacta ninguna API, no crea nada. La frase que hay que esperar: Success! The configuration is valid.

Lo que detecta: contenu en lugar de content (An argument named "contenu" is not expected here. Did you mean "content"?), una llave olvidada (Error: Unclosed configuration block), una comilla sin cerrar (Error: Unterminated template string), un tipo inexistente (The provider hashicorp/local does not support resource type "local_fichier".). El anexo C los retoma uno por uno.

Lo que no detecta: una ruta que no existe, un nombre de bucket ya tomado, una mala arquitectura. validate dice «esto es HCL correcto», no «esto es una buena idea».

T5. Escribir 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.message will be created
  + resource "local_file" "message" {
      + content              = "Bonjour, ce fichier a été créé avec 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             = "./message.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: «Compara lo que describe mi código con lo que ya sabes, y dime qué harías, sin hacerlo.»

Una sola novedad: el presupuesto. Nada se ha creado; message.txt todavía no existe. Léelo de arriba a abajo:

LíneaCómo leerla
+ createLa leyenda: en este plan, solo hay creaciones.
# local_file.message will be createdLa dirección del recurso (tipo . nombre) y su destino.
+ resource "local_file" "message" {El bloque entero está precedido de un +: todo es nuevo.
+ content = "Bonjour, …"Un atributo que escribiste: Terraform conoce su valor.
+ content_md5 = (known after apply)Un atributo que el provider calculará después de la creación: la huella del contenido. Terraform no puede adivinarla antes.
+ directory_permission = "0777"Un atributo que no escribiste: el provider tiene un valor por defecto.
+ filename = "./message.txt"Tu ${path.module}/message.txt, resuelto.
Plan: 1 to add, 0 to change, 0 to destroy.La línea que hay que leer primero, siempre. Una creación, ninguna modificación, ninguna destrucción.
Note: You didn't use the -out option…Información: este presupuesto no se guarda; apply calculará otro. Sin importancia aquí.

El equivalente conocido: git diff antes de git commit, o el modo «simulación» (--dry-run, -WhatIf) de un script. La diferencia: un script --dry-run te muestra lo que va a hacer; terraform plan te muestra lo que falta entre el código y lo real, después de haber releído lo real.

Para entender bien: ¿por qué tantas líneas para un archivo de texto?

El provider local expone, para un local_file, todo lo que sabe calcular: seis huellas del contenido (md5, sha1, sha256, sha512, y dos versiones codificadas en base64), los permisos, el identificador. Solo escribiste dos (filename, content); los demás son atributos que el provider completa. Es lo mismo para un bucket S3: escribes tres líneas, el plan muestra treinta (ARN, región, identificador del propietario…). Aprende a reconocer los tuyos y a pasar por encima de los demás, excepto la última línea Plan:, que nunca se pasa por alto.

T6. 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.message will be created
  + resource "local_file" "message" {
      + content              = "Bonjour, ce fichier a été créé avec Terraform."

      + filename             = "./message.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.message: Creating...
local_file.message: Creation complete after 0s [id=ff6b93dc92e7e1d2ba4f9dad3cc16e03ac649b45]

Apply complete! Resources: 1 added, 0 changed, 0 destroyed.

Lo que pide el comando: «Recalcula el presupuesto, muéstramelo, y si respondo yes, hazlo.»

Una sola novedad: la pregunta. Terraform se detiene en Enter a value: y espera. Escribe yes completo, luego Enter. y, Y, oui o una línea vacía dan Apply cancelled. y nada se toca: es una protección, no un error. Luego tres líneas: Creating..., Creation complete after 0s [id=…] (el identificador que el plan anunciaba como (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.

Ahora, message.txt existe en tu carpeta, y apareció un nuevo archivo al lado: terraform.tfstate. Ve a verificarlo con tu anexo (A.6 o B.6) antes de continuar: el archivo contiene efectivamente Bonjour, ce fichier a été créé avec Terraform.

El equivalente conocido: un script que escribe el archivo, Set-Content o echo > message.txt. La diferencia: el script escribe y olvida; Terraform escribe y anota en su registro que escribió, con qué identificador, con qué contenido.

T7. Releer el registro: la lista

text
terraform state list
text
local_file.message

Lo que pide el comando: «Lista todo lo que gestionas en esta carpeta.»

Una sola novedad: el state se lee. Una línea, un recurso: la dirección local_file.message, la misma que en el plan. Esta línea prueba que Terraform vinculó el bloque de tu código con el archivo real: es lo que le permitirá modificarlo o destruirlo más tarde sin que tengas que decirle de nuevo cuál es.

Antes de apply, el mismo comando respondía No state file was found!: el registro todavía no existía. Después de destroy (T12), ya no responderá nada en absoluto.

El equivalente conocido: docker ps, kubectl get pods, aws s3 ls. «¿Qué está corriendo, qué existe?» Solo que state list no va a ver lo real: lee su cuaderno.

T8. Releer el registro: el detalle

text
terraform state show local_file.message
text
# local_file.message:
resource "local_file" "message" {
    content              = "Bonjour, ce fichier a été créé avec Terraform."
    content_base64sha256 = "G+tDdGue1Lx5hU3LpqBWf3y3haa0ggckj6t/9bj5ocs="
    content_base64sha512 = "oB7gPsGHBDNnXe9Hzx4zQ3/nAF1kM9wlfDV/OdMjPybCPurPeN4P8myOoZxFg3dwvs+xLBRJxo4Q3H0qGS8l5g=="
    content_md5          = "6daf774f0eb6d3da439c871afec7cf90"
    content_sha1         = "ff6b93dc92e7e1d2ba4f9dad3cc16e03ac649b45"
    content_sha256       = "1beb43746b9ed4bc79854dcba6a0567f7cb785a6b48207248fab7ff5b8f9a1cb"
    content_sha512       = "a01ee03ec1870433675def47cf1e33437fe7005d6433dc257c357f39d3233f26c23eeacf78de0ff26c8ea19c45837770becfb12c1449c68e10dc7d2a192f25e6"
    directory_permission = "0777"
    file_permission      = "0777"
    filename             = "./message.txt"
    id                   = "ff6b93dc92e7e1d2ba4f9dad3cc16e03ac649b45"
}

Lo que pide el comando: «Muéstrame todo lo que sabes del recurso local_file.message

Una sola novedad: el comando toma un parámetro, la dirección leída en T7. Compara con el plan de T5: todos los valores (known after apply) ahora están completados. El id es la huella SHA-1 del contenido, el mismo valor que content_sha1 y que el [id=…] que muestra apply. Es el registro del arquitecto, pieza por pieza.

Si te equivocas de dirección (local_file.mesage), Terraform responde No instance found for the given address! y te remite a terraform state list.

Para entender bien: qué contiene `terraform.tfstate`, y por qué nunca se edita

El archivo terraform.tfstate es JSON: un número de serie ("serial"), la versión de Terraform, y una lista "resources" donde cada recurso tiene exactamente los atributos que state show te muestra. Puedes abrirlo para leerlo. Nunca lo modificas a mano: una coma desplazada, y Terraform ya no reconoce lo que construyó, o cree gestionar algo que ya no existe. Para actuar sobre el state, existen comandos (terraform state rm, terraform state mv, terraform import) que verás en el módulo 4.

Otras dos reglas, desde hoy. El state puede contener secretos (aquí, el texto del archivo; en otros casos, una contraseña de base de datos): no se comparte por mensaje ni se sube a Git. Y es la memoria de Terraform: si lo eliminas, Terraform cree que nada existe y propone recrear todo, mientras que los recursos siguen ahí y, en el cloud, siguen siendo facturados.

T9. Pedir las salidas de un proyecto que no tiene ninguna

text
terraform output
text
Warning: No outputs found

The state file either has no outputs defined, or all the defined outputs are
empty. Please define an output in your configuration with the `output`
keyword and run `terraform refresh` for it to become available. If you are
using interpolation, please verify the interpolated value is not empty. You
can use the `terraform console` command to assist.

Lo que pide el comando: «Muestra los valores que el código eligió exponer con bloques output

Una sola novedad: una advertencia (Warning), no un error. Tu main.tf no tiene ningún bloque output, así que Terraform no tiene nada que mostrar y te lo dice. Escribirás tus primeros outputs en el proyecto 02; aquí, el comando sirve para ver la diferencia entre «esto falló» (Error:) y «no hay nada que mostrar» (Warning:).

T10. Modificar el código y releer el presupuesto

Abre main.tf, reemplaza la línea content por esta, guarda:

hcl
  content  = "Deuxième version du fichier créée avec Terraform."

Luego:

text
terraform plan
text
local_file.message: Refreshing state... [id=ff6b93dc92e7e1d2ba4f9dad3cc16e03ac649b45]

Terraform used the selected providers to generate the following execution
plan. Resource actions are indicated with the following symbols:
-/+ destroy and then create replacement

Terraform will perform the following actions:

  # local_file.message must be replaced
-/+ resource "local_file" "message" {
      ~ content              = "Bonjour, ce fichier a été créé avec Terraform." -> "Deuxième version du fichier créée avec Terraform." # forces replacement
      ~ content_base64sha256 = "G+tDdGue1Lx5hU3LpqBWf3y3haa0ggckj6t/9bj5ocs=" -> (known after apply)
      ~ content_base64sha512 = "oB7gPsGHBDNnXe9Hzx4zQ3/nAF1kM9wlfDV/OdMjPybCPurPeN4P8myOoZxFg3dwvs+xLBRJxo4Q3H0qGS8l5g==" -> (known after apply)
      ~ content_md5          = "6daf774f0eb6d3da439c871afec7cf90" -> (known after apply)
      ~ content_sha1         = "ff6b93dc92e7e1d2ba4f9dad3cc16e03ac649b45" -> (known after apply)
      ~ content_sha256       = "1beb43746b9ed4bc79854dcba6a0567f7cb785a6b48207248fab7ff5b8f9a1cb" -> (known after apply)
      ~ content_sha512       = "a01ee03ec1870433675def47cf1e33437fe7005d6433dc257c357f39d3233f26c23eeacf78de0ff26c8ea19c45837770becfb12c1449c68e10dc7d2a192f25e6" -> (known after apply)
      ~ id                   = "ff6b93dc92e7e1d2ba4f9dad3cc16e03ac649b45" -> (known after apply)
        # (3 unchanged attributes hidden)
    }

Plan: 1 to add, 0 to change, 1 to destroy.

Lo que pide el comando: lo mismo que en T5. Pero esta vez Terraform tiene un registro con el que comparar.

Una sola novedad: el símbolo -/+, «destruir y luego recrear». Tres pistas te lo dicen, y hay que saber identificarlas:

PistaDóndeQué dice
must be replacedel título # local_file.message must be replacedNo es will be updated in-place.
# forces replacemental final de la línea ~ content = "…" -> "…"Es este atributo el que obliga a reemplazar. El ~ delante dice que el valor cambia; el comentario dice que este cambio no puede hacerse en el lugar.
Plan: 1 to add, 0 to change, 1 to destroy.la última líneaUna destrucción y una creación, cero modificación.

Mira también la primera línea, nueva: Refreshing state... [id=…]. Antes de comparar, Terraform fue a releer el archivo real para verificar que todavía corresponde a su registro. Ahí es donde detectaría una deriva (lección 01), si hubieras modificado message.txt a mano.

La diferencia esencial entre ~ y -/+. Para un archivo de texto, ser reemplazado o modificado en el lugar da lo mismo: al final, el contenido es el nuevo. Para una base de datos, un disco o un usuario, -/+ significa pérdida del objeto y de su identificador: los datos del disco, la contraseña del usuario, la dirección IP del servidor. Es el provider quien decide, atributo por atributo, qué fuerza un reemplazo; tú lo lees en el plan antes de decir yes. El provider local reemplaza el archivo en cuanto content cambia: nunca un ~ solo para este atributo.

T11. Aplicar el reemplazo

text
terraform apply
text

Plan: 1 to add, 0 to change, 1 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.message: Destroying... [id=ff6b93dc92e7e1d2ba4f9dad3cc16e03ac649b45]
local_file.message: Destruction complete after 0s
local_file.message: Creating...
local_file.message: Creation complete after 0s [id=1df9196ac94445f0943c35b75c8c2e1bdf3e0cd6]

Apply complete! Resources: 1 added, 0 changed, 1 destroyed.

Lo que pide el comando: lo mismo que en T6.

Nada nuevo en el comando; todo está en la salida. Cuatro líneas de acción en lugar de dos: Destroying..., Destruction complete, luego Creating..., Creation complete. El orden es el del símbolo -/+: primero lo menos, luego lo más. Y el identificador cambió (ff6b93dc… antes, 1df9196a… después): es otro objeto, no el mismo modificado. Verifica el nuevo contenido con tu anexo (A.8 o B.8): Deuxième version du fichier créée avec Terraform.

Balance de T5 a T11: viste los dos presupuestos que releerás toda tu carrera: + (crear) y -/+ (reemplazar). El tercero, ~ (modificar en el lugar), no existe para el content de un local_file; lo encontrarás en los proyectos cloud, por ejemplo cuando una etiqueta (tag) cambia en un recurso AWS.

T12. Desmontar todo

text
terraform destroy
text
local_file.message: Refreshing state... [id=1df9196ac94445f0943c35b75c8c2e1bdf3e0cd6]

Terraform used the selected providers to generate the following execution
plan. Resource actions are indicated with the following symbols:
  - destroy

Terraform will perform the following actions:

  # local_file.message will be destroyed
  - resource "local_file" "message" {
      - content              = "Deuxième version du fichier créée avec Terraform." -> null
      - content_base64sha256 = "36Hz+L76pjLbvY4LIzPfw+UsqNneFneSfFGjtfRLxkI=" -> null

      - filename             = "./message.txt" -> null
      - id                   = "1df9196ac94445f0943c35b75c8c2e1bdf3e0cd6" -> null
    }

Plan: 0 to add, 0 to change, 1 to destroy.

Do you really want to destroy all resources?
  Terraform will destroy all your managed infrastructure, as shown above.
  There is no undo. Only 'yes' will be accepted to confirm.

  Enter a value: yes

local_file.message: Destroying... [id=1df9196ac94445f0943c35b75c8c2e1bdf3e0cd6]
local_file.message: Destruction complete after 0s

Destroy complete! Resources: 1 destroyed.

Lo que pide el comando: «Destruye todo lo que gestionas en esta carpeta, y muéstrame el presupuesto antes.»

Una sola novedad: el símbolo - solo, y una pregunta más grave: Do you really want to destroy all resources? … There is no undo. Cada atributo pasa a -> null: ya no quedará nada. La frase que hay que esperar: Destroy complete! Resources: 1 destroyed. El archivo message.txt desapareció de tu carpeta.

Es el comando que cierra cada sesión de este curso. Aquí borra un archivo de texto; en el proyecto 03 eliminará un bucket que, de lo contrario, seguiría facturándose.

T13. Verificar que el registro está vacío

text
terraform state list
text

Lo que pide el comando: lo mismo que en T7.

Nada nuevo, y una salida vacía: Terraform ya no gestiona nada en esta carpeta. El archivo terraform.tfstate todavía existe, pero su lista "resources" es [], y apareció un terraform.tfstate.backup al lado (la versión de antes del destroy, que Terraform guarda por precaución). Tu anexo (A.9 y A.10, o B.9 y B.10) te hace listar la carpeta y lanzar etat para la prueba final: Ressources encore gérées : 0 (0 attendu à la fin d'une séance).

Balance de T1 a T13: init una vez, luego fmt, validate, plan, apply, state list, state show, un plan y un apply de modificación, destroy, state list. Trece comandos, cinco frases que reconocer: successfully initialized!, The configuration is valid., Plan: N to add, N to change, N to destroy., Apply complete!, Destroy complete!.

El mensaje que hay que retener. Un script PowerShell o bash habría escrito message.txt en una línea, y lo habría eliminado en otra. Lo que el script no hace y que viste hacer a Terraform: anunciar antes de actuar (plan), pedir un acuerdo explícito (yes), anotar lo que creó (state list), releer lo real antes de cada decisión (Refreshing state...), distinguir modificar de reemplazar (-/+), y saber deshacer todo sin que se le tenga que repetir qué.

La consola AWS, en el navegador: preparar la cuenta para los proyectos siguientes

Mostrar la preparación de la cuenta AWS (grupo, usuario IAM, Access Key)

El proyecto 01 no toca AWS. Pero el proyecto 03 crea un bucket S3 real, y necesitarás una cuenta lista. Esta sección se hace en el navegador, es idéntica en Windows, Linux y macOS, y puedes hacerla antes o después del ciclo Terraform de este proyecto. Los comandos aws configure y aws sts get-caller-identity que la acompañan están en tu anexo (A.2 o B.2).

Si trabajas en AWS Academy, AWS Educate, un sandbox proporcionado por la escuela o una cuenta temporal de laboratorio: usa las credenciales proporcionadas por la plataforma y pasa directamente al paso A.2 o B.2 (caso «Academy»). No crees un usuario IAM si tu profesor ya te da accesos temporales.

Abrir la consola AWS

  1. Abre el navegador y ve a https://aws.amazon.com/.
  2. Haz clic en Sign in to the Console.
  3. Conéctate con la cuenta AWS del laboratorio.
  4. Verifica la región en la parte superior derecha. Para Canadá, elige ca-central-1 si el laboratorio no impone otra.

No trabajar con la cuenta root

La cuenta root sirve únicamente para crear la cuenta, gestionar la facturación y hacer las operaciones sensibles. Activa el MFA (autenticación de dos factores) en la cuenta root, luego crea un usuario separado para el trabajo de laboratorio, a continuación.

Crear un grupo administrador para el laboratorio

  1. En la barra de búsqueda de AWS, escribe IAM y abre el servicio IAM.
  2. Menú de la izquierda: User groupsCreate group.
  3. Nombre del grupo: terraform-admins.
  4. En la búsqueda de permisos, escribe AdministratorAccess, marca la política AdministratorAccess.
  5. Create group.

Solo para un laboratorio. AdministratorAccess otorga acceso completo a todos los servicios y recursos de la cuenta. Es práctico para aprender; no es un modelo de seguridad para producción, donde se le dan a Terraform solo los permisos que necesita (módulo 4).

Crear un usuario IAM para el laboratorio

  1. En IAM: UsersCreate user.
  2. Nombre: terraform-admin.
  3. Si también quieres conectarte a la consola con este usuario, marca Provide user access to the AWS Management Console y elige una contraseña temporal o generada. Marca User must create a new password at next sign-in si le entregas la cuenta a alguien.
  4. NextAdd user to group → marca terraform-adminsNextCreate user.

Crear una Access Key para AWS CLI

  1. En IAM: Users → haz clic en terraform-admin.
  2. Pestaña Security credentials, sección Access keysCreate access key.
  3. Elige Command Line Interface (CLI), marca la confirmación si AWS muestra una recomendación, Next.
  4. Description tag value: aws-cli-terraform-labCreate access key.
  5. Descarga el archivo .csv o copia Access key y Secret access key en un gestor de contraseñas. La Secret access key nunca volverá a mostrarse.

Lo que nunca debe hacerse. Nunca pegues una Access Key, una Secret Access Key, un token de sesión, un archivo .env o un terraform.tfstate en GitHub, Word, Teams, Discord, Slack, un ticket o un correo. Estos elementos dan acceso a la cuenta. Si una clave se filtra: IAM → el usuario → Security credentialsDeactivate y luego Delete, y se crea otra.

Desafío extra (opcional)

Antes de relanzar terraform destroy una segunda vez en una carpeta ya destruida, escribe en papel lo que dirá la última línea del plan. Luego lánzalo. Después, recrea el archivo con terraform apply, abre message.txt en VS Code, añade una palabra a mano, guarda, y escribe terraform plan: ¿qué dice la línea Refreshing state..., qué símbolo aparece, y cómo se llama esta diferencia en la lección 01? Termina con destroy: la carpeta debe volver a Ressources encore gérées : 0.

Anexo A — Paso a paso detallado en Windows (PowerShell)

Mostrar el paso a paso en Windows (A.0 a A.10)

Todos los comandos de este anexo se escriben en PowerShell (Windows Terminal o PowerShell 7), con .\labo.ps1 …. Las salidas reproducidas son las de la máquina del curso, en Windows 11 y Terraform 1.12.2.

A.0 — Antes de empezar

  • Haber leído las lecciones 01 y 02 del módulo.
  • Git instalado (git --version responde), VS Code instalado con el comando code disponible en PowerShell (si no: VS Code → Ctrl+Shift+P → «Shell Command: Install 'code' command in PATH», o reinstala marcando «Add to PATH»).
  • Si PowerShell rechaza ejecutar .\labo.ps1 («la ejecución de scripts está deshabilitada en este sistema»): Set-ExecutionPolicy -Scope CurrentUser RemoteSigned, responde O, vuelve a lanzar. Una sola vez por máquina.
  • Al final, .\labo.ps1 etat debe mostrar Ressources encore gérées : 0 (0 attendu à la fin d'une séance).

A.1 — Instalar Terraform

Lo más simple, con el gestor de paquetes de Windows:

powershell
winget install Hashicorp.Terraform

Cierra PowerShell, vuelve a abrirlo, luego:

powershell
terraform version

Punto de control:

text
Terraform v1.12.2
on windows_amd64

Tu versión puede ser más reciente; todo lo que sea 1.6 o superior es válido. Si Terraform añade Your version of Terraform is out of date!, es información, no un error.

Sin winget, con el binario oficial: ve a https://developer.hashicorp.com/terraform/install, elige Windows, descarga la versión AMD64, descomprime el .zip, crea la carpeta C:\terraform, mueve terraform.exe ahí, luego añade C:\terraform al PATH: menú Inicio → «variables de entorno» → Editar las variables de entorno del sistemaVariables de entorno → en Variables del sistema, selecciona PathEditarNuevoC:\terraformAceptar. Cierra todas las ventanas de PowerShell, vuelve a abrir, escribe de nuevo terraform version.

Si ves algo distinto: terraform : Le terme «terraform» n'est pas reconnu comme nom d'applet de commande… → Terraform no está en el PATH, o PowerShell no se reinició después de la instalación. Anexo C.

A.2 — Instalar y configurar AWS CLI versión 2 (para los proyectos siguientes)

El proyecto 01 no usa AWS; este paso prepara el proyecto 03. Puedes hacerlo ahora o dejarlo para más tarde.

  1. Ve a https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html, descarga el MSI Windows 64-bit de AWS CLI versión 2.
  2. Lanza el .msi: Next, acepta la licencia, mantén la carpeta por defecto, Install.
  3. Cierra y vuelve a abrir PowerShell.
powershell
aws --version

Punto de control: una versión que empieza con aws-cli/2 (en la máquina del curso: aws-cli/2.22.18). Si ves aws-cli/1, es la versión antigua: desinstálala.

Luego configura las claves creadas en la sección La consola AWS, en el navegador:

powershell
aws configure
text
AWS Access Key ID [None]: TON_ACCESS_KEY_ID
AWS Secret Access Key [None]: TA_SECRET_ACCESS_KEY
Default region name [None]: ca-central-1
Default output format [None]: json

Verifica que la CLI hable bien con AWS:

powershell
aws sts get-caller-identity

Ejemplo de respuesta (los valores son los de tu cuenta):

json
{
    "UserId": "AIDA...",
    "Account": "123456789012",
    "Arn": "arn:aws:iam::123456789012:user/terraform-admin"
}

Caso AWS Academy o sandbox temporal: abre el laboratorio, haz clic en AWS Details o Credentials, copia Access Key, Secret Key y Session Token (obligatorio con accesos temporales), luego:

powershell
aws configure set aws_access_key_id TON_ACCESS_KEY_ID
aws configure set aws_secret_access_key TA_SECRET_ACCESS_KEY
aws configure set aws_session_token TON_SESSION_TOKEN
aws configure set region ca-central-1
aws configure set output json
aws sts get-caller-identity

A.3 — Clonar el kit y verificar los prerrequisitos

Ubícate en la carpeta donde guardas tus proyectos (por ejemplo C:\Users\<tú>\Documents), luego:

powershell
git clone https://github.com/hrhouma2/aiopsatlas-terraform-labo-fr.git lab-terraform
cd lab-terraform
dir

Punto de control: dir lista projets, labo.ps1, labo.sh, README.md (y .gitattributes, .gitignore con dir -Force). Luego:

powershell
.\labo.ps1 prerequis
text
OK      terraform 1.12.2
OK      aws 2.22.18
OK      git 2.49.0.windows.1
OK      code 1.135.0
OK      gh 2.81.0 (optionnel)
ABSENT  az (optionnel, projet 08B seulement)
OK      gcloud 544.0.0 (optionnel)
Prérequis : 4 outils requis présents sur 4.

Las cuatro herramientas requeridas son terraform, aws, git y code. gh, az y gcloud son opcionales y pueden estar ABSENT sin consecuencia antes del módulo 3. Si aws está ABSENT porque dejaste A.2 para más tarde, la última línea dice 3 outils requis présents sur 4: puedes continuar este proyecto igualmente.

A.4 — Crear la carpeta de trabajo y abrirla en VS Code

powershell
.\labo.ps1 nouveau projet-01-local
text
Dossier travail\projet-01-local créé (ignoré par Git). Tapez :
  cd travail\projet-01-local

Haz lo que el script te indica, luego abre la carpeta en VS Code:

powershell
cd travail\projet-01-local
code .

La carpeta travail\ está ignorada por Git: puedes escribir libremente en ella sin ensuciar el kit. El corregido queda en projets\01-terraform-local\.

Si code . no hace nada: abre VS Code a mano, FileOpen Folder, y elige lab-terraform\travail\projet-01-local.

A.5 — Crear main.tf

En VS Code: icono New File en el explorador de la izquierda, nombra el archivo main.tf (atención: no main.tf.txt, VS Code no añade extensión pero el Bloc de notas de Windows sí lo haría), pega el código de la sección El código: archivo por archivo, guarda con Ctrl+S.

Verifica desde PowerShell:

powershell
Get-Content .\main.tf

Punto de control: las quince líneas del archivo, de terraform { a }. Luego:

powershell
Get-ChildItem

Una sola entrada: main.tf. Si ves main.tf.txt, renombra: Rename-Item main.tf.txt main.tf.

A.6 — Inicializar, formatear, validar, planificar, aplicar

Recorre T2 a T6 de la sección Terraform, en la terminal:

powershell
terraform init
terraform fmt
terraform validate
terraform plan
terraform apply

Responde yes a la pregunta de apply. Puntos de control, en orden: Terraform has been successfully initialized!, nada para fmt, Success! The configuration is valid., Plan: 1 to add, 0 to change, 0 to destroy., Apply complete! Resources: 1 added, 0 changed, 0 destroyed.

Verifica lo que apareció en la carpeta:

powershell
Get-ChildItem -Force
text
.terraform
.terraform.lock.hcl
main.tf
message.txt
terraform.tfstate

(-Force también muestra las entradas ocultas, las que empiezan con un punto; sin él, solo verías main.tf, message.txt y terraform.tfstate.) Cinco entradas:

EntradaQuién la creóQué es
.terraforminitCarpeta oculta, el provider descargado. Nunca en Git.
.terraform.lock.hclinitLas versiones de providers elegidas. En Git.
main.tfEl código.
message.txtapplyEl recurso.
terraform.tfstateapplyEl state, el registro. Nunca en Git, nunca compartido.

Lee el archivo creado:

powershell
Get-Content .\message.txt
text
Bonjour, ce fichier a été créé avec Terraform.

También puedes verificarlo en el explorador de Windows: abre la carpeta lab-terraform\travail\projet-01-local, haz doble clic en message.txt.

A.7 — Leer el state

Recorre T7, T8 y T9:

powershell
terraform state list
terraform state show local_file.message
terraform output

Puntos de control: local_file.message; el bloque completo con filename = "./message.txt" y un id de cuarenta caracteres; Warning: No outputs found.

Si tienes curiosidad, mira el state en sí, sin modificarlo:

powershell
Get-Content .\terraform.tfstate

JSON con "serial", "terraform_version": "1.12.2" y una lista "resources" que contiene local_file.message. Vuelve a cerrarlo. Nunca se edita a mano.

A.8 — Modificar el contenido y observar el reemplazo

En VS Code, reemplaza la línea content de main.tf por:

hcl
  content  = "Deuxième version du fichier créée avec Terraform."

Guarda, luego recorre T10 y T11:

powershell
terraform plan
terraform apply

Responde yes. Puntos de control: # local_file.message must be replaced, # forces replacement al final de la línea content, Plan: 1 to add, 0 to change, 1 to destroy., luego Apply complete! Resources: 1 added, 0 changed, 1 destroyed.

powershell
Get-Content .\message.txt
text
Deuxième version du fichier créée avec Terraform.

A.9 — Destruir y verificar

Recorre T12 y T13:

powershell
terraform destroy
terraform state list

Responde yes. Puntos de control: Destroy complete! Resources: 1 destroyed., luego una salida vacía para state list.

powershell
Get-ChildItem -Force
text
.terraform
.terraform.lock.hcl
main.tf
terraform.tfstate
terraform.tfstate.backup

message.txt desapareció. terraform.tfstate sigue ahí pero ya no contiene ningún recurso; terraform.tfstate.backup es la copia de antes del destroy. .terraform y .terraform.lock.hcl permanecen: es normal, te servirán si relanzas apply.

A.10 — El contador del kit

Vuelve a la raíz del kit y lanza etat:

powershell
cd ..\..
.\labo.ps1 etat
text
travail projet-01-local : aucune ressource
Ressources encore gérées : 0 (0 attendu à la fin d'une séance).

Si hubieras olvidado el destroy, la salida diría travail projet-01-local : 1 ressource dans le state y luego Ressources encore gérées : 1 (0 attendu à la fin d'une séance).: es el guardián que lanzarás al final de cada sesión, cuando los recursos se estén facturando.

Para empezar de nuevo desde cero, en lugar de limpiar la carpeta: .\labo.ps1 nouveau projet-01-reprise, y partes de una carpeta vacía.

Anexo B — Paso a paso detallado en Linux, macOS, WSL 2 y Git Bash

Mostrar el paso a paso en Linux, macOS, WSL 2 y Git Bash (B.0 a B.10)

Todos los comandos de este anexo se escriben en una terminal bash (o zsh en macOS), con ./labo.sh …. Las salidas de Terraform son las de la máquina del curso (Terraform 1.12.2); las salidas de ls -la se capturaron en Git Bash, las columnas de permisos, propietario y fecha difieren en tu caso.

B.0 — Antes de empezar

  • Haber leído las lecciones 01 y 02 del módulo.
  • Git instalado (git --version responde), VS Code instalado con el comando code disponible en la terminal (en macOS: VS Code → Cmd+Shift+P → «Shell Command: Install 'code' command in PATH»).
  • Si ./labo.sh responde Permission denied: chmod +x labo.sh, una sola vez.
  • Al final, ./labo.sh etat debe mostrar Ressources encore gérées : 0 (0 attendu à la fin d'une séance).

B.1 — Instalar Terraform

Sigue la página oficial https://developer.hashicorp.com/terraform/install para tu sistema. En resumen:

  • Ubuntu, Debian, WSL 2 Ubuntu: añade el repositorio HashiCorp (apt con la clave GPG, comandos copiados de la página oficial), luego sudo apt-get install terraform.
  • macOS con Homebrew: brew tap hashicorp/tap luego brew install hashicorp/tap/terraform.
  • Cualquier distribución, binario: descarga el .zip Linux AMD64 (o ARM64), unzip, luego sudo mv terraform /usr/local/bin/.
  • Git Bash en Windows: instala Terraform como en el anexo A.1 (winget), Git Bash lo ve en el PATH.

Cierra la terminal, vuelve a abrirla, luego:

bash
terraform version

Punto de control: Terraform v1.12.2 (o más reciente) seguido de on linux_amd64, on darwin_arm64 o on windows_amd64 según tu máquina. Todo lo que sea 1.6 o superior es válido.

Si ves algo distinto: bash: terraform: command not found → el binario no está en una carpeta del PATH (echo $PATH), o la terminal no se volvió a abrir. Anexo C.

B.2 — Instalar y configurar AWS CLI versión 2 (para los proyectos siguientes)

El proyecto 01 no usa AWS; este paso prepara el proyecto 03. Puedes hacerlo ahora o dejarlo para más tarde.

Sigue https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html para tu sistema (paquete .zip con ./aws/install en Linux, .pkg en macOS). Luego:

bash
aws --version

Punto de control: una versión que empieza con aws-cli/2. Si ves aws-cli/1, es la versión antigua: desinstálala.

Configura las claves creadas en la sección La consola AWS, en el navegador:

bash
aws configure
text
AWS Access Key ID [None]: TON_ACCESS_KEY_ID
AWS Secret Access Key [None]: TA_SECRET_ACCESS_KEY
Default region name [None]: ca-central-1
Default output format [None]: json

Verifica que la CLI hable bien con AWS:

bash
aws sts get-caller-identity

Ejemplo de respuesta (los valores son los de tu cuenta):

json
{
    "UserId": "AIDA...",
    "Account": "123456789012",
    "Arn": "arn:aws:iam::123456789012:user/terraform-admin"
}

Caso AWS Academy o sandbox temporal: abre el laboratorio, haz clic en AWS Details o Credentials, copia Access Key, Secret Key y Session Token (obligatorio con accesos temporales), luego:

bash
aws configure set aws_access_key_id TON_ACCESS_KEY_ID
aws configure set aws_secret_access_key TA_SECRET_ACCESS_KEY
aws configure set aws_session_token TON_SESSION_TOKEN
aws configure set region ca-central-1
aws configure set output json
aws sts get-caller-identity

B.3 — Clonar el kit y verificar los prerrequisitos

Ubícate en la carpeta donde guardas tus proyectos (por ejemplo ~/projets), luego:

bash
git clone https://github.com/hrhouma2/aiopsatlas-terraform-labo-fr.git lab-terraform
cd lab-terraform
ls

Punto de control: ls lista labo.ps1 labo.sh projets README.md (y .gitattributes, .gitignore con ls -a). Luego:

bash
./labo.sh prerequis
text
OK  terraform 1.12.2
OK  aws 2.22.18
OK  git 2.49.0.windows.1
OK  code 1.135.0
OK  gh 2.81.0 (optionnel)
ABSENT  az (optionnel, projet 08B seulement)
OK  gcloud 544.0.0 (optionnel)
Prérequis : 4 outils requis présents sur 4.

(Salida capturada en Git Bash, de ahí el git 2.49.0.windows.1; en Linux leerás tu propia versión de Git.) Las cuatro herramientas requeridas son terraform, aws, git y code. gh, az y gcloud son opcionales y pueden estar ABSENT sin consecuencia antes del módulo 3. Si aws está ABSENT porque dejaste B.2 para más tarde, la última línea dice 3 outils requis présents sur 4: puedes continuar este proyecto igualmente.

B.4 — Crear la carpeta de trabajo y abrirla en VS Code

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

Haz lo que el script te indica, luego abre la carpeta en VS Code:

bash
cd travail/projet-01-local
code .

La carpeta travail/ está ignorada por Git: puedes escribir libremente en ella sin ensuciar el kit. El corregido queda en projets/01-terraform-local/.

Si code . no hace nada: abre VS Code a mano, FileOpen Folder, y elige lab-terraform/travail/projet-01-local.

B.5 — Crear main.tf

En VS Code: icono New File en el explorador de la izquierda, nombra el archivo main.tf, pega el código de la sección El código: archivo por archivo, guarda con Ctrl+S (Cmd+S en macOS).

Tercer camino, sin editor, si prefieres la terminal:

bash
cat > main.tf <<'EOF'
terraform {
  required_providers {
    local = {
      source  = "hashicorp/local"
      version = "~> 2.5"
    }
  }
}

provider "local" {}

resource "local_file" "message" {
  filename = "${path.module}/message.txt"
  content  = "Bonjour, ce fichier a été créé avec Terraform."
}
EOF

(Las comillas alrededor de 'EOF' evitan que bash interprete ${path.module}: sin ellas, la línea filename quedaría vacía.) Verifica:

bash
cat main.tf
ls -la
text
total 1
drwxr-xr-x 1 rehou 197609   0 sept. 15 14:47 .
drwxr-xr-x 1 rehou 197609   0 sept. 15 14:47 ..
-rw-r--r-- 1 rehou 197609 286 sept. 15 14:47 main.tf

Punto de control: las quince líneas del archivo, y una sola entrada en la carpeta, main.tf, de unos 286 bytes.

B.6 — Inicializar, formatear, validar, planificar, aplicar

Recorre T2 a T6 de la sección Terraform, en la terminal:

bash
terraform init
terraform fmt
terraform validate
terraform plan
terraform apply

Responde yes a la pregunta de apply. Puntos de control, en orden: Terraform has been successfully initialized!, nada para fmt, Success! The configuration is valid., Plan: 1 to add, 0 to change, 0 to destroy., Apply complete! Resources: 1 added, 0 changed, 0 destroyed.

Verifica lo que apareció en la carpeta:

bash
ls -la
text
total 14
drwxr-xr-x 1 rehou 197609    0 sept. 15 14:47 .
drwxr-xr-x 1 rehou 197609    0 sept. 15 14:47 ..
drwxr-xr-x 1 rehou 197609    0 sept. 15 14:47 .terraform
-rw-r--r-- 1 rehou 197609 1257 sept. 15 14:47 .terraform.lock.hcl
-rw-r--r-- 1 rehou 197609  286 sept. 15 14:47 main.tf
-rw-r--r-- 1 rehou 197609   50 sept. 15 14:47 message.txt
-rw-r--r-- 1 rehou 197609 1667 sept. 15 14:47 terraform.tfstate

(-a también muestra las entradas ocultas, las que empiezan con un punto; -l da el detalle.) Cinco entradas además de . y ..:

EntradaQuién la creóQué es
.terraforminitCarpeta oculta, el provider descargado. Nunca en Git.
.terraform.lock.hclinitLas versiones de providers elegidas. En Git.
main.tfEl código.
message.txtapplyEl recurso. 50 bytes: el texto, sin salto de línea final.
terraform.tfstateapplyEl state, el registro. Nunca en Git, nunca compartido.

Lee el archivo creado:

bash
cat message.txt
text
Bonjour, ce fichier a été créé avec Terraform.

(El archivo no tiene salto de línea final: tu indicador de línea de comandos puede aparecer pegado al final de la frase. Es normal.)

B.7 — Leer el state

Recorre T7, T8 y T9:

bash
terraform state list
terraform state show local_file.message
terraform output

Puntos de control: local_file.message; el bloque completo con filename = "./message.txt" y un id de cuarenta caracteres; Warning: No outputs found.

Si tienes curiosidad, mira el state en sí, sin modificarlo:

bash
cat terraform.tfstate

JSON con "serial", "terraform_version": "1.12.2" y una lista "resources" que contiene local_file.message. Vuelve a cerrarlo. Nunca se edita a mano.

B.8 — Modificar el contenido y observar el reemplazo

En VS Code, reemplaza la línea content de main.tf por:

hcl
  content  = "Deuxième version du fichier créée avec Terraform."

Guarda, luego recorre T10 y T11:

bash
terraform plan
terraform apply

Responde yes. Puntos de control: # local_file.message must be replaced, # forces replacement al final de la línea content, Plan: 1 to add, 0 to change, 1 to destroy., luego Apply complete! Resources: 1 added, 0 changed, 1 destroyed.

bash
cat message.txt
text
Deuxième version du fichier créée avec Terraform.

B.9 — Destruir y verificar

Recorre T12 y T13:

bash
terraform destroy
terraform state list

Responde yes. Puntos de control: Destroy complete! Resources: 1 destroyed., luego una salida vacía para state list.

bash
ls -la
text
total 17
drwxr-xr-x 1 rehou 197609    0 sept. 15 14:47 .
drwxr-xr-x 1 rehou 197609    0 sept. 15 14:47 ..
drwxr-xr-x 1 rehou 197609    0 sept. 15 14:47 .terraform
-rw-r--r-- 1 rehou 197609 1257 sept. 15 14:47 .terraform.lock.hcl
-rw-r--r-- 1 rehou 197609  286 sept. 15 14:47 main.tf
-rw-r--r-- 1 rehou 197609  181 sept. 15 14:47 terraform.tfstate
-rw-r--r-- 1 rehou 197609 1667 sept. 15 14:47 terraform.tfstate.backup

message.txt desapareció. terraform.tfstate pasó de 1667 a 181 bytes: ya no contiene ningún recurso; terraform.tfstate.backup (1667 bytes) es la copia de antes del destroy. .terraform y .terraform.lock.hcl permanecen: es normal, te servirán si relanzas apply.

bash
cat terraform.tfstate
json
{
  "version": 4,
  "terraform_version": "1.12.2",
  "serial": 3,
  "lineage": "9ddb3372-803f-0964-7665-8413b8f65ee1",
  "outputs": {},
  "resources": [],
  "check_results": null
}

"resources": []: el registro está vacío. Tu lineage (el identificador único de este state) será diferente.

B.10 — El contador del kit

Vuelve a la raíz del kit y lanza etat:

bash
cd ../..
./labo.sh etat
text
travail projet-01-local : aucune ressource
Ressources encore gérées : 0 (0 attendu à la fin d'une séance).

Si hubieras olvidado el destroy, la salida diría travail projet-01-local : 1 ressource dans le state y luego Ressources encore gérées : 1 (0 attendu à la fin d'une séance).: es el guardián que lanzarás al final de cada sesión, cuando los recursos se estén facturando.

Para empezar de nuevo desde cero, en lugar de limpiar la carpeta: ./labo.sh nouveau projet-01-reprise, y partes de una carpeta vacía.

Anexo C — Si algo se traba (todos los sistemas)

Mostrar los casos que se traban

Cada caso: el mensaje exacto → la causa → el gesto.

  • terraform plan responde Error: Inconsistent dependency lock filerequired by this configuration but no version is selected → No lanzaste terraform init en esta carpeta (o añadiste un provider desde entonces). El mensaje termina con la solución: terraform init, y vuelve a lanzar.

  • terraform validate responde Error: Missing required providerYou may be able to install it automatically by running: terraform init → Misma causa, mismo gesto: terraform init.

  • Error: Unsupported argumentAn argument named "contenu" is not expected here. Did you mean "content"? → Error de tipeo en un nombre de argumento. Terraform a menudo propone la palabra correcta. Corrige, vuelve a guardar, relanza validate.

  • Error: Unclosed configuration blockThere is no closing brace for this block before the end of the file. → Falta una llave }. Cuéntalas: cada { tiene su }. En main.tf, hay tres pares anidados para el bloque terraform, uno para provider, uno para resource.

  • Error: Invalid multi-line string luego Error: Unterminated template stringNo closing marker was found for the string. → Falta una comilla " al final de un valor. La línea culpable se cita (3: content = "Bonjour Terraform).

  • Error: Invalid resource typeThe provider hashicorp/local does not support resource type "local_fichier". → El tipo de recurso no existe en este provider. Los tipos del provider local se llaman local_file y local_sensitive_file; la documentación del provider en el Registry da la lista.

  • Error: Invalid Attribute CombinationNo attribute specified when one (and only one) of [content,sensitive_content,content_base64] is required (repetido cuatro veces) → Quitaste la línea content: un local_file debe decir qué contiene. Vuelve a ponerla.

  • terraform validate dice Success! pero terraform plan responde Error: No configuration filescreate a Terraform configuration file (.tf file) and try again. → No hay ningún archivo .tf en la carpeta: o no estás en travail/projet-01-local (verifica con pwd), o el archivo se llama main.tf.txt. Renómbralo a main.tf. Una carpeta vacía es una configuración válida (vacía), de ahí el Success! engañoso.

  • terraform apply responde Apply cancelled. y nada se crea → Escribiste algo distinto de yes (por ejemplo y, Y, oui, o solo Enter). Vuelve a lanzar y escribe yes completo.

  • terraform state list responde No state file was found! → Todavía no se hizo ningún apply en esta carpeta, o no estás en la carpeta correcta. No es una falla: todavía no hay nada que listar.

  • terraform state show responde No instance found for the given address! → La dirección está mal escrita, o el recurso fue destruido. terraform state list da las direcciones exactas.

  • terraform fmt -check sale en error (código 3) mostrando main.tf → El archivo no está en el formato oficial (indentación, alineación de los =). No es un error de sintaxis: terraform fmt sin -check lo corrige.

  • Después de destroy, terraform.tfstate sigue ahí y crees que el destroy falló → No: ábrelo, "resources": []. El archivo permanece, vacío, con un terraform.tfstate.backup al lado. Destroy complete! Resources: 1 destroyed. es la prueba.

  • .\labo.ps1 etat o ./labo.sh etat muestra Ressources encore gérées : 1 → Se olvidó un destroy en una de las carpetas listadas arriba (travail projet-01-local : 1 ressource dans le state). Ve a esa carpeta, terraform destroy, yes, vuelve a lanzar etat.

  • Solo Windows — terraform : Le terme «terraform» n'est pas reconnu comme nom d'applet de commande, fonction, fichier de script ou programme exécutable. → Terraform no está en el PATH, o PowerShell no se reinició después de la instalación. Cierra todas las ventanas de PowerShell, vuelve a abrir, escribe de nuevo terraform version. Si persiste, anexo A.1 (agregar C:\terraform al PATH).

  • Solo Windows — aws : Le terme «aws» n'est pas reconnu… → AWS CLI no está instalado o PowerShell no se reinició. Reinstala AWS CLI versión 2 (A.2), cierra y vuelve a abrir PowerShell, escribe de nuevo aws --version.

  • Solo Windows — .\labo.ps1 es rechazado: «la ejecución de scripts está deshabilitada en este sistema»Set-ExecutionPolicy -Scope CurrentUser RemoteSigned, responde O, vuelve a lanzar. Una sola vez por máquina.

  • Solo Windows — el archivo se llama main.tf.txt → El Bloc de notas añade .txt. En PowerShell: Rename-Item main.tf.txt main.tf. Usa VS Code para crear los archivos.

  • Linux nativo y macOS — bash: terraform: command not found → El binario no está en una carpeta del PATH. sudo mv terraform /usr/local/bin/, o verifica la instalación por paquete (B.1). Vuelve a abrir la terminal.

  • macOS y bash — ./labo.sh responde Permission deniedchmod +x labo.sh, una sola vez. Si bash: ./labo.sh: /bin/bash^M: bad interpreter, el archivo tiene finales de línea de Windows: git config core.autocrlf input y vuelve a clonar, o sed -i 's/\r$//' labo.sh (sed -i '' … en macOS).

  • aws sts get-caller-identity responde AccessDenied o InvalidClientTokenId → La clave configurada no es la correcta, o el token de sesión de Academy expiró. aws configure con la clave de terraform-admin (verifica que el usuario esté en terraform-admins con AdministratorAccess), o vuelve a hacer aws configure set … con nuevas credenciales de Academy. Sin efecto en el proyecto 01, que no llama a AWS.

Lo que entregas

Una carpeta comprimida o un repositorio Git que contenga:

  • main.tf (el archivo final, con la segunda versión de content);
  • sorties.txt: la salida completa de terraform plan (primera versión), de terraform state list después de apply, del terraform plan de modificación (el que tiene must be replaced), y de terraform state list después de destroy (vacío);
  • README.md según el modelo a continuación.

No entregues ni la carpeta .terraform/, ni terraform.tfstate, ni ninguna Access Key.

markdown
# Proyecto 01 — Terraform local

- Terraform: (salida de `terraform version`)
- Sistema: Windows / Linux / macOS

## Lo que hice
init, fmt, validate, plan, apply, state list, state show, modificación de content, plan, apply, destroy, state list.

## El archivo terraform.tfstate, en tres líneas propias
(Para qué sirve. Por qué Terraform lo necesita para destroy. Por qué no se edita ni se comparte.)

## Qué me bloqueó, y cómo lo resolví
(Una línea, o «nada».)

Fuentes oficiales

Frase para recordar: Terraform no hace clic en la consola en tu lugar. Lee tu código, lo compara con su state y con lo real, te anuncia lo que va a cambiar, y luego crea, reemplaza o destruye para alcanzar el estado solicitado.