Terraform 32: 5: Manteniendo los entornos DRY con módulos compartidos
easy⏱ 5 mincourseterraform
Los recursos viven en un módulo compartido
Mové los recursos a modules/service/ una vez. El directorio de cada entorno se vuelve un llamador delgado que pasa environment, location, sizing, etc. Arreglás un bug en el módulo y cada entorno hereda el arreglo en su próximo apply — sin copy-paste.
# modules/service/main.tf — the reusable definition
variable "environment" { type = string }
variable "service" { type = string }
variable "vm_count" { type = number }
resource "azurerm_resource_group" "this" {
name = "${var.environment}-${var.service}-rg"
location = var.location
tags = { environment = var.environment, managed_by = "terraform" }
}
Los entornos solo llaman al módulo
El main.tf de cada entorno es un bloque module con entradas específicas del entorno. Lo único que difiere entre envs/dev y envs/prod son los valores de tfvars y la clave del backend — la lógica del recurso es compartida.
# envs/prod/main.tf — a thin caller
module "orders" {
source = "../../modules/service"
environment = var.environment # "prod"
service = "orders"
location = var.location
vm_count = var.vm_count # 3 in prod, 1 in dev
}
for_each sobre un mapa para replicar muchas copias
Dentro del módulo, manejá los recursos repetidos desde un mapa con for_each. Una entrada de mapa por instancia; each.key lo nombra y each.value lo configura. Agregar un servicio es editar una línea del mapa, no copiar y pegar un bloque de recurso.
variable "buckets" {
type = map(object({ tier = string }))
# { logs = { tier = "Cool" }, uploads = { tier = "Hot" } }
}
resource "azurerm_storage_container" "this" {
for_each = var.buckets
name = "${var.environment}-${each.key}" # dev-logs, dev-uploads
storage_account_name = azurerm_storage_account.this.name
container_access_type = "private"
}
Calculá los nombres del for_each
Dado env y un mapa buckets, escribí containerNames(env, buckets) que devuelva el array ordenado de nombres "{env}-{key}" que Terraform crearía. Logueá containerNames("dev", { logs: {}, uploads: {} }) — se espera ["dev-logs", "dev-uploads"].