Introduction
Pulumi is a modern Infrastructure as Code (IaC) platform and a powerful alternative to Terraform. It handles Kubernetes resources particularly well and allows you to write infrastructure code using familiar programming languages like TypeScript, Python, or Go.
1. Install Pulumi
brew install pulumi
pulumi version
# v3.116.1 (2024) - Check for latest version at pulumi.com
2. Working with Stacks
Stacks in Pulumi represent different instances of your infrastructure (dev, stage, prod).
➜ marquez (main) ✔ pulumi stack ls
NAME LAST UPDATE RESOURCE COUNT
dev 2 months ago 19
prod n/a n/a
stage* 1 day ago 19
➜ marquez (main) ✔ pulumi stack select dev
➜ marquez (main) ✔ pulumi stack ls
NAME LAST UPDATE RESOURCE COUNT
dev* 2 months ago 19
prod n/a n/a
stage 1 day ago 19
pulumi stack => show ‘s the current stack resource
➜ marquez (mkang/prefect-stage) ✔ p stack
Current stack is dev:
Managed by One-Concern-C02D25JPMD6R-mkang.local
Last updated: 2 minutes ago (2024-05-17 10:40:06.455933 -0700 PDT)
Pulumi version used: v3.116.1
Current stack resources (19):
TYPE NAME
pulumi:pulumi:Stack marquez-dev
├─ kubernetes:helm.sh/v3:Chart default
│ ├─ kubernetes:core/v1:ConfigMap marquez/default-marquez-config
│ ├─ kubernetes:core/v1:Service marquez/default-marquez
│ ├─ kubernetes:core/v1:Service marquez/default-marquez-web
│ ├─ kubernetes:networking.k8s.io/v1:Ingress marquez/default-marquez
│ ├─ kubernetes:apps/v1:Deployment marquez/default-marquez-web
│ └─ kubernetes:apps/v1:Deployment marquez/default-marquez
├─ kubernetes:core/v1:Namespace default
├─ gcp:sql/databaseInstance:DatabaseInstance default
├─ gcp:serviceAccount/account:Account default
├─ gcp:serviceAccount/iAMBinding:IAMBinding default
├─ kubernetes:core/v1:ServiceAccount default
├─ gcp:projects/iAMMember:IAMMember cloudsql-admin
├─ gcp:sql/database:Database default
├─ gcp:sql/user:User default
├─ kubernetes:core/v1:Secret default
├─ pulumi:providers:kubernetes default_4_11_0
└─ pulumi:providers:gcp default_6_49_0
Current stack outputs (0):
No output values currently in this stack
Use `pulumi stack select` to change stack; `pulumi stack ls` lists known ones
I changed my kubernetes context name, so it was causing problems
➜ marquez (main) ✔ k config get-contexts
CURRENT NAME CLUSTER AUTHINFO NAMESPACE
docker-desktop docker-desktop docker-desktop
* gke_my-stage_my_my-stage-my gke_my-stage_my_my-stage-my gke_my-stage_my_my-stage-my marquez
my-dev gke_my-dev_my_my-dev-my gke_my-dev_my_my-dev-my prefect
my-prod gke_my-prod_my_my-prod-my gke_my-prod_my_my-prod-my dna-api
➜ marquez (main) ✔ k config rename-context my-dev gke_my-dev_my_my-dev-my
Context "my-dev" renamed to "gke_my-dev_my_my-dev-my".
➜ marquez (main) ✔ k config get-contexts
CURRENT NAME CLUSTER AUTHINFO NAMESPACE
docker-desktop docker-desktop docker-desktop
gke_my-dev_my_my-dev-my gke_my-dev_my_my-dev-my gke_my-dev_my_my-dev-my prefect
* gke_my-stage_my_my-stage-my gke_my-stage_my_my-stage-my gke_my-stage_my_my-stage-my marquez
my-prod gke_my-prod_my_my-prod-my gke_my-prod_my_my-prod-my dna-api
2.1 Making new stack
pulumi stack init stage
This will create Pulumi.stage.yaml file
2.2 Removing stack
pulumi stack rm stage
3. Some setup
Enter the passphrase to unlock config/secrets
(set PULUMI_CONFIG_PASSPHRASE or PULUMI_CONFIG_PASSPHRASE_FILE to remember)
I added this in my .rc file
export PULUMI_CONFIG_PASSPHRASE=''
4. Preview the changes
➜ marquez (main) ✔ pulumi preview
Previewing update (dev):
Downloading plugin: 37.89 MiB / 37.89 MiB [=========================] 100.00% 0s
[resource plugin kubernetes-4.9.0] installing
Type Name Plan
pulumi:pulumi:Stack marquez-dev
Resources:
17 unchanged
➜ marquez (main) ✔ pulumi preview --diff
Previewing update (dev):
pulumi:pulumi:Stack: (same)
[urn=urn:pulumi:dev::marquez::pulumi:pulumi:Stack::marquez-dev]
Resources:
17 unchanged
pulumi preview --diff
5. pulumi up
➜ marquez (main) ✔ p up
Previewing update (stage):
Type Name Plan
+ pulumi:pulumi:Stack marquez-stage create
+ ├─ kubernetes:helm.sh/v3:Chart default create
+ │ ├─ kubernetes:core/v1:ConfigMap marquez/default-marquez-config create
+ │ ├─ kubernetes:apps/v1:Deployment marquez/default-marquez create
+ │ ├─ kubernetes:core/v1:Service marquez/default-marquez create
+ │ ├─ kubernetes:core/v1:Service marquez/default-marquez-web create
+ │ ├─ kubernetes:networking.k8s.io/v1:Ingress marquez/default-marquez create
+ │ └─ kubernetes:apps/v1:Deployment marquez/default-marquez-web create
+ ├─ kubernetes:core/v1:Namespace default create
+ ├─ gcp:serviceAccount:Account default create
+ ├─ gcp:sql:DatabaseInstance default create
+ ├─ gcp:serviceAccount:IAMBinding default create
+ ├─ gcp:sql:Database default create
+ ├─ gcp:projects:IAMMember cloudsql-admin create
+ ├─ kubernetes:core/v1:ServiceAccount default create
+ ├─ gcp:sql:User default create
+ └─ kubernetes:core/v1:Secret default create
Resources:
+ 17 to create
Do you want to perform this update? yes
Updating (stage):
Type Name Status Info
+ pulumi:pulumi:Stack marquez-stage **creating failed (671s)** 1 error
+ ├─ kubernetes:helm.sh/v3:Chart default created
+ │ ├─ kubernetes:core/v1:Service marquez/default-marquez created (39s)
+ │ ├─ kubernetes:core/v1:Service marquez/default-marquez-web created (32s)
+ │ ├─ kubernetes:apps/v1:Deployment marquez/default-marquez **creating failed** 1 error
+ │ ├─ kubernetes:core/v1:ConfigMap marquez/default-marquez-config created (1s)
+ │ ├─ kubernetes:networking.k8s.io/v1:Ingress marquez/default-marquez created (29s)
+ │ └─ kubernetes:apps/v1:Deployment marquez/default-marquez-web created (22s)
+ ├─ kubernetes:core/v1:Namespace default created (1s)
+ ├─ gcp:serviceAccount:Account default created (3s)
+ ├─ gcp:sql:DatabaseInstance default created (664s)
+ ├─ gcp:serviceAccount:IAMBinding default created (4s)
+ ├─ gcp:projects:IAMMember cloudsql-admin created (9s)
+ └─ kubernetes:core/v1:ServiceAccount default created (1s)
Diagnostics:
pulumi:pulumi:Stack (marquez-stage):
error: update failed
kubernetes:apps/v1:Deployment (marquez/default-marquez):
error: 3 errors occurred:
* resource "urn:pulumi:stage::marquez::kubernetes:helm.sh/v3:Chart$kubernetes:apps/v1:Deployment::marquez/default-marquez" was successfully created, but the Kubernetes API server reported that it failed to fully initialize or become live: 'default-marquez' timed out waiting to be Ready
* Minimum number of live Pods was not attained
* [Pod marquez/default-marquez-5f9cdd5bc4-hhcqf]: containers with unready status: [marquez cloud-sql-proxy] -- [CreateContainerConfigError] secret "marquez-pg-creds" not found -- [CreateContainerConfigError] secret "marquez-pg-creds" not found
Resources:
+ 13 created
Duration: 11m13s
6. pulumi down
➜ marquez (mkang/marquez-improve) ✔ p down
Previewing destroy (stage):
Type Name Plan
- pulumi:pulumi:Stack marquez-stage delete
- ├─ kubernetes:helm.sh/v3:Chart default delete
- │ ├─ kubernetes:core/v1:Service marquez/default-marquez-web delete
- │ ├─ kubernetes:apps/v1:Deployment marquez/default-marquez-web delete
- │ ├─ kubernetes:apps/v1:Deployment marquez/default-marquez delete
- │ ├─ kubernetes:core/v1:ConfigMap marquez/default-marquez-config delete
- │ ├─ kubernetes:networking.k8s.io/v1:Ingress marquez/default-marquez delete
- │ └─ kubernetes:core/v1:Service marquez/default-marquez delete
- ├─ gcp:serviceAccount:IAMBinding default delete
- ├─ gcp:sql:DatabaseInstance default delete
- ├─ kubernetes:core/v1:Secret default delete
- ├─ kubernetes:core/v1:ServiceAccount default delete
- ├─ gcp:serviceAccount:Account default delete
- ├─ gcp:sql:User default delete
- ├─ gcp:projects:IAMMember cloudsql-admin delete
- ├─ kubernetes:core/v1:Namespace default delete
- └─ gcp:sql:Database default delete
Resources:
- 17 to delete
Do you want to perform this destroy? yes
Destroying (stage):
Type Name Status Info
Type Name Status Info
pulumi:pulumi:Stack marquez-stage **failed** 1 error
- ├─ kubernetes:core/v1:Secret default deleted (1s)
- ├─ gcp:sql:Database default deleted (6s)
- ├─ gcp:sql:User default deleted (7s)
- ├─ kubernetes:core/v1:ServiceAccount default deleted (3s)
- ├─ gcp:serviceAccount:IAMBinding default deleted (7s)
- ├─ gcp:projects:IAMMember cloudsql-admin deleted (8s)
- ├─ kubernetes:helm.sh/v3:Chart default deleted (0.58s)
- │ ├─ kubernetes:core/v1:Service marquez/default-marquez deleted (4s)
- │ ├─ kubernetes:core/v1:Service marquez/default-marquez-web deleted (4s)
- │ ├─ kubernetes:networking.k8s.io/v1:Ingress marquez/default-marquez deleted (5s)
- │ ├─ kubernetes:apps/v1:Deployment marquez/default-marquez deleted (37s)
- │ ├─ kubernetes:core/v1:ConfigMap marquez/default-marquez-config deleted (1s)
- │ └─ kubernetes:apps/v1:Deployment marquez/default-marquez-web deleted (37s)
- ├─ gcp:sql:DatabaseInstance default **deleting failed** 1 error
- ├─ kubernetes:core/v1:Namespace default deleted (8s)
- └─ gcp:serviceAccount:Account default deleted (1s)
Diagnostics:
pulumi:pulumi:Stack (marquez-stage):
error: update failed
gcp:sql:DatabaseInstance (default):
error: deleting urn:pulumi:stage::marquez::gcp:sql/databaseInstance:DatabaseInstance::default: 1 error occurred:
* Error, failed to delete instance because deletion_protection is set to true. Set it to false to proceed with instance deletion
Resources:
- 15 deleted
Duration: 49s
➜ marquez (mkang/marquez-improve) ✔
➜ marquez (mkang/marquez-improve) ✔
➜ marquez (mkang/marquez-improve) ✔ gst
On branch mkang/marquez-improve
nothing to commit, working tree clean
➜ marquez (mkang/marquez-improve) ✔ p down
^C
➜ marquez (mkang/marquez-improve) ✔
➜ marquez (mkang/marquez-improve) ✔
➜ marquez (mkang/marquez-improve) ✔
➜ marquez (mkang/marquez-improve) ✔ p stack
Current stack is stage:
Managed by One-Concern-C02D25JPMD6R-mkang.local
Last updated: 1 minute ago (2024-05-17 11:10:02.880188 -0700 PDT)
Pulumi version used: v3.116.1
Current stack resources (4):
TYPE NAME
pulumi:pulumi:Stack marquez-stage
├─ gcp:sql/databaseInstance:DatabaseInstance default
├─ pulumi:providers:kubernetes default_4_11_0
└─ pulumi:providers:gcp default_6_49_0
Current stack outputs (0):
No output values currently in this stack
Use `pulumi stack select` to change stack; `pulumi stack ls` lists known ones
➜ marquez (mkang/marquez-improve) ✔
➜ marquez (mkang/marquez-improve) ✔
➜ marquez (mkang/marquez-improve) ✔
➜ marquez (mkang/marquez-improve) ✔ p stack
Current stack is stage:
Managed by One-Concern-C02D25JPMD6R-mkang.local
Last updated: 6 minutes ago (2024-05-17 11:10:02.880188 -0700 PDT)
Pulumi version used: v3.116.1
Current stack resources (4):
TYPE NAME
pulumi:pulumi:Stack marquez-stage
├─ gcp:sql/databaseInstance:DatabaseInstance default
├─ pulumi:providers:kubernetes default_4_11_0
└─ pulumi:providers:gcp default_6_49_0
Current stack outputs (0):
No output values currently in this stack
Use `pulumi stack select` to change stack; `pulumi stack ls` lists known ones
➜ marquez (mkang/marquez-improve) ✔ p down
Previewing destroy (stage):
Type Name Plan
- pulumi:pulumi:Stack marquez-stage delete
- └─ gcp:sql:DatabaseInstance default delete
Resources:
- 2 to delete
Do you want to perform this destroy? no
confirmation declined, not proceeding with the destroy
➜ marquez (mkang/marquez-improve) ✔ p refresh
Previewing refresh (stage):
Type Name Plan
pulumi:pulumi:Stack marquez-stage
- └─ gcp:sql:DatabaseInstance default delete
Resources:
- 1 to delete
1 unchanged
Do you want to perform this refresh?
No resources will be modified as part of this refresh; just your stack's state will be.
yes
Refreshing (stage):
Type Name Status
pulumi:pulumi:Stack marquez-stage
- └─ gcp:sql:DatabaseInstance default deleted (1s)
Resources:
- 1 deleted
1 unchanged
Duration: 2s
➜ marquez (mkang/marquez-improve) ✔ p down
Previewing destroy (stage):
Type Name Plan
- pulumi:pulumi:Stack marquez-stage delete
Resources:
- 1 to delete
Do you want to perform this destroy? yes
Destroying (stage):
Type Name Status
- pulumi:pulumi:Stack marquez-stage deleted (1s)
Resources:
- 1 deleted
Duration: 4s
The resources in the stack have been deleted, but the history and configuration associated with the stack are still maintained.
If you want to remove the stack completely, run `pulumi stack rm stage`.
➜ marquez (mkang/marquez-improve) ✔ p down
Previewing destroy (stage):
Resources:
Do you want to perform this destroy? yes
Destroying (stage):
Resources:
Duration: 1s
The resources in the stack have been deleted, but the history and configuration associated with the stack are still maintained.
If you want to remove the stack completely, run `pulumi stack rm stage`.
7. pulumi refresh
- Get the latest changes of the infrastructure and update the current pulumi status
➜ marquez (main) ✗ p refresh
Previewing refresh (dev):
Type Name Plan
pulumi:pulumi:Stack marquez-dev
- └─ gcp:sql:DatabaseInstance default delete
Resources:
- 1 to delete
1 unchanged
Do you want to perform this refresh?
No resources will be modified as part of this refresh; just your stack's state will be.
yes
Refreshing (dev):
Type Name Status
pulumi:pulumi:Stack marquez-dev
- └─ gcp:sql:DatabaseInstance default deleted (1s)
Resources:
- 1 deleted
1 unchanged
Duration: 2s
➜ marquez (main) ✔ p refresh
? Options for pending CREATE of urn:pulumi:stage::marquez::kubernetes:helm.sh/v3:Chart$kubernetes:core/v1:Service::marquez/default-marquez clear (the CREATE failed; remove the pending CREATE)
? Options for pending CREATE of urn:pulumi:stage::marquez::kubernetes:helm.sh/v3:Chart$kubernetes:core/v1:Service::marquez/default-marquez-web clear (the CREATE failed; remove the pending CREATE)
Previewing refresh (stage):
Type Name Plan Info
pulumi:pulumi:Stack marquez-stage
├─ gcp:sql:User default
├─ kubernetes:helm.sh/v3:Chart default
├─ gcp:serviceAccount:Account default
~ ├─ gcp:sql:DatabaseInstance default update [diff: ~settings]
├─ kubernetes:core/v1:Namespace default
└─ gcp:sql:Database default
Resources:
~ 1 to update
6 unchanged
Do you want to perform this refresh?
No resources will be modified as part of this refresh; just your stack's state will be.
yes
Refreshing (stage):
Type Name Status Info
pulumi:pulumi:Stack marquez-stage
├─ gcp:sql:User default
├─ gcp:sql:Database default
├─ kubernetes:core/v1:Namespace default
~ ├─ gcp:sql:DatabaseInstance default updated (1s) [diff: ~settings]
├─ gcp:serviceAccount:Account default
└─ kubernetes:helm.sh/v3:Chart default
Resources:
~ 1 updated
6 unchanged
Duration: 2s
8. Other
pulumi cancel
pulumi config set xxx --secret
9. Surgery
pulumi stack export as yaml file and import back in
keycloak (main) ✔ p stack export --show-secrets --file keycloack-dev.yaml
➜ keycloak (main) ✗ p down
Previewing destroy (my-dev-my):
Type Name Plan
- pulumi:pulumi:Stack keycloak-my-dev-my delete
- ├─ gcp:sql:User keycloak-myoncern-user delete
- ├─ gcp:serviceAccount:Account default delete
- ├─ kubernetes:core/v1:Secret keycloak-pg-creds delete
- ├─ gcp:serviceAccount:IAMBinding default delete
- ├─ gcp:sql:DatabaseInstance keycloak-dev-pg-db delete
- ├─ random:index:RandomPassword keycloak-myoncern-password delete
- ├─ kubernetes:core/v1:Secret oauth-creds delete
- ├─ kubernetes:core/v1:Secret cluster-ca delete
- ├─ kubernetes:core/v1:ServiceAccount keycloak delete
- ├─ random:index:RandomPassword keycloak-postgres-password delete
- ├─ gcp:projects:IAMMember cloudsql-editor delete
- ├─ kubernetes:core/v1:Secret keycloak-db-auth delete
- ├─ kubernetes:core/v1:Secret keycloak-http delete
- └─ kubernetes:core/v1:Namespace keycloak delete
Outputs:
- keycloakDBName: "keycloak-dev-pg-db-141347"
Resources:
- 15 to delete
Do you want to perform this destroy? yes
Destroying (my-dev-my):
Type Name Status Info
pulumi:pulumi:Stack keycloak-my-dev-my **failed** 1 error
- └─ gcp:sql:User keycloak-myoncern-user **deleting failed** 1 error
Diagnostics:
gcp:sql:User (keycloak-myoncern-user):
error: deleting urn:pulumi:my-dev-my::keycloak::gcp:sql/user:User::keycloak-myoncern-user: 1 error occurred:
* Error, failed to deleteuser myoncern in instance keycloak-dev-pg-db-141347: googleapi: Error 403: The client is not authorized to make this request., notAuthorized
pulumi:pulumi:Stack (keycloak-my-dev-my):
error: update failed
Resources:
Duration: 3s
## delete the resouce called "urn:pulumi:my-dev-my::keycloak::gcp:sql/user:User::keycloak-myoncern-user" in the keycloak-dev.yaml file and run the import below
➜ keycloak (main) ✗ p stack import --file keycloack-dev.yaml
Import complete.
10. manipulating the resources
pulumi stack --show-urns
pulumi state delete "urn:pulumi:lunar::products-helm::kubernetes:helm.sh/v3:Release::my-app"
pulumi import --yes cloudflare:index/zone:Zone zone-greyrhino-ai \
61652a8db95f42f0314341ca6046e894
11. to get the cloudflare id for zones and dns
To get the id of each resource, I used this CLI tool called flarectl https://github.com/cloudflare/cloudflare-go/tree/v0/cmd/flarectl
flarectl z list
ID | NAME | PLAN | STATUS
-----------------------------------+----------------+--------------+---------
61652a8d123123dsfs4341ca6046e894 | example1.com | Free Website | active
0052235293f6asdfasd3f673e77d447b | example2.com | Free Website | active
4aeaadee6a665a7c4508745b4b9c4cb9 | exampel3.com | Free Website | active
flarectl d list --zone example1.com
ID | TYPE | NAME | CONTENT | PROXIED | TTL
-----------------------------------+-------+------------------+------------------------------------------------------------------------+---------+------
16d226272sfasdfscfadd99fa9c4269181a | A | example1.com | 103.169.142.0 | true | 1
338a23f66ca89ddasdfasdf3fc775654eb | A | www.example1.com | 103.169.142.0 | true | 1
d165748598dcc85f0576bb7b68513dc1 | CNAME | pay.example1.com | paylinks.commerce.godaddy.com | true | 1
33500b0a9eda3d60b9ae8826673b9a26 | MX | example1.com | 10 alt4.aspmx.l.google.com | false | 1
b080b32780d93c0a3c92d05eccf83902 | MX | example1.com | 10 alt3.aspmx.l.google.com | false | 1
961aef33504d52c3fb526dd345cc4e27 | MX | example1.com | 5 alt2.aspmx.l.google.com | false | 1
f93a5d6999c04ab36b9d5a336528ec4c | MX | example1.com | 5 alt1.aspmx.l.google.com | false | 1
45e19cbd0f6286931a3bfc3d48b3e58e | MX | example1.com | 1 aspmx.l.google.com | false | 1
Related Infrastructure as Code Guides
Master modern infrastructure automation with these related articles:
- Ansible Vault Tutorial: Production Environment Security - Secure your infrastructure secrets and credentials (Korean)
- Private Helm Repository with ChartMuseum - Kubernetes package management and deployment automation
- Redis in Kubernetes: Production Deployment Guide - Deploy stateful services with infrastructure as code
🚀 Browse all Pulumi articles and DevOps guides for more automation patterns.