In this chapter, we will develop a simple Pulumi program that creates a single Exoscale instance with a basic web server running on it. Our goal is to become acquainted with the Pulumi CLI, understand the structure of a Pulumi program, and learn how to create multiple stacks and override default values.
Pulumi is an open-source infrastructure-as-code tool for creating, deploying and managing cloud infrastructure. Pulumi works with traditional infrastructures like VMs, networks, and databases and modern architectures, including containers, Kubernetes clusters, and serverless functions. Pulumi supports dozens of public, private, and hybrid cloud service providers.
Pulumi is a multi-language infrastructure as Code tool using imperative languages to create a declarative infrastructure description.
You have a wide range of programming languages available, and you can use the one you and your team are the most comfortable with. Currently, (6/2023) Pulumi supports the following languages:
-
Node.js (JavaScript / TypeScript)
-
Python
-
Go
-
Java
-
.NET (C#, VB, F#)
-
YAML
The workshop examples are written in typescript
and Go
, but feel free to use the language you are most comfortable
with.
Run exo config
and enter the provided API key, secret key, account name and the default zone (at-vie-1
). Your
prompt should look similar to this:
No Exoscale CLI configuration found
In order to set up your configuration profile, you will need to retrieve
Exoscale API credentials from your organization's IAM:
https://portal.exoscale.com/iam/api-keys
[+] API Key [none]: xxx
[+] Secret Key [none]: yyy
[+] Account name [none]: <account-name>
[+] Name [none]: <account-name>
✔ at-vie-1
Now you can test with exo zone
if the configuration is correct.
You should see something like this:
┼──────────┼
│ NAME │
┼──────────┼
│ at-vie-1 │
│ at-vie-2 │
│ bg-sof-1 │
│ ch-dk-2 │
│ ch-gva-2 │
│ de-fra-1 │
┼──────────┼
If you run Pulumi for the first time, you will be asked to log in. Follow the instructions on the screen to login. You may need to create an account first, don't worry it is free.
To initialize a new Pulumi project, run pulumi new
and select from all the available templates the typescript
. Of
course, you can use any other language you want.
pulumi new
You will be guided through a wizard to create a new Pulumi project. You can use the following values:
project name (00-hello-exoscale-world): 00-hello-exoscale-world
project description (A minimal TypeScript Pulumi program):
Created project '00-hello-exoscale-world'
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): dev
...
To integrate the Exoscale provider into your project, the steps will vary based on the programming language you're using. For detailed instructions, refer to the Pulumi Exoscale Provider documentation.
I am using typescript
for this workshop, so I need to install the Exoscale provider with npm
.
npm install @pulumiverse/exoscale --save-dev
Now, let's begin adding resources to our Pulumi program, starting with a basic compute instance.
For a comprehensive list of available options, consult the Pulumi Exoscale Provider documentation or utilize your Intellisense for code completion.
To gather more information about the available images and instance types, execute the following 'exo' commands.
exo compute instance-type list
exo compute instance-template list
Please use and Ubuntu 23.04
image and a standard.medium
instance type.
This is the user data, you can use to install a simple webserver on the compute instance.
#cloud-config
package_update: true
packages:
- python3
write_files:
- path: /home/ubuntu/index.html
content: |
Hello, World from Exoscale!
runcmd:
- cd /home/ubuntu
- nohup python3 -m http.server 8080 &
Instance types are written in the format "FAMILY.SIZE" (e.g. standard.small).
If you got stuck, you can have a look at the solution.
Before you can run
pulumi up
, you need to set the Exoscale API key and secret as environment variables.EXOSCALE_API_KEY
andEXOSCALE_API_SECRET
.
pulumi up
This command will show you a preview of all the resources and asks you if you want to deploy them. You can run dedicated commands to see the preview or to deploy the resources.
pulumi preview
# or
pulumi up
To print information about the resources, you need to export the variables in your Pulumi program. In my case, I want to export the public IP of the compute instance.
export const publicIp = simpleVM.publicIpAddress
Run pulumi up
again to see the public IP of the compute instance.
pulumi up
# omiied for brevity
Outputs:
+ publicIp: "194.182.187.163"
Execute the curl
command to see if the webserver is running.
curl 194.182.187.163:8080
curl: (28) Failed to connect to 194.182.187.163 port 8080 after 75006 ms: Couldn't connect to server
Bummer, we can't reach the webserver. Why? Because we didn't open the port 80 in the firewall. Let's fix this in the code!
Add a security group and security group rule to the Pulumi program, and attach the security group to the compute instance.
After applying the changes, you should be able to reach the webserver.
➜ curl 194.182.185.5:8080
Hello, World from Exoscale!
Now that we're satisfied with our current stack, we should consider deploying our web server to a production environment. But what if we wish to deploy with varied outputs or in a different zone?
This is where the concept of 'stacks' becomes invaluable. Stacks allow us to manage multiple deployments of the same Pulumi program, each with its unique configurations. This flexibility means we can assign distinct configuration values to each stack and even establish default values for specific configurations.
To proceed, open the Pulumi.yaml
file and insert the following configuration values.
config:
httpPort: 8080
zone: at-vie-1
userData: |
#cloud-config
package_update: true
packages:
- python3
write_files:
- path: /home/ubuntu/index.html
content: |
Hello, World from Exoscale!
runcmd:
- cd /home/ubuntu
- nohup python3 -m http.server 8080 &
These will serve as our default configuration values. To streamline our Pulumi program, remove the hardcoded values and replace them with the newly established configuration values.
To create a new stack, execute the following command.
pulumi stack init prod
This will create a new stack called prod
. You can see all the available stacks with the following command.
pulumi stack ls
Create a new Pulumi.prod.yaml
file and add the following configuration values.
config:
httpPort: 8081
zone: at-vie-2
userData: |
#cloud-config
package_update: true
packages:
- python3
write_files:
- path: /home/ubuntu/index.html
content: |
Hello, World from Exoscale Prod!
runcmd:
- cd /home/ubuntu
- nohup python3 -m http.server 8081 &
Run pulumi up
again to deploy the new stack. After a brief moment, your new instance will be deployed. When you
execute
the curl
command, you should receive a response from the newly deployed web server.
curl 138.124.210.178:8081
Hello, World from Exoscale Prod!
Verify that you the instances are running in different zones.
exo compute instance list
You might have observed a link to the Pulumi Cloud Console in the Pulumi output. The Pulumi Cloud Console is a web-based interface designed for managing your Pulumi projects and stacks. It provides a comprehensive view of resources, outputs, audit logs, and more.
Click on the provided link and sign in using your Pulumi account. Take a moment to explore and familiarize yourself with its features.
Pulumi ESC (Environments, Secrets, and Configuration) is a cutting-edge solution for managing secrets and configurations in modern cloud settings. It simplifies the complexities of configuration, ensuring a "secure by default" approach. Pulumi ESC introduces a new paradigm in configuration as code, allowing teams to consolidate secrets and configurations into a unified collection termed an 'environment'. This can be utilized across various infrastructure and application services. While it seamlessly integrates with Pulumi IaC, Pulumi ESC also offers a standalone CLI and API for broader applications.
-
Pulumi ESC enables you to define environments, which contain collections of secrets and configuration. Each environment can be composed from multiple environments.
-
Pulumi ESC supports a variety of configuration and secrets sources, and it has an extensible plugin model that allows third-party sources.
-
Pulumi ESC has a rich API that allows for easy integration. Every value in an environment can be accessed from any target execution environment.
-
Every environment can be locked down with RBAC, versioned, and audited.
For more information, configuration options and example please visit the Pulumi ESC documentation.
Create new Pulumi ESC environment.
pulumi env init <your-org>/exoscale
And paste this content:
values:
webserver:
httpPort: 8080
zone: at-vie-1
userData: |
#cloud-config
package_update: true
packages:
- python3
write_files:
- path: /home/ubuntu/index.html
content: |
Hello, World from Exoscale!
runcmd:
- cd /home/ubuntu
- nohup python3 -m http.server ${webserver.httpPort} &
pulumiConfig:
httpPort: ${webserver.httpPort}
zone: ${webserver.zone}
userData: ${webserver.userData}
Set up a development environment.
pulumi env init exoscale-dev
Paste only this content:
imports:
- exoscale
Finally, create a prod environment.
pulumi env init exoscale-prod
With this content:
imports:
- exoscale
values:
webserver:
httpPort: 8081
zone: at-vie-2
userData: |
#cloud-config
package_update: true
packages:
- python3
write_files:
- path: /home/ubuntu/index.html
content: |
Hello, World from Exoscale Prod!
runcmd:
- cd /home/ubuntu
- nohup python3 -m http.server ${webserver.httpPort} &
pulumiConfig:
httpPort: ${webserver.httpPort}
zone: ${webserver.zone}
userData: ${webserver.userData}
You can now eliminate all the config fields in your Pulumi.*.yaml files and substitute them with the following:
For dev
:
environment:
imports:
- exoscale-dev
For prod
:
environment:
imports:
- exoscale-prod
Pulumi ESC offers an enhanced method for managing configuration values, making it easier to share them with your team or across different stacks. While the earlier config approach remains supported, you also have the flexibility to combine both methods.
To destroy the stack, run the following command.
pulumi destroy
pulumi stack rm <stack-name>
And confirm the destruction with yes
.
To switch between stacks, you can use the following command.
pulumi stack select <stack-name>
- Can you create a new stack with a different instance type?
- Can you enable ssh access to the compute instance with your local ssh key?