Cloud Native Infrastructure as Code

Serverless Programming with Pulumi

Pulumi provides a cloud native programming model for serverless applications: from high-level multi-cloud, to fine-grained cloud-specific libraries.

Any code, any cloud, any language.

// Create a serverless REST API
import * as cloud from "@pulumi/cloud";
let app = new cloud.API("my-app");
app.static("/", "www");
// Serve a simple REST API on `GET /hello`: app.get("/hello", (req, res) =>
     res.json({ hello: "World!" }));
export let url = app.publish().url;


What is Serverless?

Serverless, or function-based, computing enables you to build and run applications and services without thinking about the server infrastructure on which the functions depend. 'Serverless' applications of course require servers (typically cloud infrastructure, or kubernetes clusters), but don't require you to provision, scale, and manage any servers.

The reduced operational overhead of serverless computing means teams can focus on the business and application logic they need: the development of products vs the management of the infrastructure for them.

Building Blocks of Serverless Programming

Building serverless applications can be considered to be a composition of a series of standardized building blocks. For instance, serverless services can provide compute, storage, data storage, messaging/queues and orchestration. With just those blocks, extremely powerful applications can be composed and delivered with minimal infrastructure concerns.


Building Block
AWS
Azure
GCP
API Lambda Functions Cloud Functions
Storage S3 Blob Storage Cloud Storage
Data Storage DynamoDB Cosmos DB Cloud Datatable
Timer CloudWatch Monitor Stackdriver Monitoring
Queue SQS Queue Storage Cloud Pub/Sub
Topic SNS Queue Storage Cloud Pub/Sub
State Machine Step Functions Azure Logic Apps

Pulumi makes it simple to interact with serverless services available from the major cloud vendors, and with Kubernetes.

The @pulumi/cloud library provides very high level, multi cloud access to building blocks of serverless applications, while the specialized @pulumi/cloud-aws, @pulumi/cloud-azure, @pulumi/cloud-gcp, and @pulumi/kubernetes libraries offer fine grained control of the individual cloud vendor services.

API

Creating a Serverless REST API

This example shows how to create a simple REST API that counts the number of times a route has been hit. To implement this API, we need a DynamoDB table, an API endpoint, and a Lambda function.


Get Started

const cloud = require("@pulumi/cloud-aws");

// Create a mapping from 'route' to a count
let counterTable = new cloud.Table("counterTable", "route");
        
// Create an API endpoint
let endpoint = new cloud.API("hello-world");
        
endpoint.get("/{route+}", (req, res) => {
    let route = req.params["route"];
    console.log(`Getting count for '${route}'`);
        
    // get previous value and increment
    // reference outer `counterTable` object
    counterTable.get({ route }).then(value => {
        let count = (value && value.count) || 0;
        counterTable.insert({ route, count: ++count }).then(() 
        => {
            res.status(200).json({ route, count });
            console.log(`Got count ${count} for '${route}'`);
        });
    });
});
        
exports.endpoint = endpoint.publish().url;
STORAGE

Using storage buckets easily

Pulumi makes it easy to setup storage in the cloud. Events raised by the storage object can be handled by Lambda functions as actual lambdas in code.

This example sets up a storage bucket (using S3 on AWS) and a simple Lambda function to respond to new items being added to the bucket.


Get Started

const cloud = require("@pulumi/cloud-aws");

// A storage bucket
const bucket = new cloud.Bucket("bucket");
const bucketName = bucket.bucket.id;


// Trigger a Lamda function when something is added
bucket.onPut("onNewVideo", bucketArgs => {
    console.log(`*** New Item in Bucket`);}

// Export the bucket name.
exports.bucketName = bucketName;
    
DATA STORAGE

Stash info into a document database

This example uses a serverless timer that fetches the Hacker News homepage every hour and stashes it into a document database, making use of Pulumi's ability to reference the cloud.table object.


Get Started

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

let snapshots = new cloud.Table("snapshots");

cloud.timer.daily("daily-yc-snapshot", 
    { hourUTC: 0, minuteUTC: 0 }, () => {
        let req = require("https")
            .get("https://news.ycombinator.com", (res) => {
        let content = "";
        res.setEncoding("utf8");
        res.on("data", (chunk) => { content += chunk });
        res.on("end", () => {
            snapshots.insert({ date: Date.now(),
                content: content });
        });
    });
    req.end();
});
    
TIMER

Super simple serverless cron jobs

Pulumi’s Cloud Framework has a timer module that lets you schedule cron jobs that run serverless functions. This is the easiest way to get up and running with serverless functions, because you don’t even need any other resources to trigger events from.

There are several ways to schedule a timer, depending on your stylistic preferences. These examples simply print the current time to the console on a given interval:


Get Started

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

// Run a timer every minute:
cloud.timer.interval("interval-timer", { minutes: 0 }, () => {
    console.log(`interval-timer: ${Date.now()}`);
});

// Run a timer every minute (cron-style expression):
cloud.timer.cron("cron-timer", "0 * * * * *", () => {
    console.log(`cron-timer: ${Date.now()}`);
});

// Run a timer every day at 7:30 UTC:
cloud.timer.daily("daily-timer", { hourUTC: 7, minuteUTC: 30 }, () => {
    console.log(`daily-timer: ${Date.now()}`);
});

// Run a timer at the 45th minute UTC of every hour:
cloud.timer.hourly("hourly-timer", { minuteUTC: 45 }, () => {
    console.log(`hourly-timer: ${Date.now()}`);
});
    
MESSAGE

Post AWS SQS Messages to Slack

This example wires up a serverless AWS Lambda to an AWS SQS queue and demonstrates posting a message to Slack. This program provisions resources using Pulumi's deployment system, but lets you write serverless code as ordinary JavaScript functions.


Get Started

let aws = require("@pulumi/aws");
let serverless = require("@pulumi/aws-serverless");
let config = require("./config");

let queue = new aws.sqs.Queue("mySlackQueue", { visibilityTimeoutSeconds: 180 });

serverless.queue.subscribe("mySlackPoster", 
    queue, async (e) => {
    let slack = require("@slack/client");
    let client = new slack.WebClient(config.slackToken);
    for (let rec of e.Records) {
        await client.chat.postMessage({
            channel: config.slackChannel,
            text: `*Msg ${rec.messageId}*:\n${rec.body}\n`+
                `(with :love_letter: from Pulumi)`,
            as_user: true,
        });
        console.log(`Posted SQS message ${rec.messageId} to ${config.slackChannel}`);
    }
}, { batchSize: 1 });

module.exports = {
    queueURL: queue.id,
};
    
TOPIC

Subscribe to a SNS endpoint

This example users a timer to trigger a notification which then recursively triggers itself to countdown from 25..0 every five minutes.


Get Started

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

let countDown = new pulumi.Topic("examples-countDown");

countDown.subscribe("watcher", async (num) => {
    console.log(num);
    if (num > 0) {
        await countDown.publish(num - 1);
    }
});

pulumi.timer.interval("examples-heartbeat", {minutes: 5}, async () => {
    await countDown.publish(25);
});
MESSAGE

Create state machines of functions

This example wires up a serverless AWS Lambda to an AWS SQS queue and demonstrates posting a message to Slack. This program provisions resources using Pulumi's deployment system, but lets you write serverless code as ordinary JavaScript functions.


Get Started

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

const helloFunction = new aws.serverless.Function(
"helloFunction",
    { role: lambdaRole },
        (event, context, callback) => {
        callback(null, "Hello");
    }
);

const worldFunction = new aws.serverless.Function(
"worldFunction",
    {role: lambdaRole},
        (event, context, callback) => {
        callback(null, `${event} World!`);
    }
);

const stateMachine = new aws.sfn.StateMachine("stateMachine", {
roleArn: sfnRole.arn,
definition: pulumi.all([helloFunction.lambda.arn, worldFunction.lambda.arn])
    .apply(([helloArn, worldArn]) => {
    return JSON.stringify({
    "Comment": "A Hello World of the Amazon States Language",
    "StartAt": "Hello",
    "States": {
        "Hello": {"Type": "Task", "Resource": helloArn,
        "Next": "World"
        },
        "World": {"Type": "Task", "Resource": worldArn,
        "End": true
        }
    }
    });
})
});

exports.stateMachineArn = stateMachine.id;

How Pulumi Works

Get started with Pulumi

Pulumi works with your favorite language, and can be used with any cloud.

Install Pulumi

Setup

Configure

Try our tutorials

Quickstarts

Tour

Read the docs

Reference

Examples

Need help with serverless application delivery? Drop us a line.

More from Pulumi

Migrate to Pulumi

In this video, Pulumi CTO, Luke Hoban, discusses how to begin to migrate to Pulumi from existing tools such as CloudFormation and Terraform.

Learn more

Serverless, Containers, and Infrastructure

In this blog post, we show productive Pulumi can be at combining different aspects of cloud architecture for truly cloud native programming.

Learn more