Acesse o painel da sua conta

Não tem uma conta? Registrar

Entrar em contato

Visite também nosso site craftxp.com.br

  • img
  • img
  • img
  • img
  • img
  • img

Entre em contato

Pulumi: Infraestrutura como Código Moderna com Python, TypeScript e Go

Pulumi: Infraestrutura como Código Moderna com Python, TypeScript e Go

O que é o Pulumi?

Pulumi é uma plataforma de Infrastructure as Code (IaC) que permite gerenciar recursos de nuvem usando linguagens de programação reais como Python, TypeScript, Go, C# e Java. Diferente do Terraform que usa HCL (HashiCorp Configuration Language), o Pulumi oferece loops, condicionais, funções e bibliotecas padrão — tudo que você espera de uma linguagem de programação moderna.

Fundado em 2017 por Joe Duffy (ex-engenheiro da Microsoft e criador do Midori), o Pulumi rapidamente se tornou uma alternativa popular ao Terraform, especialmente entre times que já trabalham com TypeScript ou Python no dia a dia.

Por que Pulumi em vez de Terraform?

Enquanto o Terraform é maduro e amplamente adotado, o Pulumi resolve várias limitações fundamentais do HCL:

  • Linguagem real: Use loops for, condicionais if/else, funções auxiliares e bibliotecas npm/pip — sem aprender HCL
  • TypeScript nativo: Autocomplete, type checking e refactoring no seu editor favorito
  • Reuso de código: Publique componentes como pacotes npm, Python wheels ou Go modules
  • Testabilidade: Escreva testes unitários e de integração com Jest, Pytest ou Go test
  • Multi-cloud consistente: Mesma linguagem e ferramentas para AWS, Azure, GCP, Kubernetes e mais

Primeiros Passos com Python

Vamos criar nossa primeira infraestrutura com Pulumi usando Python:

# Instalar o Pulumi CLI
curl -fsSL https://get.pulumi.com | sh

# Verificar instalação
pulumi version

# Criar um novo projeto Python
mkdir meu-projeto-pulumi
cd meu-projeto-pulumi
pulumi new aws-python

O comando pulumi new gera a estrutura do projeto com __main__.py, Pulumi.yaml e requirements.txt.

Criando Recursos AWS

Exemplo completo de um bucket S3 com versionamento e um bucket público para site estático:

"""
import pulumi
import pulumi_aws as aws
from pulumi_aws import s3

# Bucket privado com versionamento
bucket_dados = s3.Bucket("bucket-dados",
    bucket=f"dados-{pulumi.get_stack()}",
    versioning=s3.BucketVersioningArgs(
        enabled=True
    ),
    tags={
        "Ambiente": pulumi.get_stack(),
        "GerenciadoPor": "Pulumi"
    }
)

# Bucket público para site estático
bucket_site = s3.Bucket("bucket-site",
    bucket=f"site-{pulumi.get_stack()}",
    website=s3.BucketWebsiteArgs(
        index_document="index.html",
        error_document="error.html"
    ),
)

# Política para tornar o bucket público
bucket_policy = s3.BucketPolicy("bucket-policy",
    bucket=bucket_site.id,
    policy=bucket_site.arn.apply(lambda arn: json.dumps({
        "Version": "2012-10-17",
        "Statement": [{
            "Effect": "Allow",
            "Principal": "*",
            "Action": ["s3:GetObject"],
            "Resource": f"{arn}/*"
        }]
    }))
)

# Exportar outputs
pulumi.export("bucket_dados_nome", bucket_dados.id)
pulumi.export("url_site", bucket_site.website_endpoint)

Gerenciando Kubernetes com Pulumi

O Pulumi também gerencia clusters Kubernetes com a mesma linguagem. Exemplo de deploy de um deployment Nginx com service LoadBalancer:

import pulumi
from pulumi_kubernetes import Provider
from pulumi_kubernetes.apps.v1 import Deployment
from pulumi_kubernetes.core.v1 import Service

# Provider Kubernetes (pode ser local, EKS, AKS, GKE)
k8s_provider = Provider("k8s")

# Deployment
deployment = Deployment("nginx-deploy",
    spec={
        "selector": {"match_labels": {"app": "nginx"}},
        "replicas": 3,
        "template": {
            "metadata": {"labels": {"app": "nginx"}},
            "spec": {
                "containers": [{
                    "name": "nginx",
                    "image": "nginx:1.25",
                    "ports": [{"container_port": 80}]
                }]
            }
        }
    },
    opts=pulumi.ResourceOptions(provider=k8s_provider)
)

# Service
service = Service("nginx-service",
    spec={
        "selector": {"app": "nginx"},
        "ports": [{
            "port": 80,
            "target_port": 80,
            "protocol": "TCP"
        }],
        "type": "LoadBalancer"
    },
    opts=pulumi.ResourceOptions(provider=k8s_provider)
)

pulumi.export("nginx_ip", service.status.apply(
    lambda status: status.load_balancer.ingress[0].ip if status.load_balancer.ingress else None
))

Pulumi com TypeScript: Type Safety Total

TypeScript é a linguagem mais popular do Pulumi, oferecendo type checking completo para todos os recursos cloud:

import * as aws from "@pulumi/aws";
import * as pulumi from "@pulumi/pulumi";

// VPC com subnets
const vpc = new aws.ec2.Vpc("main-vpc", {
    cidrBlock: "10.0.0.0/16",
    enableDnsSupport: true,
    enableDnsHostnames: true,
    tags: { Name: "main-vpc" },
});

const publicSubnet = new aws.ec2.Subnet("public-subnet", {
    vpcId: vpc.id,
    cidrBlock: "10.0.1.0/24",
    mapPublicIpOnLaunch: true,
    availabilityZone: "us-east-1a",
    tags: { Name: "public-subnet" },
});

// Security Group
const webSg = new aws.ec2.SecurityGroup("web-sg", {
    vpcId: vpc.id,
    ingress: [
        { protocol: "tcp", fromPort: 80, toPort: 80, cidrBlocks: ["0.0.0.0/0"] },
        { protocol: "tcp", fromPort: 443, toPort: 443, cidrBlocks: ["0.0.0.0/0"] },
    ],
    egress: [
        { protocol: "-1", fromPort: 0, toPort: 0, cidrBlocks: ["0.0.0.0/0"] },
    ],
});

export const vpcId = vpc.id;
export const subnetId = publicSubnet.id;

Pulumi Automation API: Infraestrutura Programática

Um dos recursos mais poderosos do Pulumi é a Automation API, que permite gerenciar infraestrutura programaticamente dentro de aplicações — ideal para plataformas internas (IDP) e self-service:

import pulumi
from pulumi.automation import create_stack, LocalWorkspace

def criar_ambiente_dev(projeto: str):
    """
    Cria um ambiente Pulumi completo via API.
    Útil para plataformas self-service onde devs
    solicitam ambientes sob demanda.
    """
    workspace = LocalWorkspace(
        project_settings={
            "name": "infra-dev",
            "runtime": "python",
        },
        secrets_provider="passphrase",
    )

    stack = create_stack("dev-${projeto}", workspace=workspace)

    # Define as configurações do stack
    stack.set_config("aws:region", "us-east-1")
    stack.set_all_config({
        "projeto": pulumi.Config_value(projeto),
    })

    # Define o programa Pulumi
    stack.set_program(lambda: criar_recursos_dev())

    # Executa up (equivalente ao pulumi up)
    result = stack.up(on_output=print)
    return result.outputs

def criar_recursos_dev():
    import pulumi_aws as aws
    # ... recursos do ambiente dev
    bucket = aws.s3.Bucket("dev-bucket")
    pulumi.export("bucket_name", bucket.id)

Componentes Reutilizáveis

Com Pulumi, você pode criar componentes reutilizáveis e distribuí-los como pacotes:

# meu-pacote/componente.py
import pulumi
from pulumi import ComponentResource, ResourceOptions
import pulumi_aws as aws
from typing import Optional

class BucketComTags(ComponentResource):
    def __init__(self, name: str, bucket_name: str,
                 versioning: bool = True,
                 opts: Optional[ResourceOptions] = None):
        super().__init__("meupacote:BucketComTags", name, None, opts)

        self.bucket = aws.s3.Bucket(f"{name}-bucket",
            bucket=bucket_name,
            versioning=aws.s3.BucketVersioningArgs(
                enabled=versioning
            ),
            tags={
                "GerenciadoPor": "Pulumi",
                "Projeto": name,
                "Versao": "1.0"
            },
            opts=ResourceOptions(parent=self)
        )

        self.register_outputs({
            "bucket_id": self.bucket.id,
            "bucket_arn": self.bucket.arn,
        })

# Uso: pip install meu-pacote
bucket = BucketComTags("meu-bucket", "dados-app-prod")
pulumi.export("id", bucket.bucket_id)

Pulumi Cloud: Estado, Segredos e Colaboração

O Pulumi Cloud (anteriormente Pulumi Service) oferece gerenciamento de estado remoto, armazenamento seguro de segredos e colaboração em time:

  • State remoto: Mantenha o estado da infraestrutura centralizado e versionado
  • Secrets encriptados: Senhas e chaves de API são criptografadas automaticamente
  • Webhooks: Notifique Slack, Teams ou webhooks em cada deploy
  • Pull Request comments: Veja diff de infra diretamente nos PRs do GitHub/GitLab
  • Policy as Code: Aplique regras de compliance com CrossGuard (policies em Python/TypeScript)

Policy as Code com CrossGuard

CrossGuard é o framework de políticas do Pulumi que permite validar infraestrutura antes do deploy:

# policy.py
from pulumi_policy import (
    ResourceValidationPolicy,
    PolicyPack,
    StackValidationPolicy,
)

# Política: todo bucket S3 deve ter versionamento
bucket_versioning_policy = ResourceValidationPolicy(
    name="s3-versioning-obrigatorio",
    description="Todos os buckets S3 devem ter versionamento ativado",
    validate=lambda args, report:
        report.assertion(
            args.resource_type == "aws:s3/bucket:Bucket"
            and args.props.get("versioning", {}).get("enabled"),
            "Bucket S3 sem versionamento ativado!",
        ),
)

# Política: tags obrigatórias em todos os recursos
tag_policy = ResourceValidationPolicy(
    name="tags-obrigatorias",
    description="Todos os recursos devem ter tag Ambiente",
    validate=lambda args, report:
        report.assertion(
            "Ambiente" in args.props.get("tags", {}),
            f"Tag 'Ambiente' ausente em {args.resource_type}",
        ),
)

PolicyPack(
    name="politicas-infra",
    policies=[bucket_versioning_policy, tag_policy],
)

Comparativo de Comandos

OperaçãoTerraformPulumi
Iniciar projetoterraform initpulumi new
Ver planoterraform planpulumi preview
Aplicarterraform applypulumi up
Destruirterraform destroypulumi destroy
Ver estadoterraform state listpulumi stack ls

Conclusão

Pulumi representa uma evolução natural no mundo de Infrastructure as Code. Ao permitir que desenvolvedores usem linguagens que já conhecem — Python, TypeScript, Go — ele elimina a barreira de aprendizado do HCL e abre possibilidades como testes unitários, reuso via pacotes e automação programática com a Automation API.

Se seu time já trabalha com TypeScript no front-end e Python nos dados, o Pulumi permite unificar a stack: a mesma linguagem para aplicação e infraestrutura. Para novos projetos, especialmente em ambientes multi-cloud ou com times de plataforma, o Pulumi é uma escolha cada vez mais popular — e por bons motivos.

Craft XP
Craft XP