Introduction
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, right?
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. πΒ https://dev.to/linoespinoza/how-to-manage-multiple-aws-account-profiles-with-granted-5ho3
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
-
Create a simple Node.js project with npm inside that folder. 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; };
-
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"]
-
Lets build our image, we are using an arm64 image. You can find a specific image 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 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, it would be best if you replaced the with the value of the previous step.
docker tag docker-image:test <ECRrepositoryUri>:latest
-
Finally, 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 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!
Hiππ»
My name is Lino, and I'm a builder who loves cloud technologies and serverless architectures. I write articles about these topics to share my knowledge and experience.
Don't forget to visit my Linktree to discover my projects π«°π»
Linktree: https://linktr.ee/linoespinoza
Follow me on dev.to for other articles ππ»
Top comments (2)
Hey @linoespinoza, thanks for the post ! Maybe in the title of the post you mean "How to deploy your AWS Lambda based in containers with AWS ECR" and not ECS ?
I understand that is this case you are using ECR(Elastic Container Registry) as a docker image repository and not ECS (Elastic Container Service), am I right ?
Thanks for the feedback, @hebertrfreitas. I already changed it. :)