Skip to content

Pulumi

Pulumi es una herramienta para Infrastructure as Code (IaC), del mismo modo que Terraform pero diferente en su estilo de implementación. Con Pulumi:

  • Usas lenguajes reales (Python, TypeScript, Go, etc.), por lo que puedes incluir bucles, funciones, condiciones, clases…
  • Tienes preview antes de deploy, para mostrar exactamente lo que va a cambiar.
  • Soporta todos los servicios de AWS (así como otros servicios cloud).

Instalación de Pulumi CLI

Prerrequisitos

  • Cuenta AWS (usa la de Free Tier)
  • AWS CLI instalado (sudo snap install aws-cli --classic para Linux y brew install awscli para macOS) y luego configurado:
    bash
    aws configure
    (ingresa Access Key, Secret Key, región us-east-1, output json)
  • Python 3.8+
  • Editor (VS Code o Zed recomendado)

Instalación desde macOS o Linux

bash
curl -fsSL https://get.pulumi.com | sh

Instalación para Windows (PowerShell como administrador)

bash
@"%SystemRoot%\System32\WindowsPowerShell\v1.0\powershell.exe" -NoProfile -InputFormat None -ExecutionPolicy Bypass -Command "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; iex ((New-Object System.Net.WebClient).DownloadString('https://get.pulumi.com/install.ps1'))" && SET "PATH=%PATH%;%USERPROFILE%\.pulumi\bin"

Verifcando versión instalada

bash
pulumi version   # Debe mostrar ~3.224.x o superior

Flujo de trabajo clásico de Pulumi

En Pulumi se usan Pilas (Stacks) por entorno y se puede conectarse a la nube de Pulumi para ello. Veamos:

bash
pulumi login
pulumi new aws-python --name mi-primer-stack
cd mi-primer-stack

Esto crea:

  • __main__.py (donde escribes tu código)
  • Pulumi.yaml
  • requirements.txt

Como comandos clave encuentras:

ComandoQué hace
pulumi previewMuestra exactamente qué se creará/cambiará
pulumi upPreview + confirma + deploy
pulumi stack outputVer outputs (IPs, URLs, etc.)
pulumi destroyElimina todo
pulumi stack rmBorra el stack (después de destroy)

Ejemplo con Bucket S3 simple

Reemplaza todo el contenido de __main__.py con el siguiente código:

python
import pulumi
import pulumi_aws as aws

# Crear bucket S3 privado
bucket = aws.s3.Bucket("mi-bucket-libros",
    bucket="mi-bucket-libros-2026",
    tags={
        "Environment": "Dev",
        "Owner": "Cesar"
    },
    acl="private"
)

# Exportar datos útiles
pulumi.export("bucket_name", bucket.bucket)
pulumi.export("bucket_arn", bucket.arn)

Se importan librerías y se define el recurso en una variable.
Con pulumi.export se deja a disposición datos útiles para ser usados.

Ejecuta luego:

bash
pulumi preview
pulumi up
pulumi stack output

Confirmas y podrás contar con tu primer recurso en AWS.

Ejemplo de Instancia EC2 con servidor web

Crea un nuevo proyecto o reemplaza __main__.py:

python
import pulumi
import pulumi_aws as aws

size = "t2.micro"   # Free Tier

# AMI Amazon Linux 2 (la más reciente)
ami = aws.ec2.get_ami(most_recent=True,
    owners=["137112412989"],
    filters=[{"name": "name", "values": ["amzn2-ami-hvm-*"]}])

# Security Group (puertos 22 y 80)
group = aws.ec2.SecurityGroup("web-secgrp",
    description="Permitir SSH y HTTP",
    ingress=[
        {"protocol": "tcp", "from_port": 22, "to_port": 22, "cidr_blocks": ["0.0.0.0/0"]},
        {"protocol": "tcp", "from_port": 80, "to_port": 80, "cidr_blocks": ["0.0.0.0/0"]},
    ])

# Script de inicio (servidor web simple)
user_data = """#!/bin/bash
echo "¡Hi from Pulumi + EC2!" > index.html
nohup python3 -m http.server 80 &
"""

server = aws.ec2.Instance("mi-ec2-web",
    instance_type=size,
    vpc_security_group_ids=[group.id],
    ami=ami.id,
    user_data=user_data)

pulumi.export("public_ip", server.public_ip)
pulumi.export("public_dns", server.public_dns)
bash
pulumi up
pulumi stack output public_dns   # Abre esa URL en el navegador

Si abres la url en el navegador, verás el mensaje: ¡Hi from Pulumi + EC2!

Ejemplo de Función Lambda (Serverless)

Crea una carpeta lambda y dentro un archivo lambda_function.py:

python
def handler(event, context):
    return {
        "statusCode": 200,
        "body": "¡Hola desde Lambda con Pulumi!"
    }

Comprimelo con formato zip:

bash
cd lambda
zip -r ../lambda.zip .
cd ..

Ahora en __main__.py (nuevo proyecto o reemplaza):

python
import pulumi
import pulumi_aws as aws

# Rol IAM para Lambda
role = aws.iam.Role("lambda-role",
    assume_role_policy="""{
        "Version": "2012-10-17",
        "Statement": [{
            "Action": "sts:AssumeRole",
            "Principal": {"Service": "lambda.amazonaws.com"},
            "Effect": "Allow"
        }]
    }""")

aws.iam.RolePolicyAttachment("lambda-basic",
    role=role.name,
    policy_arn="arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole")

# Función Lambda
lambda_func = aws.lambda_.Function("mi-lambda",
    code=pulumi.FileArchive("lambda.zip"),
    role=role.arn,
    handler="lambda_function.handler",
    runtime="python3.12",
    timeout=10)

pulumi.export("lambda_name", lambda_func.name)
pulumi.export("lambda_arn", lambda_func.arn)
bash
pulumi up

Para probar, ve a la consola AWS - Lambda - Test

Resumen del flujo Pulumi

Básicamente, se dispone de los siguientes hitos:

  1. pulumi preview: para ver el plan
  2. pulumi up: para confirmar y despliegar
  3. pulumi destroy: para limpiar todo (si es una prueba)

Pulumi es legible para desarrollaores si usas lenguajes de programación como Python