Terraform y LocalStack

Terraform y LocalStack

Image: Infra as Code

Si trabajas con DevOps, redes, sistemas o cloud, probablemente ya escuchaste hablar de Terraform. Esta herramienta se volvió casi obligatoria para quien quiere automatizar infraestructura de forma simple y escalable.

Pero existe una barrera para mucha gente: ¿cómo practicar sin gastar dinero en nube pública? El co$$to de jugar en la cloud puede ser alto. Basta olvidar una VM encendida para percibir lo rápido que llega la cuenta. Es ahí donde entra la combinación Terraform + LocalStack.

Usar los dos juntos es una excelente forma de entrenar infraestructura como código (IaC) sin gastar nada. Como LocalStack es open source y puede instalarse vía containers, consigues crear un escenario realista de nube privada para experimentar recursos como redes, máquinas virtuales y volúmenes. Esto elimina gastos en cloud pública y viabiliza el aprendizaje de forma accesible.

Otra gran ventaja es que el combo permite simular flujos muy próximos a los entornos de producción. Escribes el código Terraform, lo aplicas en LocalStack y ves los recursos siendo aprovisionados en la práctica. Así, resulta fácil entender conceptos como versionado, modularización, gestión de estado y automatización de infraestructura. Es un aprendizaje práctico, que va más allá de la teoría, acelera la curva de conocimiento y además ayuda a perder el miedo de crear y destruir recursos sin preocupación.

Preparé un lab basado en Docker Compose y voy a mostrar cómo usar Terraform para aprovisionar una instancia en LocalStack (y también comparar con AWS).

Organización de los archivos

Antes de empezar, para mantener el laboratorio organizado y fácil de entender, es importante seguir una estructura de directorio como la descrita abajo. El archivo docker-compose.yml debe quedar en la raíz del proyecto, pues es quien levanta todo el ambiente de containers. Los archivos de Terraform quedan dentro de la carpeta terraform/, separando lo que es infraestructura de la orquestación de containers. Dentro de esa carpeta, el provider.tf se usa para configurar el proveedor (como LocalStack o AWS) y el main.tf concentra la definición de los recursos que serán creados. Esa organización simple hace el lab más legible, modular y fácil de mantener.

├── docker-compose.yml
├── terraform/
    ├── main.tf
    ├── provider.tf

Docker Compose

Docker Compose va a ser la base para crear los ambientes y ejecutar el script terraform y una instancia de LocalStack para simular un provider de cloud.

Archivo: docker-compose.yml

 1version: '3.8'
 2
 3services:
 4  localstack:
 5    container_name: localstack
 6    image: localstack/localstack:latest
 7    ports:
 8      - "4566:4566"
 9      - "4510-4559:4510-4559"
10    environment:
11      - EDGE_PORT=4566
12      - AWS_DEFAULT_REGION=us-east-1
13      - AWS_ACCESS_KEY_ID=test
14      - AWS_SECRET_ACCESS_KEY=test  
15      - SERVICES=ec2
16      - DEBUG=1
17      - DATA_DIR=/tmp/localstack/data
18      - DOCKER_HOST=unix:///var/run/docker.sock
19      - HOST_TMP_FOLDER=/var/lib/localstack
20    volumes:
21      - localstack_data:/var/lib/localstack
22      - "/var/run/docker.sock:/var/run/docker.sock"
23    networks:
24      - terraform
25
26  terraform:
27    image: hashicorp/terraform:1.6
28    container_name: terraform
29    working_dir: /workspace
30    volumes:
31      - ./terraform:/workspace
32    networks:
33      - terraform
34    depends_on:
35      - localstack
36    entrypoint: ["tail", "-f", "/dev/null"]
37
38
39volumes:
40  localstack_data:
41
42networks:
43  terraform:
44    name: terraform

Para crear el ambiente basta con ejecutar

docker compose up -d --build

LocalStack Cloud Provider

En Terraform, un provider (proveedor) es el componente responsable de hacer el puente entre los scripts Terraform y el servicio que quieres gestionar; en el caso de esta explicación es LocalStack. Cada provider es como si fuera un plugin que traduce los comandos de Terraform en llamadas a la API de la plataforma que estás usando.

Ejemplo práctico: si quieres crear una instancia en AWS, necesitas el provider “aws”. Si quieres crear una red en LocalStack, usas el provider “localstack”. Y así sucesivamente, ¿captaste?

Mira la config de nuestro lab:

Archivo: terraform/provider.tf
 1terraform {
 2  required_providers {
 3    aws = {
 4      source  = "hashicorp/aws"
 5      version = "~> 5.0"
 6    }
 7  }
 8}
 9
10provider "aws" {
11  access_key                  = "test"
12  secret_key                  = "test"
13  region                      = "us-east-1"
14  s3_use_path_style          = true
15  skip_credentials_validation = true
16  skip_metadata_api_check     = true
17  skip_requesting_account_id  = true
18
19  endpoints {
20    s3       = "http://localstack:4566"
21    ec2      = "http://localstack:4566"
22  }
23}

Terraform script

Un script Terraform es un archivo o un conjunto de archivos de configuración escritos en HCL (HashiCorp Configuration Language) que describen la infraestructura que deseas crear o gestionar.

En vez de crear recursos manualmente en un panel de cloud, escribes ese script diciendo, por ejemplo, “quiero una VM con tal red y tal disco”. Terraform lee el script, compara con el estado actual de la infraestructura y ejecuta los cambios necesarios para dejar todo igual a lo que fue definido en el código. Es la base del concepto de infraestructura como código (IaC).

El script de abajo crea una VM en AWS; para Terraform eso es un recurso llamado “aws_instance”, mira los pasos de cómo crearla.

Archivo: terraform/main.tf
 1# Buscar a última AMI Amazon Linux 2
 2data "aws_ami" "amazon_linux" {
 3  most_recent = true
 4
 5  filter {
 6    name   = "name"
 7    values = ["amzn2-ami-hvm-*-x86_64-gp2"]
 8  }
 9
10  owners = ["amazon"]
11}
12
13# Criar uma instância EC2
14resource "aws_instance" "exemplo_ec2" {
15  ami           = data.aws_ami.amazon_linux.id
16  instance_type = "t2.micro"
17
18  tags = {
19    Name = "Infraascode.com.br - Terraform"
20  }
21}

Iniciando Terraform

El comando terraform init sirve para inicializar un directorio de trabajo de Terraform, preparando todo para que puedas usar tus scripts. Descarga e instala los providers necesarios (como AWS, Azure, LocalStack, etc.), configura el backend de almacenamiento del estado (si lo hubiera) y valida la estructura inicial de los archivos; en resumen, es el primer paso obligatorio antes de correr cualquier otro comando, pues garantiza que el ambiente esté listo para ejecutar el plan y aplicar la infraestructura.

 1  $ terraform  init
 2
 3Initializing the backend...
 4
 5Initializing provider plugins...
 6- Finding hashicorp/aws versions matching "~> 5.0"...
 7- Installing hashicorp/aws v5.100.0...
 8- Installed hashicorp/aws v5.100.0 (signed by HashiCorp)
 9
10Terraform has created a lock file .terraform.lock.hcl to record the provider
11selections it made above. Include this file in your version control repository
12so that Terraform can guarantee to make the same selections by default when
13you run "terraform init" in the future.
14
15Terraform has been successfully initialized!
16
17You may now begin working with Terraform. Try running "terraform plan" to see
18any changes that are required for your infrastructure. All Terraform commands
19should now work.
20
21If you ever set or change modules or backend configuration for Terraform,
22rerun this command to reinitialize your working directory. If you forget, other
23commands will detect it and remind you to do so if necessary.

Verificando el plan de ejecución

El comando terraform plan sirve para mostrar, de forma previa, lo que Terraform va a hacer antes de aplicar los cambios en tu infraestructura. Compara lo que está definido en tus archivos de configuración con el estado actual y genera un “plan de ejecución”, indicando qué recursos serán creados, alterados o destruidos. Esto ayuda a revisar y validar los cambios antes de ejecutarlos, evitando sorpresas o errores.

 1terraform plan -out=infraascode_com_br
 2data.aws_ami.amazon_linux: Reading...
 3data.aws_ami.amazon_linux: Read complete after 2s [id=ami-04681a1dbd79675a5]
 4
 5Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
 6  + create
 7
 8Terraform will perform the following actions:
 9
10  # aws_instance.exemplo_ec2 will be created
11  + resource "aws_instance" "exemplo_ec2" {
12      + ami                                  = "ami-04681a1dbd79675a5"
13      + arn                                  = (known after apply)
14      + associate_public_ip_address          = (known after apply)
15      + availability_zone                    = (known after apply)
16      + instance_type                        = "t2.micro"
17      + tags                                 = {
18          + "Name" = "Infraascode.com.br - Terraform"
19        }
20      + tags_all                             = {
21          + "Name" = "Infraascode.com.br - Terraform"
22        }
23      + id                                   = (known after apply)
24      + public_ip                            = (known after apply)
25      + private_ip                           = (known after apply)
26    }
27
28Plan: 1 to add, 0 to change, 0 to destroy.
29
30───────────────────────────────────────────────────────────────────────────────
31
32Saved the plan to: infraascode_com_br
33
34To perform exactly these actions, run the following command to apply:
35    terraform apply "infraascode_com_br"

Terraform apply

El comando terraform apply se usa para ejecutar los cambios descritos en los archivos de configuración, aplicando en la infraestructura todo lo que fue planeado en el terraform plan. Crea, altera o remueve recursos de acuerdo con el código y solo finaliza cuando la infraestructura está en el estado deseado. En otras palabras, es el comando que transforma tu código Terraform en recursos reales funcionando en el ambiente definido, en nuestro caso LocalStack.

1  $terraform  apply infraascode_com_br
2aws_instance.exemplo_ec2: Creating...
3aws_instance.exemplo_ec2: Still creating... [10s elapsed]
4aws_instance.exemplo_ec2: Creation complete after 10s [id=i-50b40c581c4dad9b4]
5
6Apply complete! Resources: 1 added, 0 changed, 0 destroyed.

Verificando el resultado

El comando terraform state list sirve para exhibir todos los recursos que Terraform está gestionando en el archivo de estado (terraform.tfstate). Muestra la lista de los objetos conocidos por Terraform, como VMs, redes, discos o cualquier otro recurso creado. Esto es útil para verificar lo que ya fue aprovisionado, confirmar nombres correctos de recursos e incluso para depurar situaciones en que el código y la infraestructura parecen no estar alineados.

 1terraform state list
 2data.aws_ami.amazon_linux
 3aws_instance.exemplo_ec2
 4/workspace/# terraform state show   aws_instance.exemplo_ec2
 5# aws_instance.exemplo_ec2:
 6resource "aws_instance" "exemplo_ec2" {
 7    ami                                  = "ami-04681a1dbd79675a5"
 8    arn                                  = "arn:aws:ec2:us-east-1::instance/i-50b40c581c4dad9b4"
 9    associate_public_ip_address          = true
10    availability_zone                    = "us-east-1a"
11    disable_api_stop                     = false
12    disable_api_termination              = false
13    ebs_optimized                        = false
14    get_password_data                    = false
15    hibernation                          = false
16    id                                   = "i-50b40c581c4dad9b4"
17    instance_initiated_shutdown_behavior = "stop"
18    instance_state                       = "running"
19    instance_type                        = "t2.micro"
20    ipv6_address_count                   = 0
21    ipv6_addresses                       = []
22    monitoring                           = false
23    placement_partition_number           = 0
24    primary_network_interface_id         = "eni-697884262d742bf4f"
25    private_dns                          = "ip-10-75-171-105.ec2.internal"
26    private_ip                           = "10.75.171.105"
27    public_dns                           = "ec2-54-214-150-17.compute-1.amazonaws.com"
28    public_ip                            = "54.214.150.17"
29    secondary_private_ips                = []
30    security_groups                      = []
31    source_dest_check                    = true
32    subnet_id                            = "subnet-777fbdb4bbd4df236"
33    tags                                 = {
34        "Name" = "Infraascode.com.br - Terraform"
35    }
36    tags_all                             = {
37        "Name" = "Infraascode.com.br - Terraform"
38    }
39    tenancy                              = "default"
40    user_data_replace_on_change          = false
41    vpc_security_group_ids               = []
42
43    metadata_options {
44        http_endpoint               = "enabled"
45        http_protocol_ipv6          = "disabled"
46        http_put_response_hop_limit = 1
47        http_tokens                 = "optional"
48        instance_metadata_tags      = "disabled"
49    }
50
51    root_block_device {
52        delete_on_termination = true
53        device_name           = "/dev/sda1"
54        encrypted             = false
55        iops                  = 0
56        tags                  = {}
57        tags_all              = {}
58        throughput            = 0
59        volume_id             = "vol-22f90e0fe787def16"
60        volume_size           = 8
61        volume_type           = "gp2"
62    }
63}

Resumiendo

Jugar con Terraform y LocalStack en un ambiente de LAB abre un abanico de posibilidades para quien quiere aprender infraestructura como código sin depender de la nube pública y sin preocuparse por los costos. Puedes probar la creación de máquinas virtuales, redes, volúmenes y simular flujos de producción de forma segura, rápida y controlada. Esa libertad de experimentar da confianza para entender conceptos de automatización, versionado y modularización sin miedo de “romper” nada crítico.

Además, el lab con Terraform y LocalStack es una excelente manera de descubrir nuevas funcionalidades, crear escenarios diferentes y evolucionar tus habilidades de forma práctica. En cada prueba ganas un poco más de experiencia y te acercas a lo que encontrarás en ambientes de empresas. Es una inversión en aprendizaje que acelera tu curva de evolución y te prepara para los desafíos.

¡Un abrazo!

¡Larga y próspera vida a todos!

Referencias


Entre em contato:

NewsLetter - https://engineeringmanager.com.br/
Linkdin - linkedin.com/in/leonardoml/
Twitter: @infraascode_br

Te convido a ver os outros posts do blog Infra-as-Code garanto que tem coisas legais lá!!


--- --- IMPORTANTE --- ---
As opiniões aqui expressas são pessoais e de responsabilidade única e exclusiva do autor, elas não refletem necessariamente a posição das empresas que eu trabalho(ei) e/ou presto(ei) serviço.


bio_banner_test