Sintaxis del bloque module
El bloque module es la forma de invocar un módulo secundario desde el módulo raíz (o desde otro módulo secundario). Su sintaxis básica es:
module "<nombre_local>" {
source = "<fuente_del_modulo>"
# Variables de entrada del módulo
variable_1 = valor_1
variable_2 = valor_2
}Cada parte tiene un significado preciso:
<nombre_local>: identificador único para esta instancia del módulo. Puedes usar el mismo módulo varias veces con distintos nombres locales. Se usa para referenciar los outputs:module.<nombre_local>.<output>.source: indica dónde está el módulo. Es el único argumento obligatorio.- Variables: el resto de argumentos corresponden a las variables declaradas en el
variables.tfdel módulo. Si una variable no tienedefault, es obligatorio proporcionarla aquí.
Argumentos especiales del bloque module
Además de las variables del módulo, existen argumentos especiales que controla Terraform, no el módulo:
module "mi_instancia" {
source = "terraform-aws-modules/ec2-instance/aws"
version = "~> 5.0"
# Variables del módulo
name = "mi-servidor"
instance_type = "t3.micro"
# --- Argumentos especiales de Terraform ---
# count: crea múltiples instancias del módulo (como con recursos)
count = 3
# for_each: crea una instancia por cada elemento del mapa o set
# (no se puede usar count y for_each simultáneamente)
# for_each = { dev = "t3.micro", prod = "t3.large" }
# depends_on: dependencias explícitas con otros recursos o módulos
depends_on = [module.red]
# providers: especifica qué configuración de provider usar (avanzado)
# providers = {
# aws = aws.eu_west_1
# }
}Fuentes de módulos: local, Terraform Registry, GitHub y S3
El argumento source acepta distintos formatos según dónde esté el módulo. Terraform identifica el tipo de fuente automáticamente por el formato del string.
Fuente local
La más sencilla: el módulo vive en el mismo sistema de archivos. La ruta es relativa al archivo que hace la llamada:
# Módulo en un subdirectorio
module "red" {
source = "./modules/networking"
}
# Módulo en el directorio padre
module "compartido" {
source = "../modules/comun"
}
# Módulo varios niveles arriba
module "corporativo" {
source = "../../infraestructura-base/modules/seguridad"
}Importante: las rutas locales siempre empiezan con ./ o ../. Sin esa barra inicial, Terraform interpreta la ruta como un módulo del registry.
Terraform Registry
El formato para el registry público es <namespace>/<nombre>/<provider>:
module "vpc" {
source = "terraform-aws-modules/vpc/aws"
version = "~> 5.0"
name = "mi-vpc"
cidr = "10.0.0.0/16"
azs = ["eu-west-1a", "eu-west-1b", "eu-west-1c"]
private_subnets = ["10.0.1.0/24", "10.0.2.0/24", "10.0.3.0/24"]
public_subnets = ["10.0.101.0/24", "10.0.102.0/24", "10.0.103.0/24"]
}GitHub
Puedes referenciar directamente repositorios GitHub. El doble slash // separa el repositorio del subdirectorio:
# Todo el repositorio como módulo
module "ejemplo" {
source = "github.com/hashicorp/example"
}
# Subdirectorio específico dentro del repositorio
module "s3_bucket" {
source = "github.com/terraform-aws-modules/terraform-aws-s3-bucket//modules/object"
}
# Con referencia a una rama, tag o commit específico
module "s3_bucket_v3" {
source = "github.com/terraform-aws-modules/terraform-aws-s3-bucket//modules/object?ref=v3.15.1"
}Repositorios Git genéricos
Para repositorios en otros servidores Git (GitLab, Bitbucket, servidores privados):
# HTTPS (repositorio público o con autenticación via .netrc)
module "interno" {
source = "git::https://gitlab.empresa.com/infra/terraform-modules.git//vpc?ref=v2.0.0"
}
# SSH (requiere clave SSH configurada)
module "privado" {
source = "git::ssh://[email protected]/infra/terraform-modules.git//networking?ref=main"
}Amazon S3
Para módulos almacenados en buckets S3:
module "desde_s3" {
source = "s3::https://s3-eu-west-1.amazonaws.com/mi-bucket-terraform/modulos/servidor-v1.2.0.zip"
}Google Cloud Storage
module "desde_gcs" {
source = "gcs::https://www.googleapis.com/storage/v1/mi-bucket/modulos/networking.zip"
}El argumento source y sus formatos
Tabla resumen de todos los formatos de source:
| Tipo de fuente | Formato | Requiere version |
Autenticación |
|---|---|---|---|
| Local | ./ruta/al/modulo |
No | No |
| Terraform Registry (público) | namespace/nombre/provider |
Recomendado | No |
| Terraform Registry (privado) | app.terraform.io/org/nombre/provider |
Recomendado | Token TF Cloud |
| GitHub HTTPS | github.com/org/repo//subdir?ref=tag |
Via ?ref= |
Token (repo privado) |
| GitHub SSH | git::ssh://[email protected]/org/repo.git//subdir?ref=tag |
Via ?ref= |
Clave SSH |
| GitLab HTTPS | git::https://gitlab.com/org/repo.git//subdir?ref=tag |
Via ?ref= |
Token |
| Git genérico | git::https://servidor.com/repo.git?ref=tag |
Via ?ref= |
Variable |
| S3 | s3::https://s3-region.amazonaws.com/bucket/archivo.zip |
Via nombre | IAM |
| GCS | gcs::https://www.googleapis.com/storage/v1/bucket/archivo.zip |
Via nombre | SA |
| HTTP/HTTPS | https://example.com/modulo.zip |
Via URL | Variable |
Pasar variables a un módulo
Al invocar un módulo, los argumentos del bloque module (excepto los especiales como source, version, count, for_each, depends_on, providers) se mapean directamente a las variables declaradas en variables.tf del módulo:
# Si el módulo tiene en variables.tf:
# variable "nombre" { type = string }
# variable "instancias" { type = number, default = 1 }
# variable "etiquetas" { type = map(string), default = {} }
module "mi_servidor" {
source = "./modules/servidor"
# Pasamos valores para las variables del módulo
nombre = "servidor-web" # string
instancias = 3 # number
etiquetas = { # map(string)
Entorno = "produccion"
Proyecto = "tienda-online"
Equipo = "backend"
}
# 'instancias' y 'etiquetas' tienen default, así que son opcionales
}Pasar expressions como valores de variables
Los valores de las variables no tienen que ser literales: pueden ser cualquier expresión de Terraform, incluyendo referencias a otros recursos, outputs de otros módulos o variables del módulo raíz:
variable "entorno" {
type = string
default = "dev"
}
module "base_datos" {
source = "./modules/database"
# Usando una variable del módulo raíz
entorno = var.entorno
# Usando el output de otro módulo
subnet_ids = module.red.private_subnet_ids
# Usando una función de Terraform
nombre_bd = "${var.entorno}-db-${formatdate("YYYYMMDD", timestamp())}"
# Expresión condicional
multi_az = var.entorno == "production" ? true : false
}Acceder a outputs de un módulo
Para usar los valores que un módulo expone (sus outputs), se usa la sintaxis:
module "red" {
source = "./modules/networking"
cidr_block = "10.0.0.0/16"
}
module "compute" {
source = "./modules/compute"
# Usamos el output 'subnet_id' del módulo 'red'
subnet_id = module.red.subnet_id
vpc_id = module.red.vpc_id
}
# Podemos usar los outputs en el módulo raíz también
output "ip_servidor" {
description = "IP pública del servidor creado"
value = module.compute.ip_publica
}
output "url_aplicacion" {
description = "URL de acceso a la aplicación"
value = "https://${module.compute.ip_publica}"
}Acceder a outputs de módulos con count o for_each
Cuando usas count o for_each en un módulo, accedes a los outputs de cada instancia mediante índice o clave:
# Con count: se crea una lista de módulos
module "servidor" {
source = "./modules/servidor"
count = 3
nombre = "servidor-${count.index}"
}
# Acceder al output de una instancia específica
output "ip_primer_servidor" {
value = module.servidor[0].ip_publica
}
# Acceder a todos los outputs como lista
output "todas_las_ips" {
value = module.servidor[*].ip_publica
}# Con for_each: se crea un mapa de módulos
module "servidor" {
source = "./modules/servidor"
for_each = toset(["web", "api", "worker"])
nombre = each.key
}
# Acceder al output de una instancia específica
output "ip_servidor_web" {
value = module.servidor["web"].ip_publica
}
# Acceder a todos los outputs como mapa
output "todas_las_ips" {
value = { for k, v in module.servidor : k => v.ip_publica }
}El argumento version en módulos del registry
Cuando usas módulos del Terraform Registry, siempre debes especificar version. Sin él, Terraform usará la versión más reciente disponible, lo que puede causar cambios inesperados en tu infraestructura:
module "vpc" {
source = "terraform-aws-modules/vpc/aws"
version = "5.1.2" # Versión exacta: muy restrictivo
}
module "ec2" {
source = "terraform-aws-modules/ec2-instance/aws"
version = "~> 5.0" # >= 5.0, < 6.0: acepta parches y menores
}
module "rds" {
source = "terraform-aws-modules/rds/aws"
version = ">= 6.0, < 7.0" # Rango explícito
}
module "s3" {
source = "terraform-aws-modules/s3-bucket/aws"
version = "!= 3.5.0" # Cualquier versión excepto la 3.5.0 (tiene un bug)
}Operadores de versión
| Operador | Significado | Ejemplo | Acepta |
|---|---|---|---|
= o sin operador |
Versión exacta | "= 5.1.2" |
Solo 5.1.2 |
!= |
Excluir versión | "!= 5.1.2" |
Todo excepto 5.1.2 |
> |
Mayor que | "> 5.0" |
5.0.1, 5.1.0, 6.0.0... |
>= |
Mayor o igual | ">= 5.0" |
5.0.0, 5.1.0, 6.0.0... |
< |
Menor que | "< 6.0" |
5.x.x pero no 6.0.0 |
<= |
Menor o igual | "<= 5.9.9" |
Hasta 5.9.9 |
~> |
Pessimistic constraint | "~> 5.1" |
>= 5.1, < 6.0 |
~> (parche) |
Pessimistic constraint | "~> 5.1.0" |
>= 5.1.0, < 5.2.0 |
El operador ~> (tilde-mayor) es el más usado: permite actualizaciones de parches y menores pero bloquea cambios mayores.
Módulos anidados (nested modules)
Un módulo puede invocar a otros módulos, creando una jerarquía. Esto permite componer módulos complejos a partir de módulos simples:
root/
├── main.tf ← módulo raíz
└── modules/
├── aplicacion-completa/ ← módulo de nivel 1
│ ├── main.tf ← llama a los módulos de nivel 2
│ ├── variables.tf
│ ├── outputs.tf
│ └── (no tiene submódulos propios aquí)
├── red/ ← módulo de nivel 2
│ ├── main.tf
│ ├── variables.tf
│ └── outputs.tf
└── servidor/ ← módulo de nivel 2
├── main.tf
├── variables.tf
└── outputs.tf# modules/aplicacion-completa/main.tf
# Este módulo "orquesta" otros módulos
module "red_interna" {
source = "../red" # ruta relativa desde este módulo
cidr_block = var.cidr_red
nombre = "${var.nombre_app}-red"
}
module "servidor_web" {
source = "../servidor"
nombre = "${var.nombre_app}-web"
subnet_id = module.red_interna.subnet_id # output del módulo de red
}Advertencia: evita anidar módulos más de 2-3 niveles. La profundidad excesiva hace que los errores sean difíciles de rastrear y que las referencias de outputs se vuelvan complicadas.
terraform get y terraform init con módulos
Cuando añades o modificas módulos, Terraform necesita descargados o localizarlos antes de poder crear el plan:
terraform init
Es el comando principal para inicializar un directorio de trabajo. Hace múltiples cosas:
# Inicialización completa: descarga providers Y módulos
terraform init
# Salida típica cuando hay módulos:
# Initializing modules...
# - red in modules/networking
# - compute in modules/compute
# Downloading terraform-aws-modules/vpc/aws 5.1.2 for vpc...
# - vpc in .terraform/modules/vpc
#
# Initializing provider plugins...
# ...terraform get
Solo descarga módulos (no toca los providers). Útil cuando solo has añadido o cambiado módulos:
# Descarga los módulos referenciados
terraform get
# Actualiza los módulos ya descargados a sus versiones más recientes
# (respetando las restricciones de version)
terraform get -update¿Cuándo usar cada uno?
| Situación | Comando recomendado |
|---|---|
| Primera vez en el proyecto | terraform init |
| Añadiste un nuevo módulo | terraform init o terraform get |
Cambiaste el source de un módulo |
terraform init |
| Quieres actualizar módulos del registry | terraform get -update |
| Añadiste un nuevo provider | terraform init |
| Cambiaste restricciones de versión de módulo | terraform get -update |
Actualizar módulos: terraform get -update
Cuando quieres actualizar los módulos del registry a versiones más recientes (dentro de los rangos permitidos):
# Ver versiones actuales descargadas
cat .terraform/modules/modules.json
# Actualizar módulos a la versión más reciente permitida
terraform get -update
# Tras actualizar, verificar el plan para ver qué cambia
terraform planEl archivo .terraform/modules/modules.json registra qué versión de cada módulo está descargada:
{
"Modules": [
{
"Key": "vpc",
"Source": "registry.terraform.io/terraform-aws-modules/vpc/aws",
"Version": "5.1.2",
"Dir": ".terraform/modules/vpc"
}
]
}Ejemplos completos de uso de módulos locales y del registry
Ejemplo 1: Usando módulos locales encadenados
# main.tf — módulo raíz que orquesta la infraestructura completa
terraform {
required_version = ">= 1.0"
required_providers {
local = {
source = "hashicorp/local"
version = "~> 2.0"
}
}
}
# Módulo de "base de datos" (conceptual con archivos locales)
module "base_datos_dev" {
source = "./modules/configuracion-app"
nombre_aplicacion = "postgresql"
directorio_destino = "/tmp/configs/dev/db"
configuracion_servidor = {
host = "localhost"
puerto = 5432
workers = 4
}
entorno = "development"
}
# Módulo de "API" que depende de la base de datos
module "api_dev" {
source = "./modules/configuracion-app"
nombre_aplicacion = "mi-api"
directorio_destino = "/tmp/configs/dev/api"
configuracion_servidor = {
host = "localhost"
puerto = 3000
workers = 2
}
entorno = "development"
# Dependencia explícita: la API se configura después de la BD
depends_on = [module.base_datos_dev]
}
# Outputs del módulo raíz
output "archivos_creados" {
value = {
base_datos = module.base_datos_dev.resumen
api = module.api_dev.resumen
}
}Ejemplo 2: Usando módulos del Terraform Registry (AWS)
# Nota: Este ejemplo requiere credenciales AWS configuradas.
# Lo incluimos como referencia de sintaxis real.
terraform {
required_version = ">= 1.0"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}
provider "aws" {
region = "eu-west-1"
}
# -----------------------------------------------
# Módulo de VPC del registry oficial
# Documentación: registry.terraform.io/modules/terraform-aws-modules/vpc/aws
# -----------------------------------------------
module "vpc" {
source = "terraform-aws-modules/vpc/aws"
version = "~> 5.0"
name = "mi-proyecto-vpc"
cidr = "10.0.0.0/16"
# Zonas de disponibilidad donde crear subredes
azs = ["eu-west-1a", "eu-west-1b", "eu-west-1c"]
# Subredes privadas (sin acceso directo a internet)
private_subnets = ["10.0.1.0/24", "10.0.2.0/24", "10.0.3.0/24"]
# Subredes públicas (con acceso a internet via IGW)
public_subnets = ["10.0.101.0/24", "10.0.102.0/24", "10.0.103.0/24"]
# Crear NAT Gateway para que las subredes privadas puedan acceder a internet
enable_nat_gateway = true
# Un solo NAT gateway para ahorrar costes (en producción usa uno por AZ)
single_nat_gateway = true
# Etiquetas aplicadas a todos los recursos del módulo
tags = {
Proyecto = "mi-proyecto"
Entorno = "produccion"
GestionPor = "terraform"
}
}
# -----------------------------------------------
# Módulo de instancia EC2 del registry oficial
# -----------------------------------------------
module "servidor_web" {
source = "terraform-aws-modules/ec2-instance/aws"
version = "~> 5.0"
name = "servidor-web"
# AMI de Amazon Linux 2023 (ejemplo, el ID varía por región)
ami = "ami-0c55b159cbfafe1f0"
instance_type = "t3.micro"
# Usamos el output del módulo VPC para colocar el servidor en la subred correcta
subnet_id = module.vpc.public_subnets[0]
vpc_security_group_ids = [aws_security_group.web.id]
# Asignación de IP pública (necesario en subred pública)
associate_public_ip_address = true
tags = {
Proyecto = "mi-proyecto"
Rol = "web-server"
}
}
# Grupo de seguridad (definido directamente, no como módulo)
resource "aws_security_group" "web" {
name = "sg-web"
vpc_id = module.vpc.vpc_id # Output del módulo VPC
ingress {
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
}
# Outputs del módulo raíz
output "vpc_id" {
value = module.vpc.vpc_id
}
output "ip_servidor" {
value = module.servidor_web.public_ip
}Ejercicio: Usar el módulo creado en el tema anterior y el módulo oficial de AWS VPC
Contexto: Tienes el módulo gestion-proyecto creado en el tema 04-02. Ahora debes:
- Crear un módulo raíz que use
gestion-proyectopara tres proyectos diferentes. - Usar
for_eachpara crear los tres proyectos con una sola llamada al módulo. - Exponer un output que liste todos los directorios creados como un mapa.
Datos de los proyectos:
portal-clientes: "Portal web para gestión de clientes", versión "3.1.0", autor "Equipo Frontend"api-pagos: "API de procesamiento de pagos", versión "2.0.5", autor "Equipo Backend"worker-emails: "Worker asíncrono para envío de emails", versión "1.2.0", autor "Equipo Plataforma"
Solución detallada
# main.tf
terraform {
required_version = ">= 1.0"
required_providers {
local = {
source = "hashicorp/local"
version = "~> 2.0"
}
}
}
# Definimos los proyectos como un mapa de objetos.
# Esto nos permite usar for_each para crear todos los proyectos con una sola
# llamada al módulo.
locals {
proyectos = {
"portal-clientes" = {
descripcion = "Portal web para gestión de clientes"
version = "3.1.0"
autor = "Equipo Frontend"
caracteristicas = ["autenticacion-sso", "dashboard-analiticas", "exportacion-csv"]
}
"api-pagos" = {
descripcion = "API de procesamiento de pagos"
version = "2.0.5"
autor = "Equipo Backend"
caracteristicas = ["stripe-integration", "webhooks", "idempotencia"]
}
"worker-emails" = {
descripcion = "Worker asíncrono para envío de emails"
version = "1.2.0"
autor = "Equipo Plataforma"
caracteristicas = ["plantillas-html", "cola-reintentos", "tracking"]
}
}
}
# for_each en el bloque module: crea una instancia del módulo por cada proyecto.
# each.key es la clave del mapa (nombre del proyecto).
# each.value es el objeto con los datos del proyecto.
module "proyectos" {
source = "./modules/gestion-proyecto"
for_each = local.proyectos
# each.key contiene el nombre del proyecto (clave del mapa)
nombre_proyecto = each.key
# each.value contiene el objeto con los demás datos
descripcion = each.value.descripcion
version = each.value.version
autor = each.value.autor
caracteristicas = each.value.caracteristicas
}
# Output: mapa de nombre_proyecto => directorio_base
# La expresión for transforma el mapa de módulos en un nuevo mapa.
output "directorios_proyectos" {
description = "Mapa de proyectos a sus directorios base creados."
value = {
# k es el nombre del proyecto (each.key), v es la instancia del módulo
for k, v in module.proyectos : k => v.directorio_base
}
}
# Output: lista de todos los archivos README creados
output "todos_los_readme" {
description = "Lista de rutas de todos los README.md creados."
value = [
for k, v in module.proyectos : v.ruta_readme
]
}
# Output: mapa completo con todos los detalles
output "resumen_completo" {
description = "Información completa de todos los proyectos creados."
value = {
for k, v in module.proyectos : k => {
directorio = v.directorio_base
readme = v.ruta_readme
configuracion = v.ruta_configuracion
}
}
}Para ejecutar y verificar:
# 1. Inicializar el proyecto
terraform init
# 2. Ver el plan: qué recursos se crearán
terraform plan
# Salida esperada del plan:
# Plan: 9 to add, 0 to change, 0 to destroy.
# (3 proyectos × 3 archivos cada uno = 9 archivos)
# 3. Aplicar los cambios
terraform apply -auto-approve
# 4. Ver los outputs
terraform output directorios_proyectos
# {
# "api-pagos" = "/tmp/proyectos/api-pagos"
# "portal-clientes" = "/tmp/proyectos/portal-clientes"
# "worker-emails" = "/tmp/proyectos/worker-emails"
# }
terraform output todos_los_readme
# tolist([
# "/tmp/proyectos/api-pagos/README.md",
# "/tmp/proyectos/portal-clientes/README.md",
# "/tmp/proyectos/worker-emails/README.md",
# ])
# 5. Verificar los archivos creados
ls /tmp/proyectos/
# api-pagos portal-clientes worker-emails
cat /tmp/proyectos/portal-clientes/README.md
# 6. Limpiar recursos cuando termines
terraform destroy -auto-approveCómo referenciar una instancia específica con for_each
# Si necesitas el directorio de un proyecto específico:
output "directorio_api_pagos" {
value = module.proyectos["api-pagos"].directorio_base
}
# Si necesitas verificar que una clave existe antes de usarla:
output "directorio_condicional" {
value = contains(keys(module.proyectos), "api-pagos") ? module.proyectos["api-pagos"].directorio_base : "no existe"
}Errores comunes al usar módulos
Error 1: Olvidar terraform init tras añadir un módulo
Error: Module not installed
on main.tf line 5:
5: module "vpc" {
This module is not yet installed. Run "terraform init" to install all modules
required by this configuration.Solución: terraform init siempre antes de terraform plan o terraform apply cuando hay módulos nuevos.
Error 2: Usar source sin ./ para módulos locales
# INCORRECTO: Terraform busca "modules/networking" en el registry público
module "red" {
source = "modules/networking" # ← falta ./
}
# CORRECTO
module "red" {
source = "./modules/networking"
}Error 3: No especificar version en módulos del registry
# PELIGROSO: sin version, usará siempre la última disponible
module "vpc" {
source = "terraform-aws-modules/vpc/aws"
# Si publican la versión 6.0 con breaking changes, tu infra se romperá
}
# CORRECTO
module "vpc" {
source = "terraform-aws-modules/vpc/aws"
version = "~> 5.0"
}Error 4: Intentar acceder a un output que no existe en el módulo
Error: Unsupported attribute on main.tf line 25, in output "mi_output": 25: value = module.servidor.ip_privada This object does not have an attribute named "ip_privada".
Solución: Verifica que el output ip_privada está declarado en el outputs.tf del módulo servidor.
Error 5: Cambiar count o for_each de un módulo existente
Si tu módulo tenía count = 2 y lo cambias a count = 3, Terraform entiende que los recursos existentes son module.servidor[0] y module.servidor[1], y el nuevo es module.servidor[2]. Esto es correcto.
Pero si cambias de count a for_each, o viceversa, Terraform lo trata como destrucción y recreación de todos los recursos del módulo:
# Cambiar de esto:
module "servidor" {
count = 2
...
}
# A esto:
module "servidor" {
for_each = toset(["web", "api"])
...
}
# RESULTADO: Terraform destruye module.servidor[0], module.servidor[1]
# y crea module.servidor["web"], module.servidor["api"]
# ¡Puede causar downtime!Solución: Planifica con antelación si usarás count o for_each. Usa terraform state mv si necesitas migrar sin recrear.
Error 6: Módulos anidados con rutas source incorrectas
Cuando un módulo anidado llama a otro módulo, la ruta source es relativa al módulo que hace la llamada, no al módulo raíz:
root/
├── main.tf
└── modules/
├── orquestador/
│ └── main.tf ← llama a ../networking
└── networking/
└── main.tf# modules/orquestador/main.tf
module "red" {
source = "../networking" # Correcto: relativo a modules/orquestador/
# NO: source = "./modules/networking" (sería relativo al root)
}Resumen
En esta lección has aprendido todo lo necesario para usar módulos de Terraform de forma efectiva:
- La sintaxis del bloque
moduley sus argumentos especiales (count,for_each,depends_on). - Los distintos formatos de
source: local, Terraform Registry, GitHub, Git genérico, S3. - Cómo pasar variables a un módulo y cómo usar expresiones como valores.
- Cómo acceder a outputs de un módulo con
module.<nombre>.<output>, y cómo hacerlo con módulos instanciados concountofor_each. - La importancia de especificar
versionen módulos del registry y los operadores disponibles. - Cuándo usar
terraform initvsterraform getpara gestionar módulos. - Los errores más comunes y cómo evitarlos.
En el siguiente tema explorarás el Terraform Registry: cómo buscar y evaluar módulos públicos, cómo publicar tus propios módulos y cómo trabajar con módulos privados en Terraform Cloud.
Curso de Terraform
Módulo 1: Introducción a Terraform
- ¿Qué es Terraform?
- Instalando Terraform
- Conceptos Básicos de Terraform
- Primera Configuración de Terraform
Módulo 2: Lenguaje de Configuración de Terraform
Módulo 3: Gestión del Estado
Módulo 4: Módulos de Terraform
Módulo 5: Aprovisionamiento de Recursos
- Conceptos Básicos de Aprovisionamiento
- Aprovisionamiento de Recursos AWS
- Aprovisionamiento de Recursos Azure
- Aprovisionamiento de Recursos GCP
Módulo 6: Funcionalidades Avanzadas de Terraform
Módulo 7: Mejores Prácticas de Terraform
- Organización del Código
- Control de Versiones
- Pruebas del Código de Terraform
- Mejores Prácticas de Seguridad
Módulo 8: Terraform en CI/CD
- Integración de Terraform con CI/CD
- Automatización de Terraform con Jenkins
- Uso de Terraform con GitHub Actions
- Terraform Cloud y Enterprise
