Pulumi Pocket Book

Pulumi Pocket Book — Uplatz

50 in-depth cards • Wide layout • Readable examples • 20-question interview Q&A included

Section 1 — Foundations

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.

Section 2 — Language Flavors & Basic Patterns

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.

Section 3 — Multi-Cloud & Kubernetes Essentials

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.

Section 4 — Advanced Patterns, Components & CI/CD

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.

Section 5 — Practical Recipes, Checklists & Interview Q&A

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.