Salta el contingut

State Management: El Cor de Terraform

4. State Management: El Cor de Terraform

El state management és potser l'aspecte més important i més sovint mal entès de Terraform. Aprofundim en com funciona i com gestionar-lo correctament.

Què Hi Ha en el State?

El state file (terraform.tfstate) és un fitxer JSON que conté:

  1. Metadata sobre la configuració: Versió de Terraform, backend utilitzat, etc.

  2. Un inventari complet de tots els recursos gestionats: Cada recurs que Terraform ha creat, amb:

  3. Identificador únic del recurs
  4. Totes les propietats del recurs (incloses les sensibles com contrasenyes)
  5. Dependencies entre recursos
  6. Metadata del provider

  7. Outputs calculats: Els valors dels outputs definits

Vegem un fragment d'un state file real:

{
  "version": 4,
  "terraform_version": "1.9.0",
  "resources": [
    {
      "mode": "managed",
      "type": "aws_instance",
      "name": "web_server",
      "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]",
      "instances": [
        {
          "attributes": {
            "id": "i-0abc123def456",
            "ami": "ami-0c55b159cbfafe1f0",
            "instance_type": "t3.micro",
            "public_ip": "203.0.113.45",
            "private_ip": "10.0.1.23",
            "tags": {
              "Name": "Web Server",
              "Environment": "production"
            }
          },
          "dependencies": ["aws_security_group.web"]
        }
      ]
    }
  ]
}

Per Què el State És Crític

El state és absolutament crític per al funcionament de Terraform. Sense ell:

No hi hauria idempotència: Cada vegada que executessis terraform apply, Terraform intentaria crear tots els recursos de nou, causant errors o duplicats.

No hi hauria gestió de canvis: Terraform no sabria quins recursos ja existeixen, així que no podria modificar-los o destruir-los correctament.

No hi hauria tracking de dependencies: Terraform no sabria en quin ordre destruir recursos sense trencar dependencies.

Es perdria informació important: Alguns valors que necessites (com IPs assignades dinàmicament) només es coneixen després de crear un recurs, i s'emmagatzemen en el state.

State Locking: Prevenint Conflictes

Imagina aquest escenari: tu i un company executeu terraform apply simultàniament. Ambdós llegiu el mateix state, calculen canvis, i intenten aplicar-los. El resultat podria ser catastròfic: state corromput, recursos en estats inconsistents, errors difícils de depurar.

El state locking prevé això. Quan utilitzes un backend que suporta bloqueig (com S3 amb DynamoDB, o Terraform Cloud), Terraform adquireix un lock abans de qualsevol operació que modifiqui l'estat. Si algú més ja té el lock, has d'esperar.

Configuració d'state locking amb S3 i DynamoDB:

# Primer, crea la taula de DynamoDB per al locking
resource "aws_dynamodb_table" "terraform_lock" {
  name           = "terraform-state-lock"
  billing_mode   = "PAY_PER_REQUEST"
  hash_key       = "LockID"

  attribute {
    name = "LockID"
    type = "S"
  }
}

# Després, configura el backend
terraform {
  backend "s3" {
    bucket         = "my-terraform-state-bucket"
    key            = "production/terraform.tfstate"
    region         = "eu-west-1"
    encrypt        = true
    dynamodb_table = "terraform-state-lock"
  }
}

Backends Remots: Best Practices

En producció, sempre hauries d'utilitzar un backend remot. Vegem les opcions més comunes:

S3 Backend (AWS):

terraform {
  backend "s3" {
    bucket         = "company-terraform-state"
    key            = "project/environment/terraform.tfstate"
    region         = "eu-west-1"
    encrypt        = true
    kms_key_id     = "arn:aws:kms:eu-west-1:123456789:key/abc-123"
    dynamodb_table = "terraform-locks"

    # Control d'accés
    workspace_key_prefix = "workspaces"
  }
}

Azure Storage Backend:

terraform {
  backend "azurerm" {
    resource_group_name  = "terraform-state-rg"
    storage_account_name = "companytfstate"
    container_name       = "tfstate"
    key                  = "production.terraform.tfstate"
  }
}

Google Cloud Storage Backend:

terraform {
  backend "gcs" {
    bucket = "company-terraform-state"
    prefix = "production"
  }
}

Terraform Cloud:

terraform {
  cloud {
    organization = "my-company"

    workspaces {
      name = "production-infrastructure"
    }
  }
}

State Manipulation: Quan i Com

Hi ha moments en què necessites manipular el state manualment. Terraform proporciona diverses comandes per això, però has d'anar amb molt de compte perquè pots fer malbé fàcilment.

terraform state list: Llista tots els recursos en el state:

$ terraform state list
aws_instance.web_server
aws_security_group.web
aws_db_instance.main

terraform state show: Mostra detalls d'un recurs específic:

$ terraform state show aws_instance.web_server
# aws_instance.web_server:
resource "aws_instance" "web_server" {
    id                    = "i-0abc123def456"
    ami                   = "ami-0c55b159cbfafe1f0"
    instance_type         = "t3.micro"
    public_ip             = "203.0.113.45"
    # ...més propietats
}

terraform state mv: Mou un recurs en el state (útil quan refactoritzar codi):

# Reanomenar un recurs en el codi sense destruir-lo
terraform state mv aws_instance.old_name aws_instance.new_name

terraform state rm: Elimina un recurs del state (el recurs real segueix existint):

# Deixar de gestionar un recurs amb Terraform
terraform state rm aws_instance.web_server

terraform import: Afegeix un recurs existent al state:

# Importar un servidor creat manualment
terraform import aws_instance.web_server i-0abc123def456

Aquesta darrera comanda és especialment útil quan adoptes Terraform en una infraestructura existent. Però recorda: després d'importar, has d'escriure el codi de Terraform que correspongui al recurs importat.

Drift Detection: Detectant Canvis Manuals

Una de les funcions més potents del state és la detecció de "drift" (desviació). El drift ocorre quan algú fa un canvi manual a la infraestructura fora de Terraform.

Per exemple, imagina que algú entra a la consola d'AWS i canvia el tipus d'instància d'un servidor de t3.micro a t3.medium. La propera vegada que executis terraform plan, Terraform detectarà aquest canvi:

$ terraform plan

Terraform will perform the following actions:

  # aws_instance.web_server will be updated in-place
  ~ resource "aws_instance" "web_server" {
        id            = "i-0abc123def456"
      ~ instance_type = "t3.medium" -> "t3.micro"
        # (15 unchanged attributes hidden)
    }

Plan: 0 to add, 1 to change, 0 to destroy.

Terraform veu que l'estat real (t3.medium) no coincideix amb l'estat desitjat (t3.micro) definit en el codi, i proposa tornar-lo a l'estat desitjat.

Això és extremadament valuós perquè assegura que la teva infraestructura sempre coincideix amb el que està definit en codi, prevenint "configuration drift" que és una causa comuna de problemes en producció.

State Refresh: Sincronitzant amb la Realitat

Periòdicament, Terraform "refresca" el state consultant l'API del provider per obtenir l'estat actual real de cada recurs. Això passa automàticament abans de plan i apply, però també pots fer-ho manualment:

terraform refresh

Això actualitza el state amb l'estat real dels recursos sense fer cap canvi. És útil si sospites que el state està desincronitzat.