Serverless Functions and Serverless Containers

The same application in both AWS Lamda (function) and AWS Fargate (container)

Lately, I've been playing with serverless architectures. I noticed there is a lot of hype around serverless functions, but there doesn't seem to be a great deal written about the differences and similarities between serverless functions and serverless containers. While all cloud platforms currently provide a runtime for both serverless functions and self-managed container clusters, it is also becoming easier to use containers in a 'serverless' fashion. That is, without the need to manage Kubernetes clusters.

There are examples for both approaches individually, but I couldn't find a good example comparing both at the same time. Hence, I created a repository from scratch that contains the same example application twice:

  1. Serverless functions: AWS Lambda functions with an API Gateway
  2. Serverless containers: AWS Fargate (ECS) containers with a load balancer

The examples are meant to make it easy to compare both alternatives.

A common demo UI is provided (html/index.html) that allows switching between the two backends. Both versions use the same storage (a DynamoDB table) and share the same code (src/common.py). Wrappers are provided to handle the API Gateway events (Functions approach) or serve a simple Flask-based REST endpoint (Container approach). Deploying the stack will update the URLs in the demo UI (src/urls.js), which can be opend locally, or potentially be deployed to S3/CloudFront or elsewhere.

ui-screenshot

The full stack is defined in an AWS CloudFormation template (template.yaml), backed by AWS SAM. A full deployment includes a few additional steps, so a deployment script has been provided (deploy.sh).

stack-architecture

Note that this repo is meant as a demo, and the stack only includes the absolute minimum necessary to create a working app. This demo is not meant to be used as template for production-ready applications. The CloudFormation template includes some hints about missing resources and security good practices.

Some learnings from the process:

  • Containers need plenty of components: even if both approaches are "serverless" in the sense that we don't have to manage EC2 instances, the Container approach still needs an awful large amount of components to get started. We need a VPC, network components, a load balancer, scaling config, lots of Fargate components, and quite a bit of configuration between them. I spent at least a day getting everything set up.
  • The Lambda/API Gateway approach, in contrast, already comes with load balancing, concurrency, auto-scaling, and a VPC built-in. The AWS SAM framework comes with some handy 'meta' serverless resources; maybe it's time to create similar shortcuts for containers (AWS::Serverless::Container)?
  • Endpoint configuration: the Lambda variant configures the REST endpoints inside the CloudFormation template (and hence the endpoints scale independently), while the container variant has them all served together configured in code (although multiple containers & scaling policies could be made if necessary). The payloads are also slightly different, due to the API Gateway proxy event that differs from the events provided by the framework inside your container (Flask in this case).

For details on how to deploy and test the application, have a look at the repository's readme:

https://github.com/turiphro/aws-serverless-functions-and-serverless-containers

 

        -------------------------------------
        |                                   |
        |           related graph           |
        |          /             \          |
        |       graphs         relations    |
        |                                   |
        -------------------------------------
        

Resources

  • Repository