Getting Started with Pulumi: Deploying a Demo App to AWS and GCP Using TypeScript

Getting Started with Pulumi: Deploying a Demo App to AWS and GCP Using TypeScript

Pulumi is a modern infrastructure as code (IaC) tool that empowers developers to define multi cloud resources using familiar programming languages such as TypeScript, Python, Go, and C#. In this blog post, I will guide you through the process of getting started with Pulumi, setting up your environment, and deploying a demo application to both AWS and GCP using TypeScript. I'll also highlight the differences between Pulumi and Terraform and discuss the benefits of using Pulumi.

Prerequisites

Before we dive in, make sure you have the following installed:

Step 1: Install Pulumi

First, let’s get the Pulumi CLI installed. You can do this using npm:

npm install -g pulumi

To check if it’s installed correctly, run:

pulumi version

Step 2: Set Up Your Pulumi Project

Create a new Pulumi project:

mkdir pulumi-demo
cd pulumi-demo
pulumi new typescript

Pulumi will prompt you to log in (you can use your Pulumi account, GitHub, or other options) and then guide you through setting up your new project. You’ll be asked to provide a project name, description, and stack name.

Step 3: Configure AWS and GCP Credentials

AWS

Configure your AWS credentials using the AWS CLI:

aws configure

GCP

For GCP, set up your credentials and authenticate using the SDK:

gcloud auth login
gcloud auth application-default login

Step 4: Define Your Infrastructure in TypeScript

Now, let's open the index.ts file in your Pulumi project and define some infrastructure. We'll start with AWS.

AWS Example

In this example, we’ll create an S3 bucket and an EC2 instance.

import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";

// create an S3 bucket
const bucket = new aws.s3.Bucket("my-bucket");

// create an EC2 instance
const size = "t2.micro"; // EC2 instance size
const ami = "ami-0c55b159cbfafe1f0"; // amazon Linux 2 AMI for us-west-2

const server = new aws.ec2.Instance("my-instance", {
    instanceType: size,
    ami: ami,
    tags: {
        Name: "MyInstance",
    },
    userData: `
        #!/bin/bash
        echo "hello, world!" > index.html
        nohup python -m SimpleHTTPServer 80 &
    `,
});

// export the bucket and instance details
export const bucketName = bucket.id;
export const instancePublicIp = server.publicIp;
export const instancePublicDns = server.publicDns;

In this code:

  • An S3 bucket is created with a default configuration.

  • An EC2 instance is launched using a specified AMI and instance type. The instance runs a simple HTTP server serving a "hello, world!" page.

Deploy to AWS

To deploy your stack to AWS, run:

pulumi up

Pulumi will show you a preview of the resources to be created. Confirm the deployment by typing yes.

Step 5: Deploying to GCP

Next, we'll set up a GCP Cloud Storage bucket and a Compute Engine instance. Create a new stack for GCP:

pulumi stack init gcp-demo
pulumi config set gcp:project YOUR_GCP_PROJECT_ID
pulumi config set gcp:region us-central1

Open the index.ts file again and define the GCP resources:

import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";

// create a Cloud Storage bucket
const bucket = new gcp.storage.Bucket("my-gcp-bucket");

// create a Compute Engine instance
const instance = new gcp.compute.Instance("my-instance", {
    machineType: "f1-micro",
    bootDisk: {
        initializeParams: {
            image: "debian-cloud/debian-9",
        },
    },
    networkInterfaces: [{
        network: "default",
        accessConfigs: [{}], 
    }],
    metadataStartupScript: `
        #!/bin/bash
        echo "hello, world!" > /var/www/html/index.html
        sudo apt-get update
        sudo apt-get install -y apache2
        sudo systemctl start apache2
        sudo systemctl enable apache2
    `,
});

// export the bucket and instance details
export const bucketName = bucket.name;
export const instanceName = instance.name;
export const instanceIP = instance.networkInterfaces[0].accessConfigs[0].natIp;

In this code:

  • A GCP Cloud Storage bucket is created.

  • A Compute Engine instance is launched with a startup script that installs Apache and serves a "hello, world!" page.

Deploy to GCP

Switch to the GCP stack and deploy:

pulumi stack select gcp-demo
pulumi up

Again, Pulumi will preview the resources. Confirm by typing yes.

Step 6: Clean Up Resources

When you’re done, make sure to clean up your resources. Use the pulumi destroy command for each stack:

pulumi stack select aws-demo
pulumi destroy
pulumi stack select gcp-demo
pulumi destroy

Pulumi vs. Terraform: Differences and Benefits

Pulumi and Terraform are both popular IaC tools, but they have some key differences:

Programming Languages

  • Pulumi: Uses general-purpose programming languages like TypeScript, Python, Go, and C#. This allows developers to use familiar languages and leverage existing ecosystems, libraries, and tools.

  • Terraform: Uses its own domain-specific language (HCL - HashiCorp Configuration Language). While HCL is powerful and expressive, it is different from general-purpose programming languages.

State Management

  • Pulumi: Manages state in the cloud (via the Pulumi service) by default, but also supports local state management and custom backends. This can simplify collaboration and state storage.

  • Terraform: Typically manages state in local files or remote backends (e.g., S3, Consul). This requires additional setup for team collaboration.

Extensibility

  • Pulumi: Offers more straightforward extensibility through the use of full programming languages. This makes it easier to create custom abstractions, utilities, and integrations.

  • Terraform: Extends functionality through custom providers and modules, but writing these requires knowledge of Go (for providers) and HCL (for modules).

Benefits of Pulumi

  1. Familiarity and Productivity: By using general-purpose programming languages, developers can quickly get started without learning a new language.

  2. Rich Ecosystem: Leverage existing libraries and tools from the broader programming ecosystem.

  3. Integrated Testing: Easily write unit tests for infrastructure code using standard testing frameworks.

  4. Flexibility: Use programming constructs like loops, conditionals, and functions to manage complex infrastructure logic.

  5. Unified Workflow: Manage infrastructure for multiple cloud providers and services using a single tool and consistent workflow.

Conclusion

In this blog post, we’ve learned how to get started with Pulumi and deploy multiple resources to both AWS and GCP using TypeScript. Pulumi's approach allows you to leverage your existing programming skills to manage cloud infrastructure efficiently. Compared to Terraform, Pulumi offers the flexibility of using general-purpose languages, which can enhance productivity and integration with existing codebases. For more advanced scenarios, you can extend these examples to include complex infrastructure setups, integrate with CI/CD pipelines, and more.

Did you find this article valuable?

Support Mikaeel Khalid by becoming a sponsor. Any amount is appreciated!