How to deploy your AWS Lambda based in containers with ECR

Lino Espinoza
Cloud Studio
Published in
4 min readFeb 21, 2024

--

In previous working experiences, I was used to building and deploying AWS Lambda functions with zip files stored in AWS S3. I hadn't had the opportunity to use containers instead, but there is a chance to try new ways of building solutions if you work in cloud development.

AWS Lambda deployed with containers
Photo by Fejuz on Unsplash

So, this post is about deploying an AWS Lambda function using container images stored in the AWS Elastic Container Registry. Let's jump on it.

Prerequisites

  • AWS Command Line Interface, aka AWS CLI.
  • Docker
  • Node.js

💡 To set up your AWS CLI, you can use Granted, as I explain in this blog post. 🙂

Creating a AWS Lambda Function

Create a directory called aws-lambda-nodejs-container. Bear with me; I like to have a well-structured name on my folders, even if this is just an example. 😉

mkdir aws-lambda-nodejs-container

Inside that folder, let's create a simple Node.js project with npm. You can accept the default options for this example.

cd aws-lambda-nodejs-container && npm init

Create a new lambda function in a new file index.mjs

export const lambdaHandler = async (event, context) => { 
const response = {
statusCode: 200,
body: JSON.stringify({ message: 'This is a successful response from AWS Lambda', })
};
return response;
};

Now, we need to create a simple Dockerfile with the configuration to create an image from the AWS EC Registry, COPY our lambda function code, RUN an install command, and finally, set the handler.

FROM public.ecr.aws/lambda/nodejs:20-arm64
COPY index.mjs ${LAMBDA_TASK_ROOT}
CMD ["index.lambdaHandler"]

Let's build our image; we are using an arm64 image. You can find a specific picture in the Amazon ECR Public Gallery → https://gallery.ecr.aws/lambda/nodejs

docker build --platform linux/arm64 -t docker-image:test .

If you want to test the image locally, docker is here to help you. Run your image like this:

docker run --platform linux/arm64 -p 9000:8080 docker-image:test

Then, invoke your lambda function:

curl "<http://localhost:9000/2015-03-31/functions/function/invocations>" -d '{}'

You will get something like this:

Deploying the image to AWS ECR and your lambda function to AWS

To accomplish this, we need to create an AWS ECR Repository; we can do this through the AWS Console, AWS CLI, or the AWS CDK. Now, I'm going to use the AWS CLI; you must have experience using the CLI for your AWS tasks.

First, we must authenticate the Docker CLI to your Amazon ECR Registry.

In this example, I'm setting the us-east-1 as the AWS Region where I want to create the Amazon ECR repository.
Replace the <aws-account-id> string ****with your AWS Account ID.

aws ecr get-login-password --region us-east-1 | docker login --username AWS --password-stdin <aws-account-id>.dkr.ecr.us-east-1.amazonaws.com

Now it is time to create your AWS ECR Repository

aws ecr create-repository --repository-name dev-repository --region us-east-1

Grab the value from the repositoryUri attribute for the next step.

{
"repository": {
"repositoryArn": "arn:aws:ecr:us-east-1:123456789012:repository/dev-repository",
"registryId": "705941374709",
"repositoryName": "dev-repository",
"repositoryUri": "123456789012.dkr.ecr.us-east-1.amazonaws.com/dev-repository",
"createdAt": "2024-02-17T16:02:31.898000-05:00",
"imageTagMutability": "MUTABLE",
"imageScanningConfiguration": {
"scanOnPush": false
},
"encryptionConfiguration": {
"encryptionType": "AES256"
}
}
}

We need to tag our local image. Also, you need to replace the <ECRrepositoryUri> with the value of the previous step.

docker tag docker-image:test <ECRrepositoryUri>:latest

Then, we push our image to the AWS ECR repository.

docker push <ECRrepositoryUri>:latest

Create an execution role for the AWS Lambda function: https://docs.aws.amazon.com/lambda/latest/dg/gettingstarted-awscli.html#with-userapp-walkthrough-custom-events-create-iam-role

Let's create an AWS Lambda function.

aws lambda create-function \\ 
--function-name nodejs-hello-world \\
--package-type Image \\
--code ImageUri=123456789012.dkr.ecr.us-east-1.amazonaws.com/dev-repository:latest \\
--role arn:aws:iam::123456789012:role/service-role/myNewFunction-role-67bgsgdp

You will get something like this.

{
"FunctionName": "nodejs-hello-world",
"FunctionArn": "arn:aws:lambda:us-east-1:705941374709:function:nodejs-hello-world",
"Role": "arn:aws:iam::705941374709:role/service-role/myNewFunction-role-67bgsgdp",
"CodeSize": 0,
"Description": "",
"Timeout": 3,
"MemorySize": 128,
"LastModified": "2024-02-18T01:51:12.111+0000",
"CodeSha256": "69b8fae1b0affd9d67c93341d0d3c07fbd85b702cf8cb97afaa1c32ffea4e331",
"Version": "$LATEST",
"TracingConfig": {
"Mode": "PassThrough"
},
"RevisionId": "60613992-6bb8-4258-9e60-5ed3efefec6f",
"State": "Pending",
"StateReason": "The function is being created.",
"StateReasonCode": "Creating",
"PackageType": "Image",
"Architectures": [
"x86_64"
],
"EphemeralStorage": {
"Size": 512
},
"SnapStart": {
"ApplyOn": "None",
"OptimizationStatus": "Off"
}
}

You can invoke the function,

aws lambda invoke --function-name nodejs-hello-world response.json

And get a response like this:

{
"StatusCode": 200,
"FunctionError": "Unhandled",
"ExecutedVersion": "$LATEST"
}

Remember, if you want to update the function code, you need to build the image again, upload it to the Amazon ECR Repository, and then use the update-function-code command to deploy the image to the Lambda function

That's it. I hope that you find this helpful.

See you in the next blog post!

--

--

Passionate about serverless technologies and cloud-native architectures, I enjoy speaking and sharing my experience in cloud development with the AWS Community.