O que Pulumi Infraestrutura como Código faz?
Guia Rápido: Defina infraestrutura em nuvem em TypeScript com segurança total de tipos. Use
ComponentResourcepara encapsular padrões de infraestrutura reutilizáveis. Passe{ parent: this }para todos os recursos filhos dentro de componentes. Usepulumi.interpolatepara construir strings com Outputs (não concatenação de strings). Nunca crie recursos dentro de.apply(). UseConfig.requireSecret()para valores sensíveis. Prefiratransformsem vez detransformations(obsoleto). Sempre chamethis.registerOutputs()ao final dos construtores de componentes.
<critical_requirements>
CRÍTICO: Antes de Usar Este Skill
Todo código deve seguir as convenções do projeto em CLAUDE.md (kebab-case, exports nomeados, ordem de imports,
import type, constantes nomeadas)
(Você DEVE passar { parent: this } para TODOS os recursos filhos dentro de um ComponentResource — omitir isso quebra a árvore de recursos e o rastreamento de estado)
(Você DEVE usar pulumi.interpolate para construir strings com Outputs — a concatenação de strings produz silenciosamente [object Object])
(Você NUNCA DEVE criar recursos dentro de .apply() — eles não aparecerão em pulumi preview e causarão problemas de ordenação)
(Você DEVE usar Config.requireSecret() para valores sensíveis — Config.require() armazena valores como texto simples no estado)
(Você DEVE chamar this.registerOutputs() ao final de todo construtor de ComponentResource — omitir isso impede o rastreamento de saídas)
</critical_requirements>
Recursos Detalhados:
- examples/core.md - Definições de recursos, componentes, nomenclatura, Outputs, configuração/segredos
- examples/advanced.md - Referências de stack, transforms, provedores dinâmicos, Automation API, pacotes de política
- reference.md - Estruturas de decisão, tabela de opções de recursos, referência de API, comandos CLI
Auto-detecção: Pulumi, @pulumi/pulumi, @pulumi/aws, @pulumi/gcp, @pulumi/azure, @pulumi/kubernetes, pulumi.ComponentResource, pulumi.CustomResource, pulumi.Output, pulumi.Config, pulumi.interpolate, pulumi.all, registerOutputs, StackReference, ComponentResourceOptions, CustomResourceOptions, dynamic.Resource, dynamic.ResourceProvider, LocalWorkspace, InlineProgramArgs, Automation API, CrossGuard, PolicyPack
Quando usar:
- Definir infraestrutura em nuvem em TypeScript com APIs de recursos type-safe
- Criar componentes de infraestrutura reutilizáveis com
ComponentResource - Gerenciar arquiteturas multi-stack com referências de stack
- Lidar com segredos e configuração específica de ambiente
- Construir plataformas de infraestrutura self-service com a Automation API
- Escrever políticas de conformidade com pacotes de política CrossGuard
Quando NÃO usar:
- Scripts avulsos que criam um único recurso (use a CLI da nuvem diretamente)
- Projetos onde a equipe não tem experiência em TypeScript (considere outras opções de linguagem IaC)
Padrões principais abordados:
- Definições de recursos com entradas tipadas e nomenclatura automática
- Encapsulamento de ComponentResource (parent, nomenclatura, registerOutputs)
- Outputs:
apply,all,interpolatee lifting - Gerenciamento de configuração e segredos (
Config.require,Config.requireSecret,pulumi.secret) - Referências de stack para compartilhamento de dados entre stacks
- Opções de recursos (
dependsOn,protect,aliases,ignoreChanges,transforms) - Provedores dinâmicos para recursos CRUD personalizados
- Automation API para gerenciamento programático de stacks
- Pacotes de política CrossGuard para aplicação de conformidade
Filosofia
Pulumi trata infraestrutura como código real, não arquivos de configuração. TypeScript oferece segurança de tipos, autocompletar na IDE, ferramentas de refatoração e todo o ecossistema Node.js. Recursos são objetos, dependências são automáticas e a reutilização acontece através de funções e classes — não uma linguagem de módulo personalizada.
Princípios centrais:
- Recursos são objetos: Cada recurso de nuvem é uma instância de classe TypeScript com entradas e saídas tipadas
- Dependências são automáticas: Quando você passa a saída de um recurso como entrada de outro, o Pulumi infere o grafo de dependências
- Reutilização através de componentes:
ComponentResourceencapsula múltiplos recursos em uma única unidade lógica com suas próprias entradas e saídas - Outputs são promessas:
Output<T>representa um valor que pode não ser conhecido até após a implantação — useapply,allouinterpolatepara trabalhar com eles, nunca desempacote manualmente - Estado é gerenciado: Pulumi rastreia cada recurso no estado — mudar um nome lógico ou mover um recurso entre arquivos dispara um delete-e-recria, a menos que você use
aliases
Padrões Principais
Padrão 1: Definições de Recursos
Cada recurso recebe um nome lógico (usado para rastreamento de estado), um saco de argumentos (entradas tipadas) e opções de recurso opcionais.
const bucket = new aws.s3.Bucket(
"data-bucket",
{
versioning: { enabled: true },
lifecycleRules: [
{ enabled: true, expiration: { days: BUCKET_EXPIRY_DAYS } },
],
},
{ protect: true },
); // Impede exclusão acidental
Pontos-chave: Nomes lógicos devem ser únicos por tipo dentro de um stack. Pulumi anexa automaticamente um sufixo aleatório ao nome físico para evitar colisões. Use protect: true em recursos críticos. Exporte saídas para consumo entre stacks.
Veja examples/core.md para nomenclatura de recursos, configuração de nomenclatura automática e opções de provedor.
Padrão 2: Encapsulamento de ComponentResource
Agrupe recursos relacionados em um ComponentResource para criar unidades de infraestrutura reutilizáveis.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
interface StaticSiteArgs {
indexDocument?: string;
errorDocument?: string;
}
class StaticSite extends pulumi.ComponentResource {
public readonly bucketName: pulumi.Output<string>;
public readonly websiteUrl: pulumi.Output<string>;
constructor(
name: string,
args: StaticSiteArgs,
opts?: pulumi.ComponentResourceOptions,
) {
super("myinfra:web:StaticSite", name, args, opts);
const bucket = new aws.s3.BucketV2(`${name}-bucket`, {}, { parent: this });
const website = new aws.s3.BucketWebsiteConfigurationV2(
`${name}-website`,
{
bucket: bucket.id,
indexDocument: { suffix: args.indexDocument ?? "index.html" },
errorDocument: { key: args.errorDocument ?? "error.html" },
},
{ parent: this },
);
this.bucketName = bucket.id;
this.websiteUrl = website.websiteEndpoint;
this.registerOutputs({
bucketName: this.bucketName,
websiteUrl: this.websiteUrl,
});
}
}
Por que é bom: recursos filhos usam { parent: this }, nome é prefixado do pai, registerOutputs é chamado, token de tipo segue o formato pkg:module:Type
Veja examples/core.md para padrões completos de componentes com herança de provedor e componentes multi-recursos.
Padrão 3: Trabalhando com Outputs
Outputs representam valores resolvidos após a implantação. Nunca use concatenação de strings — use interpolate, apply ou all.
// interpolate -- template tag para construção de strings (preferido)
const url = pulumi.interpolate`https://${bucket.bucketRegionalDomainName}/index.html`;
// apply -- transforma um único output
const upper = bucket.id.apply((id) => id.toUpperCase());
// all -- combina múltiplos outputs
const endpoint = pulumi
.all([lb.dnsName, listener.port])
.apply(([dns, port]) => `http://${dns}:${port}`);
// Lifting -- acessa propriedades diretamente em saídas de recursos
const subnetId = vpc.subnets[0].id; // Não precisa de apply para propriedades conhecidas
Por que é bom: interpolate lida com valores Output de forma transparente, all espera por múltiplos valores, lifting evita chamadas apply desnecessárias
Pegadinha: Recursos criados dentro de .apply() não aparecerão em pulumi preview e podem causar problemas de ordenação. Sempre passe Outputs diretamente como entradas para outros recursos.
Veja examples/core.md para padrões de Output, encapsulamento pulumi.output() e o antipadrão apply.
Padrão 4: Config e Segredos
Use pulumi.Config para valores específicos de stack. Use requireSecret para dados sensíveis — ele criptografa o valor no estado.
const config = new pulumi.Config();
// Valores de configuração comuns
const region = config.require("region"); // Falha se ausente
const nodeCount = config.getNumber("nodeCount"); // Retorna undefined se ausente
// Valores secretos -- criptografados no estado
const dbPassword = config.requireSecret("dbPassword");
const apiKey = config.getSecret("apiKey");
// Marcar valores programáticos como secretos
const connectionString = pulumi.interpolate`postgres://admin:${dbPassword}@${db.endpoint}/mydb`;
// connectionString é automaticamente secreta porque dbPassword é secreto
// Marcar explicitamente um valor como secreto
const token = pulumi.secret(generateToken());
Ponto-chave: Qualquer Output derivado de um segredo é automaticamente marcado como secreto. Você não precisa re-marcar valores derivados.
Veja examples/core.md para config com namespace, saídas secretas e comandos CLI de configuração.
Padrão 5: Opções de Recursos
As opções de recurso controlam o comportamento do ciclo de vida. As mais importantes:
const db = new aws.rds.Instance(
"primary-db",
{
/* ... */
},
{
protect: true, // Impede exclusão acidental
dependsOn: [vpc, securityGroup], // Ordenação explícita
ignoreChanges: ["tags"], // Ignora drift em props específicas
aliases: [{ name: "old-db-name" }], // Renomeia sem recriar
retainOnDelete: true, // Mantém recurso na nuvem ao executar pulumi destroy
deleteBeforeReplace: true, // Para recursos que devem ser únicos
replaceOnChanges: ["engine"], // Força substituição em mudanças específicas
provider: usEastProvider, // Provedor explícito (região, conta)
},
);
Pegadinha: Mudar o nome lógico ou pai de um recurso faz o Pulumi excluí-lo e recriá-lo. Use aliases para renomear com segurança.
Veja reference.md para a tabela completa de opções de recursos.
Padrão 6: Referências de Stack
Compartilhe saídas entre stacks usando StackReference.
// No stack de rede: exportar saídas
export const vpcId = vpc.id;
export const subnetIds = subnets.map((s) => s.id);
// No stack de aplicação: consumir saídas
const networkStack = new pulumi.StackReference("myorg/networking/prod");
const vpcId = networkStack.getOutput("vpcId");
const subnetIds = networkStack.getOutput("subnetIds");
// requireOutput falha se a saída não existir (mais seguro que getOutput)
const vpcIdRequired = networkStack.requireOutput("vpcId");
Veja examples/advanced.md para padrões de referência de stack e getOutputDetails.
Padrão 7: Transforms
Aplique transformações a recursos e seus filhos. Use transforms (não o obsoleto transformations). Transforms recebem um objeto args com type, props e opts, e retornam um resultado modificado ou undefined para pular.
// Nível de recurso: aplicar tags a todos os filhos taggeáveis de um componente
const vpc = new MyVpcComponent(
"vpc",
{},
{
transforms: [
(args) => {
if (isTaggable(args.type)) {
return {
props: {
...args.props,
tags: { ...args.props["tags"], ManagedBy: "pulumi" },
},
opts: args.opts,
};
}
return undefined;
},
],
},
);
Diferença chave do obsoleto transformations: transforms suportam modificar filhos de componentes empacotados (awsx, eks), suportam callbacks assíncronos e não passam um objeto Resource.
Veja examples/advanced.md para transforms em nível de stack, modificação de opções e migração de transformations.
Padrão 8: Automation API
Execute Pulumi programaticamente sem a CLI — para plataformas self-service, testes de integração ou ferramentas de implantação personalizadas.
const stack = await LocalWorkspace.createOrSelectStack({
stackName: "dev",
projectName: "my-platform",
program: async () => {
const bucket = new aws.s3.Bucket("auto-bucket");
return { bucketName: bucket.id };
},
});
const upResult = await stack.up({ onOutput: console.log });
Ponto-chave: A Automation API requer que a CLI do Pulumi esteja instalada e no PATH — ela usa o motor da CLI internamente.
Veja examples/advanced.md para preview, destroy, modo de programa local, configuração e recuperação de saídas de stack.
<red_flags>
BANDEIRAS VERMELHAS
Alta Prioridade:
- Criar recursos dentro de
.apply()— Eles não aparecerão empulumi preview, causam problemas de ordenação e quebram o grafo de dependências. Passe Outputs diretamente como entradas de recursos. - Faltando
{ parent: this }em filhos de ComponentResource — Recursos aparecem na raiz da árvore de estado, quebrando o agrupamento lógico e a cascata de exclusão do componente. - Concatenação de strings com Outputs —
"https://" + bucket.idproduz[object Object]. Usepulumi.interpolateem vez disso. - Usar
Config.require()para senhas/chaves — Armazena o valor como texto simples no estado. UseConfig.requireSecret()para criptografar. - Esquecer
this.registerOutputs()— As saídas do componente não serão rastreadas corretamente no estado nem disponíveis via referências de stack. - Mudar nomes lógicos sem aliases — Pulumi exclui e recria o recurso. Use
aliases: [{ name: "old-name" }]para renomear com segurança.
Média Prioridade:
- Depender de provedores padrão em configurações multi-região — Use provedores explícitos por região. Defina
pulumi:disable-default-providersna configuração para impor. - Começar com funções em vez de ComponentResource — Migrar depois requer aliases ou recriação de recursos. Use componentes desde o início.
- Não usar
dependsOnpara dependências não óbvias — Pulumi infere dependências da fiação Input/Output, mas efeitos colaterais (propagação IAM