Deploy Python Lambda functions with Docker

A python lambda function is the easiest way to start exploring the AWS ecosystem. We will later use an API Gateway that invokes the lambda.

Meher Howji avatar image
··- views
A random image as the post cover
Photo by Jeremy Bezanger on Unsplash

AWS Account Creation

The first thing we need to have is access to [[AWS]]. You will have to sign up and provide your credit card details for account creation. I created myself a new AWS account, incase I face any issue I can highlight possible solutions to you.

After creating my fresh new account, it looks something like this on my landing page. Hope it looks somewhat similar for you as well.

Getting Started

[[AWS Lambda]] is essentially a language-specific environment that runs in an execution environment called as runtime. This runtime passes events, context information and responses between other lambdas as well.

Install Python & PIP

Python should be most probably installed on your computer. You can test by running python --version or python3 --version. You can install Python from here: https://www.python.org/downloads/

Try running pip --version if its installed, if not then you can install it from here: https://pip.pypa.io/en/stable/installation/

Installing Docker

I installed [[Docker]] on my iMac using the GUI package as it would handle setting all the configuration and path correctly. There is a CLI option as well but I wouldn’t recommend it unless the GUI package is unable to install for you. Docker’s download page > https://docs.docker.com/desktop/

Installing AWS CLI

We would need the [[AWS CLI]] to push the docker container to the [[AWS ECR]] which is just a registry or repository for storing the images. I again used the GUI installer from here > https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html

Lets Create Our Codebase

Create Dockerfile

# source the base image
FROM public.ecr.aws/lambda/python:3.9
# copy function code
COPY app.py ${LAMBDA_TASK_ROOT}
# each required library is listed as a separate line
COPY requirements.txt .
RUN pip3 install -r requirements.txt
# set the cmd to the handler
CMD ["app.handler"]

Create Lambda Function

We will create a simple function that returns the parameter it receives. This way will get to see what information does our lambda function has available when it begins to run.

  • Event is a dict that contains the parameters which are sent when the function is invoked
  • Context param is the context in which the function is called
import jsonpickle
def handler(event, context):
return {
"EVENT": jsonpickle.encode(event),
"CONTEXT": jsonpickle.encode(context)
}

Create requirements.txt

jsonpickle==1.3

Running Lambda Container Locally

Build

docker build -t <container-name> .

e.g. if we name our container raring-rusty then the cmd will look like:

docker build -t raring-rusty .

After the build is complete, we can quickly verify by hitting the following command.

docker images

It should output something like this:

docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
raring-rusty latest a0ea76e99b97 1 minute ago 595MB

Before we can run the docker, we have to install a Runtime Interface Client which defines a HTTP interface for runtimes to receive invocation events from Lambda and respond.

Install RIC

pip install awslambdaric

Running

docker run -p 9000:8080 <container-name>:latest

e.g.

docker run -p 9000:8080 raring-rusty:latest

Testing Lambda Invocation

Using Postman

You can install Postman from here: https://www.postman.com/ and test the lambda function before deploying it to [[AWS ECR]]

URL

http://localhost:9000/2015-03-31/functions/function/invocations

Method

POST

Body -

  • Select raw as the body type and json as the format
{ "is_cat": "true" }

Authorization

No Auth

Using CURL

curl -XPOST "http://localhost:9000/2015-03-31/functions/function/invocations" -d '{"is_cat":"true"}'

Result

At this point you should get a response back from your lambda function. Mine looked like below:

{
"EVENT": "{\"is_cat\": \"true\"}",
"CONTEXT": "{\"_epoch_deadline_time_in_ms\": 1657690206053, \"aws_request_id\": \"048c7493-7487-4af8-9b28-6a774ccfad8c\", \"client_context\": null, \"function_name\": \"test_function\", \"function_version\": \"$LATEST\", \"identity\": {\"cognito_identity_id\": null, \"cognito_identity_pool_id\": null, \"py/object\": \"awslambdaric.lambda_context.CognitoIdentity\"}, \"invoked_function_arn\": \"arn:aws:lambda:us-east-1:012345678912:function:test_function\", \"log_group_name\": \"/aws/lambda/Functions\", \"log_stream_name\": \"$LATEST\", \"memory_limit_in_mb\": \"3008\", \"py/object\": \"awslambdaric.lambda_context.LambdaContext\"}"
}

In next part, let’s look at how we can push our docker image to [[AWS ECR]] i.e. Elastic Container Registry to which our [[AWS Lambda]] will point.