Deploying a GraphQL Docker Container to AWS Lambda with Waypoint
I finally got around to ticking off a few items on my todo list. 1. Shoving an express.js app into a lambda function. 2. Deploying a Docker container to lambda. 3. Using a new HashiCorp product. ...And it all required very little code. Sort of.
Kevin Wang
Just want a TL;DR? I used
waypoint
to build, deploy, and release a containerized GraphQL server toLambda
.waypoint
builds the image withDocker
, publishes it toECR
, and points anALB
at the lambda function.Just here to see some code? Skip ahead ↓
Changelog:
- February 23, 2022: Added links to
#3032
and#3035
under Final thoughts
Backstory
When I hear about new tech that piques my interest or old patterns that are simply new to me, I take note and add them to my list of things to try out. However, this list has grown large and I have a bad habit of not actually getting around to many of those things, because you know... work, life, and everything else.
Somedays I do get lucky and am blessed with a streak of diligence, discipline, or just that one thing that helps triggers the domino effect in checking items off.
express.js
inside lambda
Ever since listening to “JavaScript Deployments”
(March 2020) and learning that you can put an express.js
app inside a lambda function, I’ve been
curious about exactly what that looked like... I just never got around to
figuring it out for myself.
Docker
container inside lambda
Ever since AWS announced container image support for Lambda back in December 2020, I’ve been curious about it as well, but never got around to using it since Docker wasn’t really a tool that I used regularly.
My method to date for deploying something to lambda has been using
the aws-cdk-lib/aws_lambda_nodejs
package, which uploads some compiled JavaScript
to a Node.js
lambda function.
But this is still just JavaScript
and not a containerized app.
Beyond terraform
...
And... Ever since joining HashiCorp in August 2021, I’ve telling myself to go learn more about all the
core products. Terraform
has been the only product I’ve really used and not even very in-depth.
I don’t have significant infrastructure needs, and when I have, the AWS TypeScript CDK has been
both sufficient as well as educational with its compiler hinting and documentation support.
The tipping point — waypoint
A week ago, I decided to hunker down and see how far I could get with trying out waypoint
.
Waypoint allows developers to deploy, manage, and observe their applications through a consistent abstraction of underlying infrastructure. Waypoint works with Kubernetes, ECS and many other platforms.
I referenced the AWS Lambda Tutorial,
worked around some hiccups (like image and function architecture mismatch 1) and to my surprise, I ended
up ticking off the previous 3 items on my todo list. Thank you, waypoint
!
The following section is essentially the whole project.
The code
The amount of code needed to get this project up and running is pretty light.
Containerized Application
The secret to running express.js
on lambda is
@vendia/serverless-express
, which handles the
mapping of a few supported AWS event objects (API Gateway, ALB, and Lambda@Edge) to and from the express.js
Request
and Response
objects.
The GraphQL
portion is handled by
apollo-server-lambda
,
which simply wraps @vendia/serverless-express
.
Dockerfile
It’s worth noting the special /var/task
directory, which is where Lambda expects container
code to exist, by default. 2
Application code
This is a minimal GraphQL server implementation, with one RESTDataSource
to
prove out external data fetching.
waypoint.hcl
waypoint
, similar to terraform
, uses HCL
to define the resources you want.
The highlighted lines were required for me since I’m using an M1 Macbook. 1
Deploying
Deploying was more or less simple.
I did go down some rabbit holes afterwards:
- How to resolve a DuplicateListener error 3
- How to enable HTTPS on an Application Load Balancer
Install waypoint
v0.7.1
Run the Waypoint server and run waypoint up
~/.aws/credentials
Waypoint should output a load balancer URL which is where the public can view the containerized app. It takes a few minutes for a brand new load balancer to be fully provisioned.
After doing some additional digging into Target Groups, Security Groups, SSL Certificates, I was able to add a pretty URL to the waypoint deployment. (I’ll try write about this endeavor in another blog post.)
...This URL may or may not work as I may tear down the deployment in the future.
Grok’ing the infrastructure
Here’s a brain dump of notes I took on the infrastucture that Waypoint created.
ECR
Waypoint builds a Docker
image, and publishes it to your image registry.
Lambda
Waypoint creates or publishes a new lambda function version that uses the previous image.
EC2
Waypoint creates...
- a Security Group with a default inbound rule, like “allow all traffic on port
80
”. - a Target Group that targets the previously created lambda function.
- an Application Load Balancer in some VPC (?) and the previously created security group.
- a Listener on port
80
that forwards traffic to the previously created Target Group.
Final thoughts
Waypoint is slick but has tons of room for polishing. As a developer, I feel like Waypoint resonates with me. I like being hands-on (...mostly) with every part of my stack, especially the cloud infrastructure portion. So I appreciate that Waypoint doesn’t rely on a 3rd party platform or abstraction over AWS, GCP, Azure, etc. — it’s still just you and your cloud infra.
I’ve been building and running Waypoint from source to get a feel for the codebase, as well its general architecture.
I’m also hoping to chip away at the following issue on my free time
I opened a pull request, #3032
, for:
arm64
function support for aws-lambda
deployments #3026
,
I’ve written a
I opened another pull request, go
-script to workaround#3035
, for another existing issue:
Lambda DuplicateListener error when releasing a 2nd time #2066
.
...⚠️ This is a hack! Don’t do this ⚠️...
Footnotes
-
See open issue:
arm64
function support foraws-lambda
deployments #3026 ↩ ↩2 -
See
WORKDIR
under “Container image overrides”: https://docs.aws.amazon.com/lambda/latest/dg/configuration-images.html ↩ -
See open issue: Lambda DuplicateListener error when releasing a 2nd time #2066 ↩