Cheatsheet Terraform
Infraestrutura como código para provisionar cloud e serviços
Terraform
CLI
Inicializar
terraform init
terraform init -upgrade
terraform init -backend=false
Inicializar el directorio y los providers.
Output e inspección
terraform output
terraform output public_ip
terraform show
terraform state list
Ver los outputs y el estado actual.
Plan y Apply
terraform plan
terraform plan -out=plan.tfplan
terraform apply
terraform apply plan.tfplan
terraform apply -auto-approve
Prever y aplicar cambios.
Destruir
terraform destroy
terraform destroy -target=aws_instance.web
terraform destroy -auto-approve
Eliminar toda la infraestructura.
Formateo y validación
terraform fmt
terraform fmt -check
terraform validate
terraform plan -detailed-exitcode
Formatear y validar código.
HCL e Blocos
Estructura de archivos
main.tf # recursos principales
variables.tf # variables de input
outputs.tf # outputs
providers.tf # configuración de providers
terraform.tfvars # valores
modules/ # módulos reutilizables
Organización del proyecto.
Tipos de datos
string = "texto"
number = 42
bool = true
list = ["a", "b", "c"]
map = { key = "value" }
object = { name = "x", port = 80 }
tuple = [1, "dos", true]
Tipos disponibles en HCL.
Expresiones
var.name
local.config
resource.type.name.attribute
data.type.name.attribute
module.name.output
terraform.workspace
Referencias a valores.
Bloques dinámicos
dynamic "ingress" {
for_each = var.ports
content {
from_port = ingress.value
to_port = ingress.value
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
}Generar bloques repetidos.
Resources
Definir un recurso
resource "aws_instance" "web" {
ami = "ami-12345"
instance_type = "t3.micro"
tags = {
Name = "Web Server"
}
}Crear un recurso de infraestructura.
Lifecycle
resource "aws_instance" "web" {
# ...
lifecycle {
create_before_destroy = true
prevent_destroy = true
ignore_changes = [tags]
}
}Controlar el ciclo de vida.
Data sources
data "aws_ami" "ubuntu" {
most_recent = true
owners = ["099720109477"]
filter {
name = "name"
values = ["ubuntu-*-22.04-*"]
}
}Leer datos existentes.
Dependencias
resource "aws_instance" "app" {
# dependencia implícita
subnet_id = aws_subnet.main.id
# dependencia explícita
depends_on = [aws_iam_role.app]
}Orden de creación.
for_each y count
resource "aws_instance" "servers" {
for_each = toset(["web", "api", "db"])
instance_type = "t3.micro"
tags = { Name = each.value }
}
resource "aws_subnet" "sub" {
count = 3
cidr_block = "10.0.${count.index}.0/24"
}Crear múltiples instancias.
Variáveis e Outputs
Definir variables
variable "instance_type" {
description = "Tipo de instancia"
type = string
default = "t3.micro"
}
variable "ports" {
type = list(number)
default = [80, 443]
}Inputs del módulo/proyecto.
Validation
variable "env" {
type = string
validation {
condition = contains(
["dev", "staging", "prod"],
var.env)
error_message = "Env inválido."
}
}Validar inputs.
Outputs
output "public_ip" {
description = "IP del servidor"
value = aws_instance.web.public_ip
}
output "config" {
value = aws_instance.web
sensitive = true
}Exportar valores.
Locals
locals {
project_name = "my-app"
common_tags = {
Project = local.project_name
Env = var.environment
}
subnets = [
for i in range(3) :
"10.0.${i}.0/24"
]
}Valores calculados internos.
Módulos
Usar un módulo
module "vpc" {
source = "terraform-aws-modules/vpc/aws"
version = "5.0.0"
name = "my-vpc"
cidr = "10.0.0.0/16"
azs = ["eu-west-1a", "eu-west-1b"]
}Usar un módulo del registry.
Módulo local
module "app" {
source = "./modules/app"
name = "web"
instance_type = "t3.small"
subnet_id = module.vpc.private_subnets[0]
}Módulo local personalizado.
Crear un módulo
# modules/app/main.tf
variable "name" { type = string }
variable "instance_type" { type = string }
resource "aws_instance" "this" {
instance_type = var.instance_type
}
output "id" {
value = aws_instance.this.id
}
Estructura de un módulo.
Fuentes de módulos
source = "./modules/local"
source = "terraform-aws-modules/vpc/aws"
source = "github.com/user/repo//dir"
source = "s3::https://s3-eu-west-1.amazonaws.com/bucket/module.zip"
source = "git::https://github.com/user/repo.git?ref=v1.0"
Orígenes disponibles.
State
Comandos de state
terraform state list
terraform state show aws_instance.web
terraform state mv old new
terraform state rm aws_instance.web
terraform state pull > backup.json
Gestionar el estado.
Backend remoto (S3)
terraform {
backend "s3" {
bucket = "my-tf-state"
key = "prod/terraform.tfstate"
region = "eu-west-1"
dynamodb_table = "tf-locks"
encrypt = true
}
}Estado compartido con locking.
Importar recursos
terraform import aws_instance.web i-12345
# o con un bloque import (TF 1.5+):
import {
to = aws_instance.web
id = "i-12345"
}
Adoptar recursos existentes.
Refresh y taint
terraform refresh
terraform apply -refresh-only
terraform taint aws_instance.web
terraform untaint aws_instance.web
Sincronizar y marcar para recrear.
Providers
Configurar un provider
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}
provider "aws" {
region = "eu-west-1"
}Definir el provider y la versión.
Múltiples providers
provider "aws" {
region = "eu-west-1"
}
provider "aws" {
alias = "us"
region = "us-east-1"
}
resource "aws_instance" "dr" {
provider = aws.us
}Usar varias regiones/cuentas.
Versión de Terraform
terraform {
required_version = ">= 1.5.0"
required_providers {
aws = { version = "~> 5.0" }
random = { version = "~> 3.5" }
}
}Fijar versiones.
Providers comunes
hashicorp/aws
hashicorp/azurerm
hashicorp/google
hashicorp/kubernetes
hashicorp/helm
hashicorp/null (provisioners)
hashicorp/random
Providers populares.
Avançado
Workspaces
terraform workspace list
terraform workspace new staging
terraform workspace select prod
terraform workspace show
# usar en código:
name = "${terraform.workspace}-app"
Entornos aislados.
Funciones útiles
join("-", ["a", "b"]) # "a-b"
lookup(map, key, default)
merge(map1, map2)
length(list)
format("%s-%s", a, b)
try(expr, fallback)
coalesce(a, b, c)Funciones de manipulación.
Provisioners
resource "aws_instance" "web" {
# ...
provisioner "remote-exec" {
inline = [
"sudo apt update",
"sudo apt install -y nginx"
]
}
connection {
type = "ssh"
user = "ubuntu"
private_key = file("~/.ssh/id_rsa")
}
}Ejecutar después de la creación.
Buenas prácticas
# • Usar remote state con locking
# • Módulos pequeños y reutilizables
# • Variables con description y type
# • terraform fmt + validate en CI
# • Nunca commitear .tfstate
# • Usar versiones fijas de providers
# • Separar por entorno (workspaces o dirs)
Recomendaciones de uso.