Pulumi Pocket Book — Uplatz
50 in-depth cards • Wide layout • Readable examples • 20-question interview Q&A included
1) What is Pulumi?
Pulumi is an Infrastructure as Code (IaC) platform that lets you define cloud infrastructure using real programming languages (TypeScript/JavaScript, Python, Go, C#, Java, YAML). It manages desired state via stacks, provisions resources through providers (AWS, Azure, GCP, Kubernetes, Cloudflare, etc.), and stores state locally or in a backend (Pulumi Service, S3, Azure Blob, GCS).
# CLI install
curl -fsSL https://get.pulumi.com | sh
pulumi new aws-typescript # scaffold a starter project
2) Core Concepts
Project (code + Pulumi.yaml), Stack (an instance like dev
, prod
), State (resource map), Provider (cloud plugin), and Resource (managed object). Operations: preview
, up
, destroy
.
pulumi stack init dev
pulumi preview
pulumi up -y
pulumi destroy -y
3) Declarative with Real Code
Pulumi resources are declared as objects; dependencies are tracked automatically via inputs/outputs. Use loops, conditionals, functions, and modules to build abstractions—without YAML templating complexity.
// TypeScript example
import * as aws from "@pulumi/aws";
const bucket = new aws.s3.Bucket("site", { website: { indexDocument: "index.html" }});
export const websiteUrl = bucket.websiteEndpoint;
4) Inputs & Outputs
Resource properties are often Input<T>
; computed values are Output<T>
. Use apply
to work with outputs. Don’t escape to real values unless you’re exporting, logging, or passing into other Pulumi inputs.
bucket.websiteEndpoint.apply(url => console.log("URL:", url));
5) State Backends
Default is Pulumi Service (SaaS) with history, RBAC, and state locking. Self-manage via AWS S3+DynamoDB, Azure Blob, or GCS. Choose per security/compliance needs.
pulumi login s3://my-state-bucket
# or
pulumi login
6) Configuration & Secrets
Per-stack config is stored in Pulumi.<stack>.yaml
. Use pulumi config
to set values; mark sensitive values as secrets—encrypted with a KMS or passphrase.
pulumi config set aws:region us-east-1
pulumi config set dbPassword supersecret --secret
7) Providers & Plugins
Providers map to clouds and services (e.g., @pulumi/aws
, @pulumi/azure-native
, @pulumi/kubernetes
). Plugins download automatically when you run pulumi up
.
npm i @pulumi/aws @pulumi/pulumi
8) Stacks & Environments
Create multiple stacks (dev/stage/prod). Use per-stack config for region, sizes, and secrets. Export outputs for CI/CD to consume.
pulumi stack select dev
pulumi config set size small
pulumi stack output websiteUrl
9) Previews, Plans, and Policies
pulumi preview
shows diffs; you can enforce policies with CrossGuard (policy-as-code) to block risky configurations (e.g., public S3 buckets).
pulumi preview --diff
pulumi up --policy-pack ./org-policies
10) Q&A — “Pulumi vs Terraform?”
Answer: Pulumi uses general-purpose languages for IaC (no HCL), enabling rich logic, type checking, and reuse through packages. It also supports YAML. Terraform excels with its huge module registry; Pulumi interoperates via converters and the Terraform Bridge for many providers.
11) TypeScript/JavaScript
Great DX, async/await, NPM ecosystem. Use ts-node or compile. Strong typings from provider packages reduce runtime errors.
import * as aws from "@pulumi/aws";
new aws.ec2.Instance("web", { instanceType: "t3.micro", ami: "ami-..." });
12) Python
Concise syntax; ideal for data teams. Use venv/poetry. Beware of lazy Outputs—use apply
or pass Outputs directly to Inputs.
import pulumi_aws as aws
bucket = aws.s3.Bucket("logs")
13) Go
Fast, static; great for tooling. Outputs are generic types; you’ll use ApplyT
to transform. Module structure matters for larger programs.
bucket.WebsiteEndpoint.ApplyT(func(url string) error { fmt.Println(url); return nil })
14) .NET (C#)
Strong typing; integrates with enterprise stacks. Use NuGet packages (Pulumi.Aws
, etc.). Async pattern with Output
tasks.
var bucket = new Aws.S3.Bucket("site");
15) YAML
For teams that want declarative configs with minimal code. Good for simple stacks; complex logic better in real code or Components.
name: myproj
runtime: yaml
resources:
site:
type: aws:s3:Bucket
16) Project Structure
Keep infra modules small and composable. Use a src/
folder for components, index.ts
to compose, and Pulumi.yaml
at root.
.
├─ Pulumi.yaml
├─ Pulumi.dev.yaml
└─ src/
├─ network.ts
└─ web.ts
17) Config Access
Access config via language bindings; secrets stay encrypted in state. Provide defaults in code.
// TS
import * as pulumi from "@pulumi/pulumi";
const cfg = new pulumi.Config();
const size = cfg.get("size") ?? "small";
18) Stack Outputs
Export values for other stacks or CI/CD. Keep outputs minimal and safe (avoid secrets unless necessary).
export const url = bucket.websiteEndpoint;
19) Error Handling & Debug
Use pulumi up --logtostderr -v=9
for verbose logs. In code, add try/catch
around data lookups. Use pulumi stack history
to inspect changes.
pulumi stack history
pulumi logs -f # for serverless
20) Q&A — “When to choose YAML runtime?”
Answer: For small, declarative stacks or teams unfamiliar with programming languages. For large-scale infra with reuse, pick TS/Python/Go and build Components.
21) AWS Example: Static Website
Create an S3 website bucket, upload content, and export endpoint. Attach CloudFront for CDN later.
import * as aws from "@pulumi/aws";
const site = new aws.s3.Bucket("site", { website:{ indexDocument:"index.html" }});
const obj = new aws.s3.BucketObject("index", { bucket: site, source: new pulumi.asset.FileAsset("index.html"), contentType:"text/html" });
export const url = site.websiteEndpoint;
22) Azure Example: Storage + WebApp
Provision resource group, storage account, and a Linux Web App on Azure App Service.
import * as azure from "@pulumi/azure-native";
const rg = new azure.resources.ResourceGroup("rg");
const plan = new azure.web.AppServicePlan("plan",{ resourceGroupName:rg.name, kind:"Linux", sku:{ name:"B1", tier:"Basic" }, reserved:true });
const app = new azure.web.WebApp("app",{ resourceGroupName:rg.name, serverFarmId: plan.id, siteConfig:{ linuxFxVersion:"DOTNETCORE|7.0" }});
23) GCP Example: GCS + Cloud Run
Push a container to Artifact Registry and deploy via Cloud Run. Pulumi can build images with Docker helpers.
import * as gcp from "@pulumi/gcp";
const bucket = new gcp.storage.Bucket("assets");
const service = new gcp.cloudrunv2.Service("svc",{ location:"us-central1", template:{ containers:[{ image:"gcr.io/PROJECT/IMG:tag" }]}});
24) Kubernetes: Provider & Stack
Point Pulumi at a kubeconfig or create a cluster first (EKS/AKS/GKE). Then deploy manifests or Helm charts declaratively.
import * as k8s from "@pulumi/kubernetes";
const provider = new k8s.Provider("k", { kubeconfig: fs.readFileSync("kubeconfig", "utf8") });
new k8s.helm.v3.Chart("nginx", { chart:"nginx", repo:"bitnami" }, { provider });
25) Cross-Cloud Composition
Mix providers in one program (e.g., AWS S3 + Cloudflare DNS + SendGrid). Languages make wiring outputs together easy.
// export an AWS endpoint; create DNS record in Cloudflare with it
26) Import Existing Resources
Adopt resources created outside Pulumi using import
or pulumi import
to align state without re-creating.
pulumi import aws:s3/bucket:Bucket site my-existing-bucket
27) Taint & Replace
Force recreation of a resource on next update if it’s unhealthy or drifted badly.
pulumi state delete urn::... # or use replaceOnChanges in code
28) Policy as Code (CrossGuard)
Write TypeScript/Go policies to enforce org rules (e.g., no public S3, required tags). Run policies during preview/up.
pulumi policy new aws-typescript
pulumi up --policy-pack ./policies
29) Secrets Providers
Back secrets by KMS (AWS), Key Vault (Azure), KMS (GCP), or passphrase. Rotate providers carefully and re-encrypt stack files.
pulumi stack init --secrets-provider="awskms://arn:aws:kms:..."
30) Q&A — “State in Pulumi Service vs S3?”
Answer: Pulumi Service adds history, RBAC, and concurrency control out-of-box; S3 is self-managed and cheaper but you must manage locking (DynamoDB) and access policies.
31) Component Resources
Encapsulate multiple resources into a reusable class (a “component”) with clean inputs/outputs. Publish internal packages for teams to reuse.
class StaticSite extends pulumi.ComponentResource {
constructor(name, args, opts) {
super("pkg:StaticSite", name, {}, opts);
const bucket = new aws.s3.Bucket(name, { website:{ indexDocument:"index.html" }}, { parent:this });
this.url = bucket.websiteEndpoint;
this.registerOutputs({ url:this.url });
}
}
32) Dynamic Providers
For resources lacking providers, implement CRUD with a dynamic provider. Use sparingly; prefer official providers.
// TS dynamic provider skeleton with create/read/update/delete
33) Automation API
Run Pulumi programs from your own code (build portals/CLIs). Great for on-demand environments and self-service.
import * as auto from "@pulumi/pulumi/automation";
const stack = await auto.LocalWorkspace.createOrSelectStack({ stackName:"dev", projectName:"p", program: myProgram });
34) Multi-Stack Orchestration
Compose stacks (network → data → app). Use StackReference to read outputs across stacks while keeping isolated state.
const net = new pulumi.StackReference("org/network/dev");
export const vpcId = net.getOutput("vpcId");
35) Blue/Green & Canary Infra
Represent versions as separate stacks or prefixes; swap traffic via DNS/Load Balancer resources; roll back by flipping records.
// CloudFront origins A/B and Route53 weighted records
36) GitHub Actions / CI
In CI, run pulumi login
, select stack, set config from secrets, preview, and up on main merges. Use --yes
for non-interactive.
pulumi login
pulumi stack select dev
pulumi preview
pulumi up --yes
37) Drift Detection
Rerun previews regularly; for K8s, enable retainOnDelete
carefully; consider scheduled Automation API previews to alert on drift.
38) Testing (unit/integration)
Unit test with mocks (simulate providers) and assert properties/graph. Integration test in ephemeral stacks and destroy after.
// Node: @pulumi/pulumi/runtime mocks; Python: pulumi.runtime.set_mocks
39) Cost & Tagging
Standardize tags/labels at component level. Add budgets/alerts in cloud providers. Pull estimates via cost tools in CI.
const tags = { project:"shop", env:"dev", owner:"team-x" };
40) Q&A — “How to share components across repos?”
Answer: Publish a package (npm/PyPI/Go module) or a mono-repo workspace. Version components, keep breaking changes documented, and ship examples.
41) Recipe: Serverless API (AWS)
Provision an API Gateway + Lambda with Pulumi; export endpoint. Use code archives or Docker images for Lambdas.
const role = new aws.iam.Role("r",{ assumeRolePolicy: aws.iam.assumeRolePolicyForPrincipal({Service:"lambda.amazonaws.com"})});
const fn = new aws.lambda.Function("fn",{ runtime:"nodejs18.x", role: role.arn, handler:"index.handler", code: new pulumi.asset.AssetArchive({ ".": new pulumi.asset.FileArchive("./lambda") })});
const api = new aws.apigatewayv2.Api("api",{ protocolType:"HTTP" });
new aws.apigatewayv2.Integration("i",{ apiId:api.id, integrationType:"AWS_PROXY", integrationUri: fn.arn });
export const endpoint = api.apiEndpoint;
42) Recipe: EKS Cluster
Create VPC + EKS (or use community component). Then use the generated kubeconfig to deploy workloads with the k8s provider.
// Use @pulumi/eks or aws.eks.Cluster; export kubeconfig
43) Recipe: Azure AKS + ACR
Provision ACR, build & push image, wire AKS to pull images via role assignment, deploy Helm app.
// azure-native.resources, containerservice, containerregistry, roleassignments
44) Recipe: GCP GKE + CloudSQL
Deploy GKE and a private CloudSQL instance; connect via private IP; set secrets via K8s Secret.
45) Migration from Terraform
Import state with pulumi import
or use tf2pulumi to convert HCL → Pulumi TS/Python/Go scaffolding. Validate diffs carefully.
npx tf2pulumi
46) Security Checklist
Use KMS-backed secrets, least-privilege roles for CI, policy packs for guardrails, provider credentials from OIDC, and secret outputs only when necessary.
pulumi config set --secret dbPassword ...
47) Production Checklist
Versioned components, policy packs, drift checks, cost tags, CI previews, change reviews, backup state, and rollback plans (blue/green, stack refs).
pulumi stack export > backup.json
48) Common Pitfalls
Forgetting apply
on Outputs, mixing real values/Outputs incorrectly, leaking secrets in logs, not pinning provider versions, and giant monolithic programs without components.
// Always pass Outputs to Inputs; avoid toString() on secrets
49) Cost-Saving Tips
Use smaller instance types in dev stacks, turn off autoscaling in sandbox, schedule off-hours with Automation API, and prefer serverless where suitable.
// Automation API cron to destroy preview envs nightly
50) Interview Q&A — 20 Practical Questions (Expanded)
1) Pulumi vs Terraform? Pulumi uses real languages with type systems, native loops/functions, and Components; Terraform uses HCL and modules. Both are declarative in effect.
2) What is a Stack? An isolated instance of a project (dev/prod). Each has its own config and state.
3) Inputs vs Outputs? Inputs are desired properties; Outputs are computed results. Transform Outputs with apply
.
4) How are secrets handled? Encrypted at rest in stack files via secrets provider (KMS/Key Vault/GCP KMS/passphrase) and redacted in logs/outputs.
5) What is a ComponentResource? A reusable higher-level construct that groups resources and exposes outputs—your internal module system for IaC.
6) State backends trade-offs? Pulumi Service (managed, RBAC, history) vs self-managed object storage (control, cost, DIY locking/backup).
7) Cross-stack references? Use StackReference
to read outputs from another stack safely (CI/CD-friendly).
8) Policy as code? CrossGuard prevents unsafe patterns (e.g., public buckets, unencrypted databases). Policies run in preview/up.
9) Importing existing infra? pulumi import
maps cloud IDs to Pulumi resources; validate diffs before applying.
10) Handling drift? Regular previews, alerts via Automation API, and explicit replaceOnChanges
for risky props.
11) How to avoid secret leaks? Use secret config, avoid printing outputs, never convert secret outputs to strings except as other secret inputs.
12) Outputs in CI? Use pulumi stack output
(JSON) and pass to deploy steps; keep secrets marked secret.
13) K8s best practices? Separate cluster and workloads into stacks, use Helm/manifest resources, and enable server-side apply where useful.
14) Blue/green strategy? Two stacks or two target groups; shift traffic via DNS/ALB weight; rollback by flipping back.
15) When to use Dynamic Providers? Only when no official provider exists and the resource is small/safe to own. Prefer contributing to providers.
16) Testing Pulumi code? Mocks for unit tests; ephemeral stacks for integration; assert resource graphs and props.
17) Multi-cloud in one program? Yes—instantiate multiple providers and wire outputs (e.g., S3 endpoint to Cloudflare DNS).
18) Handling long-lived creds? Prefer OIDC to cloud providers in CI (no static keys), short-lived tokens, and least privilege.
19) Team structure for IaC? Platform team builds components/policies; product teams compose them; CI enforces reviews and policies.
20) Common mistakes? Treating Outputs as plain values, stacking everything in one file, no policy guardrails, and storing secrets unencrypted.