6 min read | by Jordi Prats
Unlike Terraform that uses it's own language to deploy Instrastructure as Code (IaC), with Pulumi we can choose between any of the supported programming languages. For this tutorial we are going to use python deploying an object to a Kubernetes cluster
First we will have to install Pulumi as follows:
$ curl -fsSL https://get.pulumi.com | sh
=== Installing Pulumi v3.16.0 ===
+ Downloading https://get.pulumi.com/releases/sdk/pulumi-v3.16.0-linux-x64.tar.gz...
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 61.3M 100 61.3M 0 0 32.2M 0 0:00:01 0:00:01 --:--:-- 32.1M
+ Extracting to /home/pet2cattle/.pulumi/bin
+ Adding $HOME/.pulumi/bin to $PATH in /home/pet2cattle/.bashrc
=== Pulumi is now installed! 🍹 ===
+ Please restart your shell or add /home/pet2cattle/.pulumi/bin to your $PATH
+ Get started with Pulumi: https://www.pulumi.com/docs/quickstart
With Pulumi we can choose between several backends to store it's state, being Pulumi's cloud service the default. We are going to use it for simplicity's sake, so we'll have to register using the following URL:
https://app.pulumi.com/account/tokens
Once registered we'll have to login using the CLI and the access token we will be able to create once registered:
$ pulumi login
Manage your Pulumi stacks by logging in.
Run `pulumi login --help` for alternative login options.
Enter your access token from https://app.pulumi.com/account/tokens
or hit <ENTER> to log in using your browser :
Welcome to Pulumi!
Pulumi helps you create, deploy, and manage infrastructure on any cloud using
your favorite language. You can get started today with Pulumi at:
https://www.pulumi.com/docs/get-started/
Tip of the day: Resources you create with Pulumi are given unique names (a randomly
generated suffix) by default. To learn more about auto-naming or customizing resource
names see https://www.pulumi.com/docs/intro/concepts/resources/#autonaming.
Logged in to pulumi.com as jordiprats (https://app.pulumi.com/jordiprats)
To be able to create the first python project using Pulumi we'll need to have installed the following dependencies:
On Debian/Ubuntu we can just run:
sudo apt install python3.8 python3.8-venv
At this point we are all set up to be able to init a new project using pulumi new. Since we want to have installed the dependencies to deploy to Kubernetes using Python we are going to use kubernetes-python. Using the -n flag we telling Pulumi how we want to name our new project:
$ pulumi new kubernetes-python -n simple-example
This command will walk you through creating a new Pulumi project.
Enter a value or leave blank to accept the (default), and press <ENTER>.
Press ^C at any time to quit.
project description: (A minimal Python Pulumi program)
Created project 'simple-example'
Please enter your desired stack name.
To create a stack in an organization, use the format <org-name>/<stack-name> (e.g. `acmecorp/dev`).
stack name: (dev)
Created stack 'dev'
Creating virtual environment...
Finished creating virtual environment
(...)
To perform an initial deployment, run 'pulumi up'
By default we will have an example on how to push a Deployment, but as a first step we are going to create a Namespace using the following code:
import pulumi
from pulumi_kubernetes.core.v1 import Namespace
config = pulumi.Config()
demoNS = Namespace("test1")
pulumi.export("demoNS", demoNS.metadata.apply(lambda m: m.name))
This code tells pulumi to deploy a namespace tha it's resource name is going to be test1, we can check what is going to do using pulumi preview (which is equivalent to terraform plan)
$ pulumi preview
Previewing update (dev)
View Live: https://app.pulumi.com/jordiprats/simple-example/dev/previews/f08d0489-26fb-49aa-9054-1de352d2ea36
Type Name Plan
+ pulumi:pulumi:Stack simple-example-dev create
+ └─ kubernetes:core/v1:Namespace test1 create
Resources:
+ 2 to create
Using pulumi up it's going to apply it (equivalent to terraform apply)
$ pulumi up
Previewing update (dev)
View Live: https://app.pulumi.com/jordiprats/simple-example/dev/previews/3d81b12e-4933-4534-9823-6fe748ca7a88
Type Name Plan
+ pulumi:pulumi:Stack simple-example-dev create
+ └─ kubernetes:core/v1:Namespace test1 create
Resources:
+ 2 to create
Do you want to perform this update? yes
Updating (dev)
View Live: https://app.pulumi.com/jordiprats/simple-example/dev/updates/1
Type Name Status
+ pulumi:pulumi:Stack simple-example-dev created
+ └─ kubernetes:core/v1:Namespace test1 created
Outputs:
demoNS: "test1-78gjwsog"
Resources:
+ 2 created
Duration: 6s
If we check the list of namespaces we will see that it have created a namespace named after pulumi's resource but not exactly what we have called it:
$ kubectl get ns
NAME STATUS AGE
(...)
test1-78gjwsog Active 23s
$ kubectl describe ns test1-78gjwsog
Name: test1-78gjwsog
Labels: app.kubernetes.io/managed-by=pulumi
kubernetes.io/metadata.name=test1-78gjwsog
Annotations: pulumi.com/autonamed: true
Status: Active
No resource quota.
No LimitRange resource.
We can destroy what we have just created by using pulumi destroy (this command is the same we would use with terraform)
$ pulumi destroy
Previewing destroy (dev)
View Live: https://app.pulumi.com/jordiprats/simple-example/dev/previews/62fdf19d-32af-493e-8e88-1d30bb7b5a34
Type Name Plan
- pulumi:pulumi:Stack simple-example-dev delete
- └─ kubernetes:core/v1:Namespace test1 delete
Outputs:
- demoNS: "test1-78gjwsog"
Resources:
- 2 to delete
Do you want to perform this destroy? yes
Destroying (dev)
View Live: https://app.pulumi.com/jordiprats/simple-example/dev/updates/2
Type Name Status
- pulumi:pulumi:Stack simple-example-dev deleted
- └─ kubernetes:core/v1:Namespace test1 deleted
Outputs:
- demoNS: "test1-78gjwsog"
Resources:
- 2 deleted
Duration: 11s
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 dev'.
To be able to specify the exact name of the resource we will have to set it's metadata, just like we do with Kubernetes when we create the YAML definition of the object. The code that does it looks like this:
import pulumi
from pulumi_kubernetes.core.v1 import Namespace
config = pulumi.Config()
demoNS = Namespace("test1",
metadata={
"name": "test1"
})
pulumi.export("demoNS", demoNS.metadata.apply(lambda m: m.name))
If we apply this code:
$ pulumi up
Previewing update (dev)
View Live: https://app.pulumi.com/jordiprats/simple-example/dev/previews/4402bdd0-45d6-4642-94d2-8d06e8a83982
Type Name Plan
+ pulumi:pulumi:Stack simple-example-dev create
+ └─ kubernetes:core/v1:Namespace test1 create
Resources:
+ 2 to create
Do you want to perform this update? yes
Updating (dev)
View Live: https://app.pulumi.com/jordiprats/simple-example/dev/updates/5
Type Name Status
+ pulumi:pulumi:Stack simple-example-dev created
+ └─ kubernetes:core/v1:Namespace test1 created
Outputs:
demoNS: "test1"
Resources:
+ 2 created
Duration: 6s
We will be able to see that now the namespace doesn't have an auto-generated name but the same exact name we have definied:
$ kubectl get ns
NAME STATUS AGE
(...)
test1 Active 19s
$ kubectl describe ns test1
Name: test1
Labels: app.kubernetes.io/managed-by=pulumi
kubernetes.io/metadata.name=test1
Annotations: <none>
Status: Active
No resource quota.
No LimitRange resource.
You can also find this example's code on this GitHub repo
Posted on 02/11/2021