Deploy any Web App to Lambda in 60 seconds

If it listens on a port, it can be deployed to Lambda!

I’m presenting this write up in two segments.

  1. The first chunk is on demonstrating how to deploy a web app, using various languages and frameworks, to AWS Lambda.
  2. The second chunk, which is optional, is using HashiCorp’s waypoint to automate all of the previous steps, and release your app to the public in roughly 60 seconds. (YMMV)

It will also help to have some prior understanding of the following topics:

Referenced code examples can be found at my demo repo.

Deploying to Lambda

If it listens on a port, you can deploy it to AWS Lambda...

AWS Lambda is an event-driven, serverless computing platform provided by Amazon as a part of Amazon Web Services. It is a computing service that runs code in response to events and automatically manages the computing resources required by that code. 1

I won’t go into details of Lambda vs. server-ful alternatives like EC2, Digital Ocean Droplets, Heroku, or Kubernetes, since that is a different topic altogether with a ton of historic relevance that many others can speak to from experience 2. I’ll simply focus on Lambda as the platform of choice here.

Build

Let‘s say you have some code for a typical web app backend or API.

app.js

The first step in deploying this to Lambda is to package it into an OCI image with a tool like Docker. This is because we’ll also be adding a lambda extension via the Dockerfile, as well as publishing the built image to ECR, which is the only image registry that Lambda supports.

Additionally, this allows you to write your application code in programming languages that don’t have an official AWS Lambda runtime, namely Rust and Swift.

AWS Lambda Adapter

The star of the show is this neat lambda extension called aws-lambda-adapter 3. It enables you to run your long-running server code — some app listening on a port — on AWS Lambda.

Why this is so great is that it does not require any special configuration or bespoke code paths to make your app compatible with an ephemeral environment like Lambda. If you can containerize and run it locally, the adapter will make it just work on Lambda.

Furthermore, using it requires only a few additional lines in your Dockerfile. Here are a few examples of what that may look like for a few different languages.

Golang

Gin

Dockerfile
Note: The full examples can be viewed at this GitHub repo.

Push

Getting your app’s Docker image to ECR involves a series of steps/commands:

  • Build the image

  • Authenticate with ECR

  • Create repository

  • Push the image to ECR

...but this will grow very tedious if you need to build and push many times.

See ECR docs for commands to authenticate and push images to ECR.

Release

With the ECR image published, the Lambda function can be created, using said image.

To release the function to the public internet, a Lambda URL 4 can be created, which will look something like: https://qvomz3om452pulf5joiuyojwc40ekond.lambda-url.us-east-1.on.aws

At this point, your lambda should be fully invokable by the public internet.

Doing any of the previous steps via the AWS CLI is quite cumbersome. Doing this via the console is slightly less painful due to small things that get handled for you like various IAM roles and permissions. But all of this is already taken care of you by a nifty tool.

Warning: Stop here if you don’t care for learning another deployment tool.

Automate with waypoint

All the previous steps, which could be handled via a series of CLI commands and/or manual console clicking, can be automated with a single command: waypoint up.

Waypoint allows developers to deploy, manage, and observe their applications through a consistent abstraction of underlying infrastructure.

But first, you need a few mostly trivial things...

  • waypoint installed...

  • A valid config file:

    Warning: The highlighted stanza, which is a Lambda URL releaser component, is not yet available in waypoint. You can simply comment it out, and waypoint up will still automate all the previous steps, minus the Lambda URL creation.

    See: Open PR #3187
  • A Waypoint server running; Running one on Docker on your local machine is easy peasy...

  • And a project initialized...

...and you’re ready to go...

Note: If you've made changes to your application code, you can simply waypoint up again and your changes will be deployed.

In the following terminal screenshot, you can see that Waypoint finished in 50 seconds. This example was using the Golang project, for which the Docker image builds quite fast on my M1 Macbook Pro. The Swift and Rust Docker images take significantly longer.

With that being said, your mileage may vary!

Waypoint deploying everything in 50 seconds!
Waypoint deploying everything in 50 seconds!

Result

Here’s a table of the languages and frameworks that I was able to containerize and deploy:

I attempted but failed to get working examples for the following languages and frameworks:

  • Ruby + Rails
    • Rails is pretty stateful and writes to a local /tmp directory. This causes the container to crash since the Lambda environment treats that directory as read-only.
  • PHP + symfony
    • I have yet to learn the build tools/steps for PHP/symfony. (I never touched it before!)
  • Deno:
    • I was able to containerize and run a simple app locally. It just didn’t want to work on Lambda. Reason TBD.

Thanks for reading! If you have any quetions or feedback, please feel free to comment below.

Until next time!

Footnotes

  1. https://en.wikipedia.org/wiki/AWS_Lambda

  2. This podcast touchs on the early days of Lambda a bit.

  3. aws-lambda-adapter was released about 8 months prior to this post. I should read through the source code and maybe do a deep dive into how it works.

  4. Lambda URLs were announced April 6th, 2022. Fun fact: AWS did release this feature some time in December of the previous year, but they quickly rolled it back.

Comments