# Guia Pulumi ## O que é Pulumi? Pulumi é uma ferramenta de **Infrastructure as Code (IaC)**: em vez de clicar no console da AWS, você descreve os recursos em código Python (ou outras linguagens) e o Pulumi cria, atualiza e destrói esses recursos de forma controlada e reproduzível. ### Conceitos básicos | Conceito | O que é | |----------|---------| | **Projeto** | O diretório com `Pulumi.yaml` — define o nome e a linguagem do projeto | | **Stack** | Um ambiente independente do mesmo projeto (ex: `dev`, `prod`, `Inovyo`). Cada stack tem seu próprio estado e configuração | | **Estado** | Arquivo que o Pulumi mantém mapeando cada recurso do código a um recurso real na AWS. É a "memória" do Pulumi | | **`pulumi preview`** | Mostra o que **vai** mudar, sem aplicar nada — equivalente a um "dry run" | | **`pulumi up`** | Aplica as mudanças: cria, atualiza ou remove recursos para corresponder ao código | | **Output** | Valores exportados pelo código após o deploy (ex: a URL do ALB) | ### Como o Pulumi sabe o que mudar? 1. Você edita o código ou o arquivo de configuração 2. `pulumi preview` compara o código com o estado salvo e mostra o diff 3. `pulumi up` aplica o diff na AWS e atualiza o estado --- ## Pré-requisitos - [Pulumi CLI](https://www.pulumi.com/docs/install/) instalado - AWS CLI configurado com credenciais válidas para a conta - Python 3.12+ e `venv` --- ## Estrutura do projeto ``` infra/ecs_alb/ ├── Pulumi.yaml # Metadados do projeto (nome, runtime) ├── Pulumi.Inovyo.yaml # Configuração da stack "Inovyo" (região, VPC, ECS, env vars...) ├── __main__.py # Ponto de entrada — define ALB, cluster ECS e chama ecs.deploy_app() ├── conf.py # Lê as configurações do Pulumi e as expõe como variáveis Python ├── ecs.py # Cria task definition, service, target groups, listeners e auto-scaling ├── ecr.py # Referencia a imagem no ECR pelo digest ou tag ├── iam.py # Cria execution role e task role com políticas (Bedrock, DynamoDB, Secrets Manager...) └── kms.py # Chave KMS (usada opcionalmente para criptografia de segredos) ``` --- ## Setup inicial ```bash cd infra/ecs_alb # Criar e ativar virtualenv python -m venv .venv source .venv/bin/activate # Instalar dependências pip install -r requirements.txt # Selecionar a stack pulumi stack select ``` --- ## Comandos principais | Comando | O que faz | |---------|-----------| | `pulumi preview` | Mostra o que será criado/alterado/destruído **sem aplicar** | | `pulumi preview --diff` | Igual ao anterior, com diff detalhado de cada recurso | | `pulumi up` | Aplica as mudanças na AWS | | `pulumi up --yes` | Aplica sem pedir confirmação interativa | | `pulumi destroy` | Remove **todos** os recursos da stack da AWS | | `pulumi stack ls` | Lista todas as stacks do projeto | | `pulumi stack output` | Exibe os outputs exportados (ex: URL do ALB) | | `pulumi refresh` | Sincroniza o estado Pulumi com o estado real da AWS | Sempre prefira `pulumi preview` antes de `pulumi up` para revisar o impacto das mudanças. --- ## Arquivo de configuração: `Pulumi.Inovyo.yaml` Toda a configuração da stack fica nesse arquivo. As seções principais: ### Rede ```yaml app-ecs:network: vpc_id: alb_internal: false alb_subnet_ids: # Subnets públicas do ALB (mínimo 2, mesma região) - - alb_allow_ingress_cidr: # IPs que podem acessar o ALB - /32 ecs_subnet_ids: # Subnets privadas dos containers - - ``` ### ECS / Container ```yaml app-ecs:ecs: - task_name: assisnte-analitico-db-dev ecr_repo_name: assistente-analitico-db-dev # Use ecr_image_digest OU ecr_image_tag (nunca os dois) ecr_image_digest: sha256: cpu: 256 memory: 512 desired_count: 1 use_load_balancer: true auto_scaling: min_capacity: 1 max_capacity: 3 target_value: 60.0 # % de CPU alvo para escalar lb_configs: - name: api listener_port: 8000 target_port: 8000 container_port: 8000 - name: streamlit listener_port: 8501 target_port: 8501 container_port: 8501 env_variables: TABLE: poc_dnx_monthly_summary REGION: us-east-1 ``` --- ## Fluxo de deploy de nova imagem Após buildar e publicar uma nova imagem Docker (veja [deployment.md](deployment.md)): **1. Obter o digest da nova imagem:** ```bash aws ecr describe-images \ --repository-name assistente-analitico-db-dev \ --region us-east-1 \ --query 'sort_by(imageDetails, &imagePushedAt)[-1].imageDigest' \ --output text ``` **2. Atualizar o `Pulumi.Inovyo.yaml`:** ```yaml ecr_image_digest: sha256: ``` **3. Revisar e aplicar:** ```bash cd infra/ecs_alb pulumi preview --diff --stack pulumi up --stack ``` --- ## Adicionar ou alterar variáveis de ambiente do container Edite a seção `env_variables` em `Pulumi.Inovyo.yaml` e rode `pulumi up`. O Pulumi atualizará a task definition e forçará o re-deploy do serviço ECS automaticamente. ```yaml env_variables: NOVA_VARIAVEL: valor ``` --- ## Verificar o output após o deploy ```bash pulumi stack output --stack ``` Retorna a URL do ALB, por exemplo: ``` url: http://alb-assistente-analitico-xxxxxxxx.us-east-1.elb.amazonaws.com ``` --- ## Alterar capacidade de auto-scaling Edite `auto_scaling` em `Pulumi.Inovyo.yaml`: ```yaml auto_scaling: min_capacity: 1 # mínimo de tasks rodando max_capacity: 5 # máximo de tasks target_value: 70.0 # escala quando CPU média ultrapassar 70% ``` Depois rode `pulumi up`. --- ## Permitir acesso ao ALB por Security Group Por padrão, o acesso ao ALB é restrito por CIDR (`alb_allow_ingress_cidr`). Para permitir um security group no lugar de um IP, são necessárias duas alterações: **1. Edite `__main__.py`** — troque `cidr_blocks` por `security_groups` na regra de ingress do ALB: ```python ingress=[aws.ec2.SecurityGroupIngressArgs( protocol="-1", from_port=0, to_port=0, security_groups=config.network["alb_allow_ingress_sgs"], )], ``` **2. Edite `Pulumi.Inovyo.yaml`** — substitua `alb_allow_ingress_cidr` por: ```yaml app-ecs:network: alb_allow_ingress_sgs: - ``` > Para manter ambos (IP e SG ao mesmo tempo), adicione os dois campos à mesma `SecurityGroupIngressArgs`, ou crie entradas separadas em `ingress`. --- ## Solução de problemas **`pulumi up` falha com erro de estado inconsistente:** ```bash pulumi refresh --stack # sincroniza estado com AWS pulumi up --stack ``` **Recurso preso em estado de update:** ```bash pulumi stack export --stack > state.json # Editar state.json para remover o recurso problemático pulumi stack import --stack < state.json ``` **Ver logs do container após o deploy:** ```bash aws logs tail --follow --region us-east-1 ``` **Verificar tasks rodando no ECS:** ```bash aws ecs list-tasks --cluster --region us-east-1 ```