Web Analytics
Posted on:April 22, 2024 at 09:00 AM

Pulumi Infrastructure as Code: Complete Setup Guide with TypeScript

Pulumi Infrastructure as Code: Complete Setup Guide with TypeScript

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

Master modern infrastructure automation with these related articles:

🚀 Browse all Pulumi articles and DevOps guides for more automation patterns.

Related Posts