Infrastructure as Code with Pulumi
この記事の目次
Background
If you’ve dealt with cloud infrastructure previously, you know how difficult and complex it is to manage everything by hand.
For this very reason, people have come up with IaC, or Infrastructure as Code. It’s a way to define your cloud infrastructure as code, and treat it in the same way as you would other pieces of code. That is: write tests, perform quality checks and linting, deploy with CI/CD, and much more.
The competition
If you’re familiar with IaC tools, you might ask: “Why not Terraform?”. A valid question. Terraform is mature and widely used in the industry. However, there are some benefits Pulumi has to offer, which makes it worth considering.
- Language Flexibility: Pulumi allows you to use familiar programming languages such as JavaScript, TypeScript, Python, Go, and C# to define infrastructure, providing more flexibility and power compared to domain-specific languages like HCL, which is used in Terraform.
- Real Programming Constructs: With Pulumi, you can use loops, functions, classes, and other programming constructs, making it easier to reuse code (eg: for instantiating multiple instances of a resource).
- Strong Typing: Pulumi’s use of standard programming languages enables strong typing, which can reduce errors and improve the quality of the code.
- Unified Workflow: Pulumi manages both cloud infrastructure resources and cloud-native resources like Kubernetes, providing a unified workflow for deploying and managing all aspects of your infrastructure. Notably, this is an advantage over terraform, where managing kubernetes is possible, but very inflexible.
- Community and Ecosystem: Pulumi integrates with a large number of tools and services and is supported by a growing community that contributes to its libraries and plugins.
Getting Started with Pulumi
Now that we’ve covered the background and advantages of Pulumi, let’s dive into creating a simple project. We’ll use Python for this example, but remember, Pulumi supports multiple languages.
Setting Up
First, make sure you have Pulumi installed. You can follow the official installation guide for your operating system.
Next, let’s create a new directory for our project:
mkdir pulumi-demo
cd pulumi-demo
Now, let’s create a new Pulumi project:
pulumi new aws-python
This command will prompt you for some information about your project. Fill it out as appropriate.
Writing Our Infrastructure Code
Once the project is set up, you’ll find a __main__.py
file in your directory. This is where we’ll define our infrastructure. Let’s create a simple AWS S3 bucket:
import pulumi
from pulumi_aws import s3
# Create an AWS S3 bucket
bucket = s3.Bucket('my-bucket',
website={
"index_document": "index.html"
})
# Export the name of the bucket
pulumi.export('bucket_name', bucket.id)
This code creates an S3 bucket and configures it for static website hosting. We also export the bucket name so we can easily reference it later.
Deploying Our Infrastructure
To deploy our infrastructure, we simply run:
pulumi up
Pulumi will show you a preview of the changes it’s about to make. If everything looks good, confirm the changes, and Pulumi will create your S3 bucket.
Accessing Our Resources
After deployment, you can access the outputs we defined:
pulumi stack output bucket_name
This will print the name of your newly created S3 bucket.
Advanced Features
While creating a single S3 bucket is straightforward, Pulumi really shines when dealing with more complex infrastructures. Let’s look at a slightly more advanced example.
Creating Multiple Resources
Suppose we want to create multiple S3 buckets. With Pulumi, we can use Python’s list comprehension:
import pulumi
from pulumi_aws import s3
# Create multiple S3 buckets
bucket_names = ['data', 'logs', 'backups']
buckets = [s3.Bucket(f'{name}-bucket') for name in bucket_names]
# Export the names of all buckets
pulumi.export('bucket_names', [bucket.id for bucket in buckets])
This creates three S3 buckets in one go, demonstrating how we can leverage Python’s features to create multiple resources easily.
Using Components
Pulumi also allows you to create reusable components. Let’s create a component that sets up a VPC with public and private subnets
from pulumi import ComponentResource, ResourceOptions
from pulumi_aws import ec2
class VPC(ComponentResource):
def __init__(self, name, cidr_block, options=None):
super().__init__('custom:resource:VPC', name, None, options)
vpc = ec2.Vpc(f'{name}-vpc',
cidr_block=cidr_block,
enable_dns_hostnames=True,
enable_dns_support=True)
public_subnet = ec2.Subnet(f'{name}-public-subnet',
vpc_id=vpc.id,
cidr_block='10.0.1.0/24',
map_public_ip_on_launch=True,
availability_zone='us-west-2a')
private_subnet = ec2.Subnet(f'{name}-private-subnet',
vpc_id=vpc.id,
cidr_block='10.0.2.0/24',
map_public_ip_on_launch=False,
availability_zone='us-west-2b')
self.vpc_id = vpc.id
self.public_subnet_id = public_subnet.id
self.private_subnet_id = private_subnet.id
self.register_outputs({})
# Usage
my_vpc = VPC('my-vpc', '10.0.0.0/16')
pulumi.export('vpc_id', my_vpc.vpc_id)
pulumi.export('public_subnet_id', my_vpc.public_subnet_id)
pulumi.export('private_subnet_id', my_vpc.private_subnet_id)
This component encapsulates the creation of a VPC with public and private subnets, making it easy to reuse this configuration across different projects.
Conclusion
We’ve only scratched the surface of what Pulumi can do. Its ability to use familiar programming languages and constructs makes it a powerful tool for managing cloud infrastructure. By leveraging features like loops, functions, and classes, you can create more maintainable infrastructure code.
Finally, while Pulumi offers many advantages, the choice between different IaC tools often depends on your specific needs and the ecosystem you’re working in. Always evaluate your options based on your project requirements. In a nutshell, try out everything!
For more advanced usage and best practices, I highly recommend checking out the official Pulumi documentation.
カテゴリー: