About this codelab
1. Overview
This lab teaches you how to use Pulumi, an Infrastructure as Code tool to provision and manage Google Cloud resources.
What you will learn
In this lab, you will learn how to do the following:
- Install and configure Pulumi
- Write YAML program to model your infrastructure on Google Cloud
- Provision and manage Cloud resources using Pulumi
- Use pulumi convert to convert YAML program into python program
2. Setup and Requirements
Self-paced environment setup
- Sign-in to the Google Cloud Console and create a new project or reuse an existing one. If you don't already have a Gmail or Google Workspace account, you must create one.
- The Project name is the display name for this project's participants. It is a character string not used by Google APIs. You can update it at any time.
- The Project ID is unique across all Google Cloud projects and is immutable (cannot be changed after it has been set). The Cloud Console auto-generates a unique string; usually you don't care what it is. In most codelabs, you'll need to reference the Project ID (it is typically identified as
PROJECT_ID
). If you don't like the generated ID, you may generate another random one. Alternatively, you can try your own and see if it's available. It cannot be changed after this step and will remain for the duration of the project. - For your information, there is a third value, a Project Number which some APIs use. Learn more about all three of these values in the documentation.
- Next, you'll need to enable billing in the Cloud Console to use Cloud resources/APIs. Running through this codelab shouldn't cost much, if anything at all. To shut down resources so you don't incur billing beyond this tutorial, you can delete the resources you created or delete the whole project. New users of Google Cloud are eligible for the $300 USD Free Trial program.
3. Infrastructure setup
Install and Configure Pulumi
In Cloud Shell, run the following command to install Pulumi
curl -fsSL https://get.pulumi.com | sh
Add Pulumi to the path and view the help message from Pulumi
export PATH=${PATH}:~/.pulumi/bin
# view the help message to verify pulumi runs
pulumi -h
Run the following commands to set the project ID and authorize the access. You need to follow the instructions given by the commands
export PROJECT_ID=$(gcloud config get-value project)
gcloud auth application-default login
In Cloud Shell, create a GCS bucket and use it as backend
gsutil mb gs://pulumi-${PROJECT_ID}
pulumi login gs://pulumi-${PROJECT_ID}
Create a new project
In Cloud Shell, create the project root directory
mkdir pulumi-lab && cd pulumi-lab
Define project file(the entry point to Pulumi)
cat <<EOT > Pulumi.yaml
name: pulumi-lab
description: Try Pulumi
runtime: yaml
main: yaml-repo/
EOT
Define YAML resources
Create directory to hold cloud resource definitions in yaml format
mkdir yaml-repo
Create file yaml-repo/Pulumi.yaml
with the following resource definitions
- Bucket
- IAM Binding
- A text object with the string "Hello World!"
- And some outputs
resources:
# Create a GCP resource (Storage Bucket)
my-bucket:
type: gcp:storage:Bucket
properties:
location: US
website:
mainPageSuffix: index.html
uniformBucketLevelAccess: true
my-bucket-binding:
type: gcp:storage:BucketIAMBinding
properties:
bucket: ${my-bucket.name}
role: "roles/storage.objectViewer"
members: ["allUsers"]
index-object:
type: gcp:storage:BucketObject
properties:
bucket: ${my-bucket}
source:
fn::stringAsset: Hello World!
outputs:
bucketName: ${my-bucket.url}
Deploy the resources
Initialize and config stack
export PULUMI_CONFIG_PASSPHRASE=pulumi-lab
pulumi stack init dev
pulumi config set gcp:project $PROJECT_ID
Check stack config and you should see the key gcp:project with your project Id as the value
pulumi config
At this point the directory structure should look like the following
├── Pulumi.dev.yaml ├── Pulumi.yaml └── yaml-repo └── Pulumi.yaml
Deploy the stack
pulumi up
This command evaluates your program and determines the resource updates to make. First, a preview is shown that outlines the changes that will be made when you the command
(Output)
Previewing update (dev): Downloading plugin gcp v6.44.0: 45.69 MiB / 45.69 MiB [=============] 100.00% 1s Type Name Plan + pulumi:pulumi:Stack pulumi-lab-dev create + ├─ gcp:storage:Bucket my-bucket create + ├─ gcp:storage:BucketObject index-object create + └─ gcp:storage:BucketIAMBinding my-bucket-binding create Outputs: bucketName: output<string> Resources: + 4 to create Do you want to perform this update? [Use arrows to move, type to filter] yes > no details
Select yes and the resources will be provisioned. Your output should look like this
Do you want to perform this update? yes Updating (dev): Type Name Status + pulumi:pulumi:Stack pulumi-lab-dev created (3s) + ├─ gcp:storage:Bucket my-bucket created (1s) + ├─ gcp:storage:BucketObject index-object created (0.78s) + └─ gcp:storage:BucketIAMBinding my-bucket-binding created (5s) Outputs: bucketName: "gs://my-bucket-874aa08" Resources: + 4 created Duration: 11s
Running the following command will print outputs that were defined
pulumi stack output
Run the following command to verify the change
gsutil ls $(pulumi stack output bucketName)
Your output will look like this
(output)
gs://my-bucket-11a9046/index-object-77a5d80
4. Convert YAML to Python
Let's convert the above example to a Pulumi Python program
pulumi convert --language python --out ./py-repo
Inspect the code that was generated in py-repo
cat py-repo/__main__.py
(output)
import pulumi import pulumi_gcp as gcp my_bucket = gcp.storage.Bucket("my-bucket", location="US", website=gcp.storage.BucketWebsiteArgs( main_page_suffix="index.html", ), uniform_bucket_level_access=True) my_bucket_binding = gcp.storage.BucketIAMBinding("my-bucket-binding", bucket=my_bucket.name, role="roles/storage.objectViewer", members=["allUsers"]) index_object = gcp.storage.BucketObject("index-object", bucket=my_bucket.id, source=pulumi.StringAsset("Hello World!")) pulumi.export("bucketName", my_bucket.url) .......
Activate Python virtual environment
source py-repo/bin/activate
Update Pulumi.yaml project file to point to python program. Notice the runtime and the main entry have been changed
cat <<EOT > Pulumi.yaml
name: pulumi-lab
description: Try Pulumi
runtime: python
main: py-repo/
EOT
Try to redeploy the stack and select yes
pulumi up
There should not be any changes and your output should look similar to this
(output)
Previewing update (dev): Type Name Plan pulumi:pulumi:Stack pulumi-lab-dev Resources: 4 unchanged Do you want to perform this update? yes Updating (dev): Type Name Status pulumi:pulumi:Stack pulumi-lab-dev Outputs: bucketName: "gs://my-bucket-c2b49ad" Resources: 4 unchanged Duration: 6s
5. Delete the resources
Delete the resources that were created
pulumi destroy
Your confirmation will look like this
Previewing update (dev): Type Name Plan pulumi:pulumi:Stack pulumi-lab-dev Resources: 4 unchanged Do you want to perform this update? [Use arrows to move, type to filter] yes > no details Do you want to perform this destroy? yes Destroying (dev): Type Name Status - pulumi:pulumi:Stack pulumi-lab-dev deleted - ├─ gcp:storage:BucketIAMBinding my-bucket-binding deleted (5s) - ├─ gcp:storage:BucketObject index-object deleted (1s) - └─ gcp:storage:Bucket my-bucket deleted (0.73s) Outputs: - bucketName: "gs://my-bucket-874aa08" Resources: - 4 deleted Duration: 10s
6. Congratulations!
Congratulations, you finished the lab!