Translate

sábado, 3 de octubre de 2026

Terraform desde cero: variables, outputs y recursos


En el artículo anterior vimos qué problema intenta resolver Terraform y qué significa Infrastructure as Code.

La idea fundamental era: En lugar de configurar nuestra infraestructura manualmente, podemos describirla mediante código.

Ahora vamos a dar el siguiente paso.

En este artículo vamos a conocer tres conceptos que aparecen prácticamente en cualquier proyecto de Terraform:

  • Resources
  • Variables
  • Outputs

Y vamos a terminar viendo dónde aparece un concepto fundamental: el state.


Resources: los recursos que queremos crear

El concepto más importante de Terraform probablemente sea el de resource.

Un resource representa algo que queremos administrar.


Por ejemplo:

  • una máquina virtual;
  • una base de datos;
  • un bucket;
  • una red;
  • una regla de firewall;
  • un DNS;
  • un archivo local.


En el artículo anterior utilizamos:


resource "local_file" "hello" {

  filename = "hello.txt"

  content  = "Hola desde Terraform!"

}


La estructura general es:


resource "TIPO" "NOMBRE" {

  ...

}


Por ejemplo:


resource "local_file" "hello" {

  filename = "hello.txt"

  content  = "Hola desde Terraform!"

}


Tenemos dos nombres importantes:


local_file

    │

    └── tipo de recurso


hello

    │

    └── nombre del recurso


Por lo tanto, dentro de Terraform podemos referirnos a este recurso como:

local_file.hello


Es importante entender que local_file no es algo que Terraform conozca mágicamente.

Lo proporciona un provider.


Providers

Terraform utiliza providers para comunicarse con diferentes plataformas y servicios.

Por ejemplo, existen providers para trabajar con:

  • AWS
  • Azure
  • Google Cloud
  • Kubernetes
  • GitHub
  • Docker
  • bases de datos
  • recursos locales


Por ejemplo, para nuestro ejemplo local:


terraform {

  required_providers {

    local = {

      source = "hashicorp/local"

    }

  }

}


provider "local" {}


Y entonces podemos utilizar:


resource "local_file" "hello" {

  filename = "hello.txt"

  content  = "Hola desde Terraform!"

}


Podemos pensar en el provider como el componente que sabe cómo comunicarse con el sistema que estamos administrando.


Terraform sabe interpretar nuestra configuración.

El provider sabe cómo convertir esa configuración en operaciones sobre un servicio concreto.

Supongamos ahora que queremos crear dos archivos:


resource "local_file" "hello" {

  filename = "hello.txt"

  content  = "Hola desde Terraform!"

}


resource "local_file" "goodbye" {

  filename = "goodbye.txt"

  content  = "Chau desde Terraform!"

}


Funciona perfectamente.

Pero imaginemos que el nombre de nuestro ambiente aparece en varios lugares:


resource "local_file" "config" {
  filename = "production-config.txt"
  content  = "Configuración de production"
}


¿Qué pasa si mañana queremos utilizar exactamente la misma configuración para development?

Podríamos copiar el archivo y modificar los valores.

Pero eso rápidamente empieza a convertirse en un problema.

Queremos parametrizar nuestra infraestructura.

Ahí aparecen las variables.


Variables

Una variable permite definir un valor que puede cambiar sin modificar directamente nuestro resource.

Por ejemplo:

variable "environment" {
  type    = string
  default = "development"
}

Ahora podemos utilizarla:

resource "local_file" "config" {
  filename = "${var.environment}-config.txt"

  content = "Configuración de ${var.environment}"
}


Terraform reemplazará:

${var.environment}

por el valor correspondiente.


Con el valor por defecto:

development

terminaremos teniendo:

development-config.txt

y su contenido será:

Configuración de development

No siempre queremos definir un valor por defecto.

Por ejemplo:

variable "environment" {
  type = string
}

Ahora Terraform necesita que le proporcionemos un valor.

Podemos hacerlo mediante un archivo:

terraform.tfvars

con:

environment = "production"

Y nuestro resource puede seguir siendo exactamente el mismo:

resource "local_file" "config" {
  filename = "${var.environment}-config.txt"

  content = "Configuración de ${var.environment}"
}

Esto es interesante porque podemos utilizar la misma infraestructura para diferentes ambientes.


Por ejemplo:

development
staging
production

cambiando solamente los valores de entrada.

¿Por qué no poner todo directamente en el resource?

Podríamos escribir:

resource "local_file" "config" {
  filename = "production-config.txt"
  content  = "Configuración de production"
}

Pero entonces nuestro código está acoplado a un ambiente concreto.

Con variables podemos separar:

Infraestructura
      +
Configuración


Por ejemplo:

main.tf
    ↓
define cómo funciona la infraestructura

terraform.tfvars
    ↓
define los valores para este ambiente


Esta separación se vuelve especialmente importante cuando trabajamos con infraestructura real.

Las variables pueden tener diferentes tipos.

Por ejemplo:

variable "environment" {
  type = string
}

Una cadena.

También podemos tener números:

variable "instance_count" {
  type = number
}

Booleanos:

variable "enabled" {
  type = bool
}

Y estructuras más interesantes.

Por ejemplo, una lista:

variable "availability_zones" {
  type = list(string)
}

Podemos asignarle:

availability_zones = [
  "us-east-1a",
  "us-east-1b"
]

Más adelante, cuando empecemos a trabajar con configuraciones más complejas, estos tipos van a ser muy importantes.


Hasta ahora vimos cómo introducir información en Terraform mediante variables.

Pero muchas veces queremos hacer lo contrario.

Queremos que Terraform nos muestre información sobre lo que acaba de crear.

Para eso tenemos los outputs.

Por ejemplo:

output "environment" {
  value = var.environment
}

Después de ejecutar:

terraform apply

Terraform puede mostrar:

Outputs:

environment = "development"


Los outputs sirven para exponer información que resulta útil después de crear nuestros recursos.

Los outputs se vuelven mucho más interesantes cuando apuntan a recursos.


Por ejemplo:

resource "local_file" "config" {
  filename = "${var.environment}-config.txt"

  content = "Configuración de ${var.environment}"
}


Podemos definir:

output "config_file" {
  value = local_file.config.filename
}


Ahora Terraform conoce el nombre del archivo creado y podemos mostrarlo como output.


La referencia:

local_file.config.filename


significa:

resource
   │
   └── local_file.config
            │
            └── atributo filename


Esta forma de referenciar recursos es fundamental en Terraform.

Terraform entiende las dependencias

Supongamos que tenemos:

resource "local_file" "config" {
  filename = "${var.environment}-config.txt"
  content  = "Configuración de ${var.environment}"
}

y:

output "config_file" {
  value = local_file.config.filename
}


El output depende del resource.

Terraform puede detectar esa relación.

Podemos imaginarlo así:

local_file.config
        │
        ▼
output.config_file


En configuraciones más grandes tendremos muchos recursos relacionados:


network
   │
   ├── subnet
   │      │
   │      └── virtual machine
   │
   └── database


Terraform construye y utiliza estas dependencias para determinar el orden en el que debe realizar las operaciones.

Veamos un ejemplo completo

Nuestro main.tf puede quedar así:

terraform {
  required_providers {
    local = {
      source = "hashicorp/local"
    }
  }
}

provider "local" {}

variable "environment" {
  type    = string
  default = "development"
}

resource "local_file" "config" {
  filename = "${var.environment}-config.txt"

  content = <<EOF
Environment: ${var.environment}
Application: MyApplication
EOF
}

output "config_file" {
  value = local_file.config.filename
}


Ahora ejecutamos:

terraform init


Después:

terraform plan


Y finalmente:

terraform apply


Terraform crea:

development-config.txt

con:

Environment: development
Application: MyApplication

Y además podemos obtener:

Outputs:

config_file = "development-config.txt"

Tenemos entonces las tres piezas:

                                       Terraform
                                             │
        ┌────────────┼────────────┐
        │                                  │                                  │
        ▼                                ▼                                 ▼
     Variable                     Resource                       Output
        │                                  │                                  │
        │                                  │                                  │
        └────────────┼────────────┘
                                             │
                                            ▼
                                     infraestructura


¿Dónde entra el State?

Hay un concepto que todavía no explicamos en profundidad, pero que ya aparece cuando ejecutamos Terraform:

terraform apply

Terraform necesita saber qué recursos administra y cuál es el estado conocido de esos recursos.

Para eso utiliza el state.

Normalmente, después de ejecutar nuestro ejemplo veremos un archivo:

terraform.tfstate

Este archivo contiene información que Terraform utiliza para relacionar nuestra configuración con los recursos que administra.

Por ahora no necesitamos entrar en todos sus detalles.

Lo importante es entender que Terraform trabaja con tres cosas:

  Configuración
       │
       │
       ▼
   Terraform
       ▲
       │
       │
     State
       │
      ▼
Infraestructura real


La configuración dice lo que queremos.

El state ayuda a Terraform a saber qué está administrando.

Y la infraestructura real es lo que existe efectivamente.

Este concepto merece otro post... 

No hay comentarios.:

Publicar un comentario