Introduction

Pulumi is an Infrastructure as code platform that lets you create, deploy and manage AWS resources using a programming language like Python. Pulumi supports multiple cloud providers as well multiple different programming languages.

Pulumi is similar to Terraform which is also a popular Infrastructure-as-code platform. A major difference between Pulumi and Terraform is that Pulumi lets you choose one of the support general-purpose programming languages whereas Terraform has a domain-specific language called Hashicorp Configuration Language (HCL).

Pulumi is an open-source tool and it provides both free and paid tiers based on usage. For this tutorial, we will be using the Community version which is free for individual use.

Getting started

Pulumi backend

Pulumi manages the state of your infrastructure and stores it in a state file (a JSON file). Pulumi uses this file as the source of truth when it comes to your infrastructure. The state file tells Pulumi when and how to create, delete, or update any cloud resources.

Pulumi provides the capability to store the state in a backend of your choosing. Some of the commonly used options are:

  • Pulumi backend is free for individual users and provides an easy-to-use and intuitive UI for managing the state of your infrastructure
  • Object stores like AWS S3

By default, Pulumi stores this file in its backend service which is what we will use for this tutorial.

Project Setup

Create a new application

We can create a new python application by running pulumi new aws-python. You will be prompted to enter the name of the project along with some information.

pulumi new aws-python

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 name: (pulumi-tutorial)
project description: (A minimal AWS Python Pulumi program) Setting up an EC2 instance using Pulumi
Created project 'pulumi-tutorial'

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'

aws:region: The AWS region to deploy into: (us-east-1) us-west-2
Saved config

Preview infrastructure

We can run pulumi preview to confirm the initial setup worked correctly.

/assets/img/pulumi-ec2/pulumi-preview.png

As we can see from the image above, the default stack generated by Pulumi creates an S3 bucket named my-bucket.

Creating an EC2 using Python

Let’s clear up the existing contents of __main__.py and start with the following imports.

from pulumi import export
import pulumi_aws as aws

We will first create a new VPC along with an Internet Gateway and Route Table for our EC2 instance:

vpc = aws.ec2.Vpc(
	"ec2-vpc",
	cidr_block="10.0.0.0/16"
)

public_subnet = aws.ec2.Subnet(
	"ec2-public-subnet",
	cidr_block="10.0.101.0/24",
	tags={
		"Name": "ec2-public"
	},
	vpc_id=vpc.id
)

igw = aws.ec2.InternetGateway(
	"ec2-igw",
	vpc_id=vpc.id,
)

route_table = aws.ec2.RouteTable(
	"ec2-route-table",
	vpc_id=vpc.id,
	routes=[
		{
			"cidr_block": "0.0.0.0/0",
			"gateway_id": igw.id
		}
	]
)

rt_assoc = aws.ec2.RouteTableAssociation(
	"ec2-rta",
	route_table_id=route_table.id,
	subnet_id=public_subnet.id
)

Next, we will create a security group for the EC2 instance that allows HTTP traffic to port 80. This is where we will run the HTTP webserver.

sg = aws.ec2.SecurityGroup(
	"ec2-http-sg",
	description="Allow HTTP traffic to EC2 instance",
	ingress=[{
		"protocol": "tcp",
		"from_port": 80,
		"to_port": 80,
		"cidr_blocks": ["0.0.0.0/0"],
	}],
    vpc_id=vpc.id,
)

Lastly, we will use an Amazon AMI for our EC2 instance along with a custom user data script that will run a HTTP server on port 80.

ami = aws.ec2.get_ami(
	most_recent="true",
	owners=["amazon"],
	filters=[{"name": "name", "values": ["amzn-ami-hvm-*"]}]
)


user_data = """
#!/bin/bash
echo "Hello, world!" > index.html
nohup python -m SimpleHTTPServer 80 &
"""

ec2_instance = aws.ec2.Instance(
	"ec2-tutorial",
	instance_type="t2.micro",
	vpc_security_group_ids=[sg.id],
	ami=ami.id,
	user_data=user_data,
    subnet_id=public_subnet.id,
    associate_public_ip_address=True,
)

We will also export the public IP of our newly created EC2 instance so that we access the webserver at this IP address

export("ec2-public-ip", ec2_instance.public_ip)

Creating the infrastructure resources

Now that we have the code to set up our EC2 instance, let’s run pulumi preview to see which resources will be created. This is what the output should look like:

/assets/img/pulumi-ec2/pulumi-preview-ec2.png

Next, we will create our EC2 instance by running pulumi up. Select yes when prompted. Once all the resources are created, you should be able to see the public IP of the EC2 instance that was created.

/assets/img/pulumi-ec2/pulumi-up-ec2.png

Let’s verify that our EC2 instance is serving HTTP traffic by navigating to the public IP. The webserver should return Hello, World! indicating that everything was set up as expected.

Cleaning up the stack

Before finishing up, let’s clean up all the resources we created to ensure we don’t get billed for any of the resources we created. To clean up your stack, run pulumi destroy and then select yes. Once the deletion is successful, you should see output like this:

/assets/img/pulumi-ec2/pulumi-destroy.png