
Create an AWS Lambda function using a Container image (Dockerfile) stored in AWS ECR
Jan 22
5 min read
1
89
0

Overview
While creating an AWS Lambda function deployment package (zip file) for one of my ETL projects, we encountered the frustrating "service quota" issue—where the unzipped package size exceeded the allowable limit, resulting in excessive compute resource requirements.
In this post, we'll explore a more flexible approach by creating and deploying a Docker image to Amazon ECR for our AWS Lambda function:
Create a local directory to build our image. Every step will be handled in this directory.
Create a Python script that will be used as the Lambda function in this directory.
Also, we need to create a requirements.txt file for all the libraries used in the Python script.
In the end, we will create a Dockerfile which will be used to build the image.
Pre-requisites
Docker (minimum version 20.10.10 for Python 3.12 and later base images)
Python
Build a container image using an AWS base image for Python
Create a local directory for the project and navigate to it.
mkdir example
cd example
Create a new file named lambda_function.py with the following example:
import polars as pl
from helper import write_csv_s3, read_excel_s3
def lambda_handler(event, context):
es_data_sku_df = read_excel_s3(
key= AWS_ACCESS_KEY_ID,
secret= AWS_SECRET_ACCESS_KEY,
source= f"s3://{AWS_S3_BUCKET}/{AWS_KEY_RAW_EXCEL_ES_DATA_SKU}",
sheet_name= RAW_WS_EXCEL_ES_DATA_SKU,
)
if __name__ == "__main__":
lambda_handler(None, None)
Create a new file named requirements.txt with the following example:
polars
s3fs
fastexcel
Create a Dockerfile with the following configuration:
# Use a python image from AWS
FROM public.ecr.aws/lambda/python:3.12
# Copy requirements.txt into the right directory for the lambda function
COPY requirements.txt ${LAMBDA_TASK_ROOT}
# Install the specified packages (and cache the downloaded packages)
RUN --mount=type=cache,target=/root/.cache/pip pip install -r requirements.txt
# Copy function code
COPY lambda_function.py ${LAMBDA_TASK_ROOT}
COPY helper.py ${LAMBDA_TASK_ROOT}
# Set the CMD to your handler (could also be done as a parameter override outside of the Dockerfile)
CMD [ "lambda_function.lambda_handler" ]
Set the FROM property to the URI of the base image.
Use the COPY command to transfer the Lambda function code and runtime dependencies from the local directory to the Lambda function's code path, denoted by the Lambda-defined environment variable {LAMBDA_TASK_ROOT}
Set the CMD argument to the Lambda function handler.
Build the Docker image with the docker build command. The following example names the image docker-image and gives it the test tag.
docker build --platform linux/amd64 -t docker-image:test .
Note: The command includes the --platform linux/amd64 option to ensure compatibility with the Lambda execution environment, regardless of the architecture of your build machine (e.g., local machine). If you're targeting a Lambda function that uses the ARM64 instruction set architecture, replace the --platform option with --platform linux/arm64 instead.
(Optional) Test the image locally
Start the Docker image using the docker run command. In this example, docker-image is the image name and test is the tag.
docker run --platform linux/amd64 -p 9000:8080 -v ~/.aws:/root/.aws docker-image:test
Note: The -p 9000:8080 option creates a local endpoint at localhost:9000/2015-03-31/functions/function/invocations. The -v ~/.aws:/root/.aws option mounts the .aws folder from your home directory to the container’s .aws folder, enabling access to your AWS credentials while running the container locally.
In a new terminal, send an event to the local endpoint at port 9000. In PowerShell, use the following Invoke-WebRequest command:
Invoke-WebRequest -Uri "http://localhost:9000/2015-03-31/functions/function/invocations" -Method Post -Body '{}' -ContentType "application/json"
This command invokes the function with an empty event and returns a response.
Get the container ID.
docker ps
Use the docker kill command to stop the container. Replace 1234567890 with the container ID from the previous step.
docker kill 1234567890
Deploying the image: Upload the Docker image to AWS ECR and create a Lambda function that uses this image as its container
Go to AWS ECR -> Repositories -> Create Repository
AWS ECR Create Repository page
Note: Select Private for a private repository.
After assigning a specific name to the repository, such as "lambda_function_docker_repository", click on Create repository
On the main page of our repository, click View push commands.
Note: Ensure you are inside the main working directory (i.e., the local directory). Additionally, verify that you have the necessary IAM permissions to push an image to an AWS ECR repository. The AWS ECR repository must also be in the same AWS Region as the Lambda function.
At this point, ensure that AWS is configured locally using the aws configure command and that Docker is up and running. Then, execute the commands listed under View push commands one by one.
3.1. Run the get-login-password command to authenticate the Docker CLI with your AWS ECR registry.
aws ecr get-login-password --region [region] | docker login --username AWS --password-stdin [aws_account_id].dkr.ecr.[region].amazonaws.com
Replace [aws_account_id] with your AWS account ID
Set the [region] value to the AWS Region where you created the ECR repository, such as ap-southeast-1
3.2. Run the docker tag command to tag your local image as the latest version in your AWS ECR repository.
docker tag docker-image:test [aws_account_id].dkr.ecr.[region].amazonaws.com/[repository_name]:latest
Replace [aws_account_id] with your AWS account ID
Set the [region] value to the AWS Region where you created the ECR repository, such as ap-southeast-1
Replace [repository_name] with the name of your AWS ECR repository, such as lambda_function_docker_repository
Make sure to include the :latest tag at the end of the repository URI
3.3. Use the docker push command to upload your local image to the AWS ECR repository for deployment.
docker push [aws_account_id].dkr.ecr.[region].amazonaws.com/[repository_name]:latest
Replace [aws_account_id] with your AWS account ID
Set the [region] value to the AWS Region where you created the ECR repository, such as ap-southeast-1
Replace [repository_name] with the name of your AWS ECR repository, such as lambda_function_docker_repository
Make sure to include the :latest tag at the end of the repository URI
Create the Lambda function from the Docker image by following these steps:
Lambda -> Functions -> Create Function -> Container image
Function name: We can give whatever name we want to our function.
Container image URI: Click Browse for the Docker image we created and select it.
Architecture: Select x86_64
Change default execution role: We can choose the suitable IAM role in case we need it.
Click on Create function
Updating the AWS Lambda function code
To update the function code, rebuild the image, upload the new version to the Amazon ECR repository, and then use the update-function-code command to deploy the updated image to the Lambda function.
Lambda resolves the image tag to a specific image digest. This means that if you point the same image tag to a new image in Amazon ECR, Lambda will not automatically update the function to use the new image. To deploy the updated image to the same Lambda function, you must use the update-function-code command, even if the image tag in Amazon ECR remains unchanged.
aws lambda update-function-code --function-name [my-function] --image-uri [aws_account_id].dkr.ecr.[region].amazonaws.com/[repository_name]:latest
Set the [my-function] to the AWS Lambda function name
Replace [aws_account_id] with your AWS account ID
Set the [region] value to the AWS Region where you created the ECR repository, such as ap-southeast-1
Replace [repository_name] with the name of your AWS ECR repository, such as lambda_function_docker_repository
Make sure to include the :latest tag at the end of the repository URI
Reference
Using an AWS base image for Python
Pushing a Docker image to an Amazon ECR private repository
About

Benjamin ("Benj") Tabares Jr. is an experienced data practitioner with a strong track record of successfully delivering short- and long-term projects in data engineering, business intelligence, and machine learning. Passionate about solving complex customer challenges, Benj leverages data and technology to create impactful solutions. He collaborates closely with clients and stakeholders to deliver scalable data solutions that unlock business value and drive meaningful insights from data.