Getting started with AWS Lambda container support

AWS recently announced support for container images for its Lambda service. I’m a fan and advocate for all things serverless so any improvements in this space are always welcome. The following paragraphs attempt to share my initial findings as well as some tips to get started with this new capability.

The first thing to point out here is that container support does not mean Lambda can run any container. Instead you have the option of using one of the AWS base images or if you’re so inclined you can roll your own Lambda compliant custom image. Functions must also follow the Lambda event model and base images must implement the Lambda Runtime API. These idiomatic requirements prevent images from being run across any service or platforms and is an important distinction to note.

Image Types

AWS base image — These images are preloaded with one of the supported language runtimes along with all the other components required to run a container image in Lambda.

Custom image — Custom images must be compatible with Lambda. This requires implementing the Lambda Runtime API. Thankfully AWS is releasing Lambda Runtime Interface Clients for all supported runtimes so you don’t have to.

Lambda Runtime Interface

The Runtime Interface implements both the Runtime and Extensions API’s. Custom runtimes use the Runtime API to receive invocation events and send data back to Lambda within the execution environment while the Extensions API can be used to integrate Lambda with tools offering a variety of services such as security, observability, and monitoring.

Lambda Runtime Interface Emulator

The Runtime Interface Emulator comes preloaded on all AWS images providing a means to test the containerized functions locally. The emulator accepts HTTP requests which it then converts to JSON events which the Lambda function can handle.

Creating a base image

There are a couple of rules to follow when creating your base image. The container image must implement the Runtime API, it must be able run on a read-only file system, it should be able read all the files it needs using the default Lambda user and finally it can only be a Linux based image.

In this example I’m using one of the supported Go runtimes supplied from the AWS ECR public repo. The second line simply copies my Go application to the containers task root directory using the preconfigured ${LAMBDA_TASK_ROOT} environment variables supplied with the AWS base image.

Build, Test and Deploy

In this example I’m using AWS CDK to build and then deploy my container image to a private ECR repository. Before that however we can quickly test our image using the Runtime Interface Emulator.

My Lambda function is a crude variation of the mergesort algorithm, it takes two sorted arrays and returns a single combined array in linear time ( I’ll include a link to the full source at the end). I’m included a gist of the main function along with the referenced handler function with the purpose of highlighting the need for container functions to comply with the Lambda event model.

Using the Dockerfile, which was mentioned previously, the following commands can be issued to build and test the function.

1. Build our image
docker build -t myFirstImage:latest .
2. Run
docker run -p 9000:8000 myFirstImage:latest
3. Open a new terminal and use the Runtime Interface Emulator
curl -X POST "http://localhost:9000/2015-03-31/functions/function/invocations" -d '{}'

With the help of the Runtime Interface Emulator we can verify our function has correctly processed the incoming event and was also able to return data to the runtime environment.

curl -X POST "http://localhost:9000/2015-03-31/functions/function/invocations" -d '{}'
{"statusCode":200,"headers":{"Access-Control-Allow-Headers":"Content-Type,X-Amz-Date,Authorization,X-Api-Key,x-requested-with","Access-Control-Allow-Methods":"GET, OPTIONS, POST","Access-Control-Allow-Origin":"*","Content-Type":"application/json"},"multiValueHeaders":null,"body":"Array A: [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80] \n Array B [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80] \n Result: [0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13,14,14,15,15,16,16,17,17,18,18,19,19,20,20,21,21,22,22,23,23,24,24,25,25,26,26,27,27,28,28,29,29,30,30,31,31,32,32,33,33,34,34,35,35,36,36,37,37,38,38,39,39,40,40,41,41,42,42,43,43,44,44,45,45,46,46,47,47,48,48,49,49,50,50,51,51,52,52,53,53,54,54,55,55,56,56,57,57,58,58,59,59,60,60,61,61,62,62,63,63,64,64,65,65,66,66,67,67,68,68,69,69,70,70,71,71,72,72,73,73,74,74,75,75,76,76,77,77,78,78,79,79,80,80]"}

Now that we have confirmed our function is working locally we can push to AWS. CDK offers two options to deploy containerized functions;

  1. fromAssetImage — This options allows you to provide a path to your Dockerfile. AWS CDK uses the function defined by your Dockerfile as the function handler.
  2. fromEcrImage — If your image already exists in ECR you can choose this option and provide the repository URI.

In the following snippet we instruct CDK to look in the ‘image’ directory for the functions Dockerfile. The Go executable is also available in this path. CDK will build and push the image to the CDK default assets repository in ECR.

Once deployed we can test through our API Gateway endpoint

Mergesort response from our containerized function


Time will tell how popular Lambda’s containerized support will be, however I do feel it can have a far reaching appeal. Developers who have struggled with dependency management and or the challenges associated with installing native packages will welcome the supported 10GB container size. I also think a lot of applications running larger workload which would favor an event driven model will now give serious consideration to Lambda.

Tech Lead | AWS Community Builder | AWS Solutions Architect Pro | Passionate about learning | Languages include Java, Go, Typescript, and more recently Rust