Terraform Variables e Locals: Configurazione Dinamica
Le variabili e i locals di Terraform sono elementi fondamentali per creare configurazioni flessibili, riutilizzabili e facilmente gestibili. Scopri come utilizzarli efficacemente per ottimizzare la tua infrastruttura come codice.
Quando si lavora con Terraform, la capacità di creare configurazioni dinamiche e parametrizzate rappresenta la differenza tra un codice rigido e monolitico e un'infrastruttura modulare e scalabile. Le variabili e i locals sono gli strumenti che permettono di raggiungere questo obiettivo, offrendo flessibilità nella gestione dei valori e nella creazione di logiche complesse.
Comprendere le Terraform Variables
Le variabili in Terraform fungono da parametri di input per i moduli e le configurazioni, permettendo di personalizzare il comportamento senza modificare il codice principale. Questo approccio favorisce la riusabilità e semplifica la gestione di ambienti multipli.
Tipi di Variabili Supportate
Terraform supporta diversi tipi di variabili, ciascuno adatto a specifici casi d'uso:
variable "instance_count" {
description = "Numero di istanze da creare"
type = number
default = 1
}
variable "environment" {
description = "Ambiente di deployment"
type = string
default = "development"
}
variable "availability_zones" {
description = "Zone di disponibilità"
type = list(string)
default = ["us-west-2a", "us-west-2b"]
}
variable "tags" {
description = "Tag per le risorse"
type = map(string)
default = {
Project = "MyApp"
Team = "DevOps"
}
}
variable "database_config" {
description = "Configurazione database"
type = object({
engine = string
engine_version = string
instance_class = string
allocated_storage = number
})
}
Definizione e Validazione delle Variabili
Le variabili possono essere arricchite con validazioni personalizzate per garantire che i valori forniti rispettino specifici criteri:
variable "instance_type" {
description = "Tipo di istanza EC2"
type = string
default = "t3.micro"
validation {
condition = contains(["t3.micro", "t3.small", "t3.medium"], var.instance_type)
error_message = "Il tipo di istanza deve essere t3.micro, t3.small o t3.medium."
}
}
variable "cidr_block" {
description = "CIDR block per la VPC"
type = string
validation {
condition = can(cidrhost(var.cidr_block, 0))
error_message = "Il CIDR block deve essere un formato valido (es. 10.0.0.0/16)."
}
}
Variabili Sensibili
Per gestire informazioni sensibili, Terraform offre l'attributo sensitive:
variable "database_password" {
description = "Password del database"
type = string
sensitive = true
}
variable "api_keys" {
description = "Chiavi API"
type = map(string)
sensitive = true
default = {}
}
Metodi di Assegnazione delle Variabili
Terraform offre multiple modalità per assegnare valori alle variabili, seguendo un ordine di precedenza specifico.
File terraform.tfvars
Il metodo più comune per definire i valori delle variabili:
# terraform.tfvars
environment = "production"
instance_count = 3
availability_zones = ["us-west-2a", "us-west-2b", "us-west-2c"]
database_config = {
engine = "mysql"
engine_version = "8.0"
instance_class = "db.t3.medium"
allocated_storage = 100
}
tags = {
Project = "WebApp"
Team = "Backend"
Environment = "production"
}
Variabili d'Ambiente
Per valori dinamici o sensibili, è possibile utilizzare variabili d'ambiente:
# Esportazione variabili d'ambiente
export TF_VAR_database_password="super_secret_password"
export TF_VAR_api_key="my-api-key-123"
export TF_VAR_environment="staging"
Passaggio via Command Line
Per override rapidi durante l'esecuzione:
terraform apply -var="instance_count=5" -var="environment=testing"
Locals: Valori Calcolati e Derivati
I locals permettono di definire valori calcolati che possono essere riutilizzati in tutta la configurazione, riducendo la duplicazione e migliorando la leggibilità.
Definizione dei Locals
locals {
# Concatenazione di stringhe
name_prefix = "${var.environment}-${var.project_name}"
# Logica condizionale
instance_type = var.environment == "production" ? "t3.large" : "t3.micro"
# Manipolazione di liste
private_subnets = [for i, az in var.availability_zones : cidrsubnet(var.vpc_cidr, 8, i)]
public_subnets = [for i, az in var.availability_zones : cidrsubnet(var.vpc_cidr, 8, i + 10)]
# Tag comuni
common_tags = merge(var.tags, {
Environment = var.environment
ManagedBy = "terraform"
CreatedAt = timestamp()
})
# Configurazioni complesse
database_settings = {
backup_retention = var.environment == "production" ? 30 : 7
multi_az = var.environment == "production" ? true : false
storage_encrypted = true
}
}
Locals Avanzati con Funzioni
I locals possono utilizzare le funzioni built-in di Terraform per elaborazioni complesse:
locals {
# Filtraggio e trasformazione
production_subnets = [
for subnet in var.subnets : subnet
if subnet.environment == "production"
]
# Grouping per region
instances_by_region = {
for instance in var.instances : instance.region => instance...
}
# Calcoli matematici
total_storage = sum([for db in var.databases : db.storage_size])
# Validazioni condizionali
valid_config = length(var.availability_zones) >= 2 && var.instance_count > 0
# Manipolazione JSON
config_json = jsonencode({
environment = var.environment
services = var.services
timestamp = timestamp()
})
}
Pattern e Best Practices
Organizzazione delle Variabili
Una struttura ben organizzata facilita la manutenzione e la comprensione:
# variables.tf
# ========================================
# CONFIGURAZIONE GENERALE
# ========================================
variable "project_name" {
description = "Nome del progetto"
type = string
}
variable "environment" {
description = "Ambiente (dev, staging, prod)"
type = string
validation {
condition = contains(["dev", "staging", "prod"], var.environment)
error_message = "Environment deve essere dev, staging o prod."
}
}
# ========================================
# CONFIGURAZIONE RETE
# ========================================
variable "vpc_cidr" {
description = "CIDR block per la VPC"
type = string
default = "10.0.0.0/16"
}
variable "availability_zones" {
description = "Zone di disponibilità"
type = list(string)
}
# ========================================
# CONFIGURAZIONE COMPUTE
# ========================================
variable "instance_configs" {
description = "Configurazioni delle istanze"
type = map(object({
instance_type = string
min_size = number
max_size = number
desired_size = number
}))
}
Utilizzo Combinato di Variables e Locals
Un esempio pratico di come combinare variabili e locals per una configurazione flessibile:
# main.tf
locals {
# Configurazione ambiente-specifica
env_config = {
dev = {
instance_type = "t3.micro"
min_size = 1
max_size = 2
db_instance = "db.t3.micro"
}
staging = {
instance_type = "t3.small"
min_size = 1
max_size = 3
db_instance = "db.t3.small"
}
prod = {
instance_type = "t3.medium"
min_size = 2
max_size = 10
db_instance = "db.r5.large"
}
}
# Configurazione selezionata
selected_config = local.env_config[var.environment]
# Naming convention
resource_prefix = "${var.project_name}-${var.environment}"
# Tag standardizzati
standard_tags = {
Project = var.project_name
Environment = var.environment
ManagedBy = "terraform"
Team = var.team_name
}
}
# Utilizzo nelle risorse
resource "aws_launch_template" "app" {
name_prefix = "${local.resource_prefix}-app-"
image_id = var.ami_id
instance_type = local.selected_config.instance_type
tag_specifications {
resource_type = "instance"
tags = merge(local.standard_tags, {
Name = "${local.resource_prefix}-app-instance"
Type = "application"
})
}
}
Gestione Avanzata delle Configurazioni
Configurazioni Multi-Ambiente
Per gestire efficacemente più ambienti, è possibile strutturare le variabili in modo gerarchico:
# environments/prod.tfvars
environment = "prod"
instance_count = 5
database_config = {
instance_class = "db.r5.xlarge"
allocated_storage = 1000
backup_retention = 30
multi_az = true
}
monitoring = {
detailed_monitoring = true
log_retention_days = 90
alerts_enabled = true
}
# environments/dev.tfvars
environment = "dev"
instance_count = 1
database_config = {
instance_class = "db.t3.micro"
allocated_storage = 20
backup_retention = 1
multi_az = false
}
monitoring = {
detailed_monitoring = false
log_retention_days = 7
alerts_enabled = false
}
Validazione e Controlli di Coerenza
Implementare controlli per garantire configurazioni valide:
locals {
# Validazioni
validation_errors = [
for error in [
length(var.availability_zones) < 2 ? "Almeno 2 AZ richieste" : null,
var.instance_count > 10 && var.environment != "prod" ? "Max 10 istanze per non-prod" : null,
var.database_config.allocated_storage < 20 ? "Storage minimo 20GB" : null
] : error if error != null
]
# Stop execution if validation fails
validated_config = length(local.validation_errors) > 0 ? tobool("Errori di validazione: ${join(", ", local.validation_errors)}") : true
}
Debugging e Troubleshooting
Per debugging delle configurazioni complesse, utilizzare output per visualizzare i valori calcolati:
output "debug_info" {
description = "Informazioni di debug"
value = {
environment = var.environment
selected_config = local.selected_config
calculated_tags = local.standard_tags
subnet_cidrs = local.private_subnets
validation_status = local.validation_errors
}
}
# Utilizzo di terraform console per testing
# terraform console
# > local.selected_config
# > var.environment
# > local.standard_tags
Conclusioni
L'utilizzo efficace delle terraform variables e dei locals è fondamentale per creare infrastrutture robuste e maintainabili. Le variabili forniscono la flessibilità necessaria per parametrizzare le configurazioni, mentre i locals permettono di implementare logiche complesse e calcoli derivati.
La chiave del successo risiede nell'organizzazione strutturata del codice, nell'implementazione di validazioni appropriate e nell'adozione di naming convention coerenti. Questi elementi, combinati con pattern di configurazione multi-ambiente, permettono di gestire infrastrutture complesse mantenendo la chiarezza e la riusabilità del codice.
Ricorda che una configurazione ben progettata oggi semplificherà significativamente la manutenzione e l'evoluzione della tua infrastruttura domani. Investire tempo nella progettazione di variabili e locals efficaci è sempre un investimento che ripaga nel lungo termine.