Run AWS Lambda using custom docker container

[LAST UPDATED: 29-July-2022]

I wrote about building and deploying a AWS Lambda using SAM CLI previously.

In this guide, we try to run a Lambda function inside a container.

Why run Lambda in Docker?

For a very simple reason, Lambda runtimes are standardised environments where you can only use what they provide and they do not provide a lot. E.g. if your application required any binary to be installed you coudn't do that on Lambda.

But in 2020 Re:invent, AWS launched Container Image Support for Lambda for container images up to 10 GB in size. While for this may not be important for "one-off functions", but for many use cases such as machine learning models etc, the developmental workflow typically includes Dockers and that is where it gets tricky deploying them to AWS Lambda.

Setting up the development environment.

You need Docker & VSCode to be installed on your system for this guide. Download fromt he provided links and install.

Then follow the following steps.

Step 1: Install Python using these instructions.

Step 2: Install AWS CLI

Step 3: Install SAM CLI

Step 4: Configure AWS & AWS CLI

Create a new app

Run the below in your terminal to create a new SAM application

sam init --package-type Image

This will start the interactive session to create your app. Choose Option as per below

Which template source would you like to use?
        1 - AWS Quick Start Templates
        2 - Custom Template Location
Choice: 1

Choose an AWS Quick Start application template
        1 - Hello World Example
        2 - Machine Learning
Template: 1

Which runtime would you like to use?
        1 - dotnet6
        2 - dotnet5.0
        3 - dotnetcore3.1
        4 - go1.x
        5 - java11
        6 - java8.al2
        7 - java8
        8 - nodejs16.x
        9 - nodejs14.x
        10 - nodejs12.x
        11 - python3.9
        12 - python3.8
        13 - python3.7
        14 - python3.6
        15 - ruby2.7
Runtime: 11

Based on your selections, the only dependency manager available is pip.
We will proceed copying the template using pip.

Would you like to enable X-Ray tracing on the function(s) in your application?  [y/N]:  

Project name [sam-app]: selenium

Cloning from https://github.com/aws/aws-sam-cli-app-templates (process may take a moment)

    -----------------------
    Generating application:
    -----------------------
    Name: selenium
    Base Image: amazon/python3.9-base
    Architectures: x86_64
    Dependency Manager: pip
    Output Directory: .

    Next steps can be found in the README file at ./selenium/README.md

Understanding the SAM generated application template

First, go to the selenium directory.

cd selenium

You should see the following files

.
├── README.md
├── __init__.py
├── events
│   └── event.json
├── hello_world
│   ├── Dockerfile
│   ├── __init__.py
│   ├── app.py
│   └── requirements.txt
├── template.yaml
└── tests
    ├── __init__.py
    └── unit
        ├── __init__.py
        └── test_handler.py

Compared to the standard Lambda example, this has an additional file, the Dockerfile that contains the instructions to build the container where the lambda will be executed.

FROM public.ecr.aws/lambda/python:3.9

COPY app.py requirements.txt ./

RUN python3.9 -m pip install -r requirements.txt -t .

# Command can be overwritten by providing a different command in the template directly.
CMD ["app.lambda_handler"]

The first thing you notice is, this image is building on top of an image from AWS's pubic container registry.

NOTE: You can also use non-AWS images such as those based on Alpine or Debian, however, the container image must include Lambda Runtime API. So if you use a non-AWS image, you will need to add them manually otherwise your app will not work.

And the final line is responsible for running the lambda_handler() function that in defined under twitter/hello_world/app.py.

Build the project

To build the app, run the following

sam build

You need Docker & Python3.9 to be installed for this to work

Sam build success

Test the build

To test if you application is working correctly, run

sam local invoke

Again, you need Docker & Python3.9 to be installed for this to work

You should see the following output:

Sam local invoke success

Deploy the project

Now there are three more steps that needs to be performed, but in our case, SAM CLI will do them in one go.

These steps are (again, we don't need to do them if using SAM CLI) 1. We need to rename the tag of our docker container to push it to the repository. 2. Login from Docker CLI to ECR repository 3. Push the image to ECR repository

All we need to do now is

sam deploy --guided

This will start an interactive delployment session, choose options as below (blank means leave the defaults)

Configuring SAM deploy
======================

        Looking for config file [samconfig.toml] :  Not found

        Setting default arguments for 'sam deploy'
        =========================================
        Stack Name [sam-app]: hello-world
        AWS Region [us-east-1]: 
        #Shows you resources changes to be deployed and require a 'Y' to initiate deploy
        Confirm changes before deploy [y/N]: 
        #SAM needs permission to be able to create roles to connect to the resources in your template
        Allow SAM CLI IAM role creation [Y/n]: y
        #Preserves the state of previously provisioned resources when an operation fails
        Disable rollback [y/N]: 
        HelloWorldFunction may not have authorization defined, Is this okay? [y/N]: y
        Save arguments to configuration file [Y/n]: 
        SAM configuration file [samconfig.toml]: 
        SAM configuration environment [default]: 

After that, if will further ask for confirmation on creating ECR repository:

Create managed ECR repositories for all functions? [Y/n]: Y

This will deploy your app to AWS and you should see a final confirmation output similar to below. Note the URL of the API highlighted in the output.

sam deploy success

Test the deployed app

Fetch the URL of the API from the output above and send a GET request to the API using the below command.

curl -X GET https://lndcelxeyg.execute-api.us-east-1.amazonaws.com/Prod/hello

In response, you should see:

{
  "message": "hello world!"
}

Clean up and delete the app

To delete the app, run the following

sam delete

You will be asked for below confirmations:

Are you sure you want to delete the stack hello-world in the region us-east-1 ? [y/N]: y
  Are you sure you want to delete the folder hello-world in S3 which contains the artifacts? [y/N]: y
  Found ECR Companion Stack hello-world-20953121-CompanionStack

  Do you you want to delete the ECR companion stack hello-world-20953121-CompanionStack 
  in the region us-east-1 ? [y/N]: y

  ECR repository helloworld20953121/helloworldfunction19d43fc4repo may not be empty. 
  Do you want to delete the repository and all the images in it ? [y/N]: y

You app is deleted.

Need Help? Open a discussion thread on GitHub.

Related Posts