Defining and Provisioning Resources
In Pulumi, resources represent the fundamental units that make up your infrastructure, such as virtual machines, networks, storage, and databases. A resource is used to define and manage an infrastructure object in your Pulumi configuration.
In this tutorial, you will create a simple Nginx web server. You will then refer to documentation in the Pulumi Registry to create a security group resource to make the server publicly accessible.
In this tutorial, you'll learn:
- How to create a new resource
- How to update an existing resource
- How to reference resource definitions in the Pulumi documentation
Prerequisites:
- A Pulumi Cloud account and access token
- The Pulumi CLI
- An Amazon Web Services account
- The AWS CLI
- Node.js or Python installed
Create a virtual machine
The first step is to create a virtual machine resource that will be used to host the web server. The specific details of how to create your virtual machine differ by cloud provider. For the purposes of this tutorial, we will be creating our resources in AWS in the us-east-1
region.
Amazon Elastic Compute Cloud (EC2)
Amazon Elastic Compute Cloud (EC2) provides managed virtual server hosting that makes it straightforward to run applications in your AWS account. In AWS, a virtual server is referred to as an “instance”. These instances can host a variety of operating systems, tools, and applications, each configured according to your specific requirements.
Create a new project
To start, login to the Pulumi CLI and ensure it is configured to use your AWS account. Next, create a new project, then use the following code snippet to scaffold your project with the required imports and overall program structure that we will fill in as we go along:
import * as aws from "@pulumi/aws";
import * as pulumi from "@pulumi/pulumi";
// [Step 1: Create an EC2 instance.]
// [Step 2: Create a security group.]
import pulumi
import pulumi_aws as aws
# [Step 1: Create an EC2 instance.]
# [Step 2: Create a security group.]
name: aws-ec2-sg-nginx-server-yaml
runtime: yaml
description: A program to create an Nginx server on AWS
# [Step 1: Create an EC2 instance.]
# [Step 2: Create a security group.]
Define an EC2 instance
The Pulumi Registry provides the documentation for all of the Pulumi providers and their associated resources. Open the aws.ec2.Instance
documentation page to view a description of this resource, example usage, the resource definition, and supported properties.
We will now define our EC2 instance resource below.
import * as aws from "@pulumi/aws";
import * as pulumi from "@pulumi/pulumi";
const userData = `
#!/bin/bash
sudo yum update -y
sudo yum upgrade -y
sudo amazon-linux-extras install nginx1 -y
sudo systemctl enable nginx
sudo systemctl start nginx`;
});
// [Step 1: Create an EC2 instance.]
const server = new aws.ec2.Instance("webserver-www2", {
instanceType: "t2.micro",
ami: "ami-09538990a0c4fe9be",
userData: userData,
});
export const publicIp = server.publicIp;
import pulumi
import pulumi_aws as aws
user_data = """
#!/bin/bash
sudo yum update -y
sudo yum upgrade -y
sudo amazon-linux-extras install nginx1 -y
sudo systemctl enable nginx
sudo systemctl start nginx
"""
# [Step 1: Create an EC2 instance.]
server = aws.ec2.Instance(
'webserver-www',
instance_type="t2.micro",
ami="ami-09538990a0c4fe9be",
user_data=user_data,
)
pulumi.export('publicIp', server.public_ip)
name: aws-ec2-sg-nginx-server-yaml
runtime: yaml
description: A program to create an Nginx server on AWS
resources:
# [Step 1: Create an EC2 instance.]
webserver-www:
type: aws:ec2:Instance
properties:
instanceType: t2.micro
ami: "ami-09538990a0c4fe9be"
userData: |
#!/bin/bash
sudo yum update -y
sudo yum upgrade -y
sudo amazon-linux-extras install nginx1 -y
sudo systemctl enable nginx
sudo systemctl start nginx
outputs:
publicIp: ${webserver-www.publicIp}
us-east-1
region, make sure to replace the AMI ID value with the ID that is specific to your region. Otherwise you may run into an InvalidAMIID.NotFound
error.All resources have a required name
argument. Each resource has both a logical name and a physical name.
The logical name is how the resource is known inside Pulumi. This is the value provided to the required name
argument.
The physical name is the name used for the resource in the cloud provider that a Pulumi program is deploying to. It is a combination of the logical name plus a random suffix which helps to prevent resource naming collisions.
In the above example, the logical name for our aws.ec2.Instance
resource is “webserver-www”, and the physical name might typically look something like “webserver-www-d7c2fa0”.
In addition to names, resources have properties and options.
Properties are used to specify what type of resource to create. Properties are often resource-specific, and they can be required or optional depending on the specifications of the provider.
The properties inside our aws.ec2.Instance
resource are:
Property | Description |
---|---|
instance_type | tells the AWS provider to create an EC2 instance of type/size t2.micro |
ami | tells the provider to create the instance using the ami-09538990a0c4fe9be machine image |
user_data | tells the provider to initialize the instance with the script we have defined |
Options let you control certain aspects of a resource (such as showing explicit dependencies or importing existing infrastructure). We do not have any options defined for this resource, but you can learn more about options in the Pulumi documentation.
Deploy your EC2 instance
Now let’s run the pulumi up
command to preview and deploy the resource we just defined in our project.
Previewing update (webserver-dev):
Type Name Plan
+ pulumi:pulumi:Stack myproject-webserver-dev create
+ └─ aws:ec2:Instance webserver-www create
Resources:
+ 2 to create
Do you want to perform this update? yes
Updating (webserver-dev):
Type Name Status
+ pulumi:pulumi:Stack myproject-webserver-dev created
+ └─ aws:ec2:Instance webserver-www created
Outputs:
publicIp : "34.217.110.29"
Resources:
+ 2 created
Duration: 17s
The public IP address of your instance has been provided for you as an output, and you can use this to access your web server. However, if you try to visit this address, your request will eventually time out. This is because we have not yet configured web traffic access for our instance. We will do this by creating our security group resource.
Create a security group
In this section, you will use Pulumi documentation to configure the security group on your own. The security group must allow web traffic on port 80 in order for you to access your web server. An updated version of the project code has been provided below as a starting point.
import * as aws from "@pulumi/aws";
import * as pulumi from "@pulumi/pulumi";
const userData = `
#!/bin/bash
sudo yum update -y
sudo yum upgrade -y
sudo amazon-linux-extras install nginx1 -y
sudo systemctl enable nginx
sudo systemctl start nginx`;
// [Step 2: Create a security group.]
const securityGroup = // TO-DO
});
// [Step 1: Create an EC2 instance.]
const server = new aws.ec2.Instance("webserver-www2", {
instanceType: "t2.micro",
ami: "ami-09538990a0c4fe9be",
userData: userData,
vpcSecurityGroupIds: [securityGroup.id],
});
import pulumi
import pulumi_aws as aws
user_data = """
#!/bin/bash
sudo yum update -y
sudo yum upgrade -y
sudo amazon-linux-extras install nginx1 -y
sudo systemctl enable nginx
sudo systemctl start nginx
"""
# [Step 2: Create a security group.]
security_group = # TO-DO
# [Step 1: Create an EC2 instance.]
server = aws.ec2.Instance(
'webserver-www',
instance_type="t2.micro",
ami="ami-09538990a0c4fe9be",
user_data=user_data,
vpc_security_group_ids=[security_group.id], # Security group property and reference
)
pulumi.export('publicIp', server.public_ip)
name: aws-ec2-sg-nginx-server-yaml
runtime: yaml
description: A program to create an Nginx server on AWS
resources:
# [Step 2: Create a security group.]
webserver-secgrp:
# TO-DO
# [Step 1: Create an EC2 instance.]
webserver-www:
type: aws:ec2:Instance
properties:
instanceType: t2.micro
ami: "ami-09538990a0c4fe9be"
userData: |
#!/bin/bash
sudo yum update -y
sudo yum upgrade -y
sudo amazon-linux-extras install nginx1 -y
sudo systemctl enable nginx
sudo systemctl start nginx
vpcSecurityGroupIds:
- ${webserver-secgrp.id}
outputs:
publicIp: ${webserver-www.publicIp}
You may have noticed that the placeholder code for the security group resource has been moved above the code for the EC2 instance resource. This was done intentionally to accommodate for variable declaration and usage order in our code.
If we place the security group resource definition after the EC2 instance and try to deploy our program, it will fail. This is because the security group variable must be declared before we can tell our EC2 instance resource to use it.
Use the following steps as a guide for adding the Security Group resource:
- Navigate to the AWS Registry documentation page
- Search for the EC2 Security Group resource
- Define the EC2 Security Group resource in your project code
- Configure the security group to allow traffic on port 80
- Update the EC2 instance resource to use the security group
- Preview and deploy your updated project code
Once you have completed these steps, navigate to your instance IP address again. You should now be greeted with a “Welcome to nginx!” home page message that indicates your web server is running and publically accessible.
Click here to view the complete project code
import * as aws from "@pulumi/aws";
import * as pulumi from "@pulumi/pulumi";
const userData = `
#!/bin/bash
sudo yum update -y
sudo yum upgrade -y
sudo amazon-linux-extras install nginx1 -y
sudo systemctl enable nginx
sudo systemctl start nginx`;
// [Step 2: Create a security group.]
const securityGroup = new aws.ec2.SecurityGroup("webserver-secgrp2", {
description: "Enable HTTP access",
ingress: [
{
protocol: "tcp",
fromPort: 80,
toPort: 80,
cidrBlocks: ["0.0.0.0/0"],
},
],
});
// [Step 1: Create an EC2 instance.]
const server = new aws.ec2.Instance("webserver-www2", {
instanceType: "t2.micro",
ami: "ami-09538990a0c4fe9be",
userData: userData,
vpcSecurityGroupIds: [securityGroup.id],
});
export const publicIp = server.publicIp;
import pulumi
import pulumi_aws as aws
user_data = """
#!/bin/bash
sudo yum update -y
sudo yum upgrade -y
sudo amazon-linux-extras install nginx1 -y
sudo systemctl enable nginx
sudo systemctl start nginx
"""
# [Step 2: Create a security group.]
security_group = aws.ec2.SecurityGroup(
'webserver-secgrp',
description='Enable HTTP access',
ingress=[
{ 'protocol': 'tcp', 'from_port': 80, 'to_port': 80, 'cidr_blocks': ['0.0.0.0/0'] }
]
)
# [Step 1: Create an EC2 instance.]
server = aws.ec2.Instance(
'webserver-www',
instance_type="t2.micro",
ami="ami-09538990a0c4fe9be",
user_data=user_data,
vpc_security_group_ids=[security_group.id], # Security group property and reference
)
pulumi.export('publicIp', server.public_ip)
name: aws-ec2-sg-nginx-server-yaml
runtime: yaml
description: A program to create an Nginx server on AWS
resources:
# [Step 2: Create a security group.]
webserver-secgrp:
type: aws:ec2:SecurityGroup
properties:
description: Enable HTTP access
ingress:
- protocol: tcp
fromPort: 80
toPort: 80
cidrBlocks:
- 0.0.0.0/0
# [Step 1: Create an EC2 instance.]
webserver-www:
type: aws:ec2:Instance
properties:
instanceType: t2.micro
ami: "ami-09538990a0c4fe9be"
userData: |
#!/bin/bash
sudo yum update -y
sudo yum upgrade -y
sudo amazon-linux-extras install nginx1 -y
sudo systemctl enable nginx
sudo systemctl start nginx
vpcSecurityGroupIds:
- ${webserver-secgrp.id}
outputs:
publicIp: ${webserver-www.publicIp}
Clean up
Before moving on, tear down the resources that are part of your stack to avoid incurring any charges.
- Run
pulumi destroy
to tear down all resources. You'll be prompted to make sure you really want to delete these resources. A destroy operation may take some time, since Pulumi waits for the resources to finish shutting down before it considers the destroy operation to be complete. - To delete the stack itself, run
pulumi stack rm
. Note that this command deletes all deployment history from the Pulumi Service.
Next steps
In this tutorial, you made an EC2 instance configured as an Nginx webserver and made it publicly available by referencing the Pulumi Registry to define the security group. You also reviewed resource properties and example usage.
To learn more about creating resources in Pulumi, take a look at the following resources:
- Learn more about stack outputs and references in the Stack Outputs and References tutorial.
- Learn more about inputs and outputs in the Inputs and Outputs documentation.
- Learn more about resource names, options, and providers in the Pulumi documentation.