Using Pulumi on GCP
If you haven’t already take a look at the previous post to get Pulumi up and running.
These steps are to get a better understanding of how to use Pulumi with Python and GCP.
I recommend creating a new project in GCP and using that project for demo purposes before going ahead with the rest of these steps.
That way you can simply delete the project later on.
I shall use a project called ’throwaway-01’ in GCP as an example.
Create a throwaway project in GCP
Make sure you also associate a billing account with the project since you won’t be able to utilize all the resources on GCP without it.
gcloud projects create throwaway-01
gcloud alpha billing projects link throwaway-01 --billing-account=#######
Working with the Pulumi examples
Pulumi provides a lot of example projects available on their Github repository - https://github.com/pulumi/examples.git
This repository holds a multitude of projects with support for many Cloud providers; ranging from Azure to DigitalOcean.
The example below will carry out the following deployment.
- Create a new Google Cloud compute instance
- Create a new network
- Create a new firewall
- Install Nginx on the Google Cloud compute instance
git clone https://github.com/pulumi/examples.git
cd gcp-py-instance-nginx
You will find 4 files inside.
- main.py
- Pulumi.yaml
- README.md
- requirements.txt
Lets take a look at these files (I shall disregard the README.md and focus on the other files).
This is the Python code or as Pulumi calls it the ‘program’. In here you write the code to manage your cloud infrastructure.
Pulumi has its own API which you can use in your own programs.
Note
I replaced ‘poc’ with ’nginx’ below to make it more identifiable.
import pulumi
from pulumi_gcp import compute
script = "#!/bin/bash\nsudo touch /tmp/a.txt\nsudo yum install -y nginx\nsudo service nginx start"
addr = compute.address.Address("nginx")
network = compute.Network("nginx")
firewall = compute.Firewall(
"nginx",
network=network.self_link,
allows=[
{
"protocol": "tcp",
"ports": ["22"]
},
{
"protocol": "tcp",
"ports": ["80"]
}
]
)
instance = compute.Instance(
"nginx",
name="nginx",
machine_type="f1-micro",
boot_disk={
"initializeParams": {
"image": "centos-cloud/centos-7-v20190116"
}
},
network_interfaces=[
{
"network": network.id,
"accessConfigs": [{
"nat_ip": addr.address
}]
}
],
metadata_startup_script=script,
)
# Export the DNS name of the bucket
pulumi.export("instance_name", instance.name)
pulumi.export("instance_network", instance.network_interfaces)
pulumi.export("external_ip", addr.address)
This defines the metadata of a project.
name: gcp-instance-nginx
runtime: python
description: Deploy a Nginx Server in a GCP instance
Notice the runtime binding to python.
A list of dependency modules.
pulumi>=2.0.0,<3.0.0
pulumi-gcp>=3.0.0,<4.0.0
Running a deployment
The rest of the steps assume you are in the examples/gcp-py-instance-nginx directory.
Warning
Before you begin make sure you have setup the following.
- A service account in the project on GCP
- Assign roles = { Compute Admin, Service Account User }
- Saved the accounts’ credential JSON locally
- Python >= 3
Create a new stack
pulumi stack init gcp-py-instance-nginx
Created stack 'gcp-py-instance-nginx'
Open the Pulumi console - https://app.pulumi.com/
Where you’ll find the following stack.
Create Python virtual environment
python -m venv venv
source venv/bin/activate
pip install -r requirements.txt
Configure the project
export GOOGLE_PROJECT=<project name>
export GOOGLE_REGION=<region>
export GOOGLE_ZONE=<zone>
export GOOGLE_CREDENTIALS=<path to json credential file>
Deploy changes
pulumi up
Previewing update (gcp-py-instance-nginx):
Type Name Plan
+ pulumi:pulumi:Stack gcp-instance-nginx-gcp-py-instance-nginx create
+ ├─ gcp:compute:Network nginx create
+ ├─ gcp:compute:Address nginx create
+ ├─ gcp:compute:Firewall nginx create
+ └─ gcp:compute:Instance nginx create
Resources:
+ 5 to create
Do you want to perform this update? [Use arrows to move, enter to select, type to filter]
yes
> no
details
Select yes to deploy changes.
You can monitor the deployment via the terminal or through the Pulumi console.
Updating (gcp-py-instance-nginx):
Type Name Status
+ pulumi:pulumi:Stack gcp-instance-nginx-gcp-py-instance-nginx created
+ ├─ gcp:compute:Network nginx created
+ ├─ gcp:compute:Address nginx created
+ ├─ gcp:compute:Firewall nginx created
+ └─ gcp:compute:Instance nginx created
Outputs:
external_ip : "######"
instance_name : "nginx"
instance_network: [
[0]: {
accessConfigs : [
[0]: {
natIp : "########
network_tier : "PREMIUM"
}
]
name : "nic0"
network : "https://www.googleapis.com/compute/v1/projects/#####/global/networks/nginx-87752b8"
networkIp : "#####"
subnetwork : "https://www.googleapis.com/compute/v1/projects/#####/regions/#####/subnetworks/nginx-87752b8"
subnetworkProject: "#####"
}
]
Resources:
+ 5 created
Duration: 1m12s
Permalink: https://app.pulumi.com/###/gcp-instance-nginx/gcp-py-instance-nginx/updates/1
View stack output
pulumi stack output
Current stack outputs (3):
OUTPUT VALUE
external_ip #####
instance_name nginx
instance_network [{accessConfigs":[{"natIp":"#####,"network_tier":"PREMIUM","publicPtrDomainName":""}],"aliasIpRanges":[],"name":"nic0","network":"https://www.googleapis.com/compute/v1/projects/####/global/networks/nginx-87752b8","networkIp":"###","subnetwork":"https://www.googleapis.com/compute/v1/projects/####/regions/#####/subnetworks/nginx-87752b8","subnetworkProject":"######"}]
You’ll notice the properties match the ones defined in the main.py
pulumi.export("instance_name", instance.name)
pulumi.export("instance_network", instance.network_interfaces)
pulumi.export("external_ip", addr.address)
Inspect the external IP
echo $(pulumi stack output external_ip)
Run a curl to test nginx is running
curl $(pulumi stack output external_ip)
######## prints out the nginx content ######
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>Welcome to CentOS</title>
<style rel="stylesheet" type="text/css">
html {
background-image:url(img/html-background.png);
background-color: white;
font-family: "DejaVu Sans", "Liberation Sans", sans-serif;
font-size: 0.85em;
line-height: 1.25em;
margin: 0 4% 0 4%;
}
.....
##########
Destroy the resources deployed in the stack
pulumi destroy -y
Destroying (gcp-py-instance-nginx):
Type Name Status
- pulumi:pulumi:Stack gcp-instance-nginx-gcp-py-instance-nginx deleted
- ├─ gcp:compute:Firewall nginx deleted
- ├─ gcp:compute:Instance nginx deleted
- ├─ gcp:compute:Address nginx deleted
- └─ gcp:compute:Network nginx deleted
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 gcp-py-instance-nginx'.
Cleanup
Remove the stack
pulumi stack rm gcp-py-instance-nginx -y
Stack 'gcp-py-instance-nginx' has been removed!
Remove the Google Cloud project
gcloud projects delete throwaway-01 --quiet