Deploy Node.js Lambda functions with container images
There are three ways to build a container image for a Node.js Lambda function:
-
Using an AWS base image for Node.js
The AWS base images are preloaded with a language runtime, a runtime interface client to manage the interaction between Lambda and your function code, and a runtime interface emulator for local testing.
-
Using an AWS base image for custom runtimes
AWS provides base images
that contain the Amazon Linux or Amazon Linux 2 operating system and the runtime interface emulator. You can add your preferred runtime, dependencies, and code to these images. To make the image compatible with Lambda, you must include the runtime interface client for Node.js in the image. -
You can use an alternative base image from another container registry, such as Alpine Linux or Debian. You can also use a custom image created by your organization. To make the image compatible with Lambda, you must include the runtime interface client for Node.js in the image.
Tip
To reduce the time it takes for Lambda container functions to become active, see Use multi-stage builds
This page explains how to build, test, and deploy container images for Lambda.
Topics
AWS base images for Node.js
AWS provides the following base images for Node.js:
Tags | Runtime | Operating system | Dockerfile | Deprecation |
---|---|---|---|---|
18 |
Node.js 18 | Amazon Linux 2 | Dockerfile
for Node.js 18 on GitHub |
|
16 |
Node.js 16 | Amazon Linux 2 | Dockerfile
for Node.js 16 on GitHub |
Mar 11, 2024 |
14 |
Node.js 14 | Amazon Linux 2 | Dockerfile
for Node.js 14 on GitHub |
Nov 27, 2023 |
Amazon ECR repository: gallery.ecr.aws/lambda/nodejs
Using an AWS base image for Node.js
To complete the steps in this section, you must have the following:
To create a container image from an AWS base image for Node.js
-
Create a directory for the project, and then switch to that directory.
mkdir example cd example
-
Create a new Node.js project with
npm
. To accept the default options provided in the interactive experience, pressEnter
.npm init
-
Create a new file called
index.js
. You can add the following sample function code to the file for testing, or use your own.Example CommonJS handler
exports.handler = async (event) => { const response = { statusCode: 200, body: JSON.stringify('Hello from Lambda!'), }; return response; };
-
If your function depends on libraries other than the AWS SDK for JavaScript, use npm
to add them to your package. -
Create a new Dockerfile with the following configuration:
-
Set the
FROM
property to the URI of the base image. -
Use the COPY command to copy the function code and runtime dependencies to
{LAMBDA_TASK_ROOT}
. -
Set the
CMD
argument to the Lambda function handler.
Example Dockerfile
FROM
public.ecr.aws/lambda/nodejs:16
# Copy function code COPYindex.js
${LAMBDA_TASK_ROOT} # Set the CMD to your handler (could also be done as a parameter override outside of the Dockerfile) CMD [ "index.handler
" ] -
-
Build the Docker image with the docker build
command. The following example names the image docker-image
and gives it thetest
tag. docker build --platform linux/amd64 -t
docker-image
:test
.Note
The command specifies the
--platform linux/amd64
option to ensure that your container is compatible with the Lambda execution environment regardless of the architecture of your build machine. If you intend to create a Lambda function using the ARM64 instruction set architecture, be sure to change the command to use the--platform linux/arm64
option instead.
-
Start the Docker image with the docker run command. In this example,
docker-image
is the image name andtest
is the tag.docker run -p 9000:8080
docker-image
:test
This command runs the image as a container and creates a local endpoint at
localhost:9000/2015-03-31/functions/function/invocations
. -
From a new terminal window, post an event to the following endpoint using a curl command:
curl "http://localhost:9000/2015-03-31/functions/function/invocations" -d '{}'
This command invokes the function with an empty event and returns a response. If you're using your own function code rather than the sample function code, you might want to invoke the function with a JSON payload. Example:
curl "http://localhost:9000/2015-03-31/functions/function/invocations" -d '
{"payload":"hello world!"}
' -
Get the container ID.
docker ps
-
Use the docker kill
command to stop the container. In this command, replace 3766c4ab331c
with the container ID from the previous step.docker kill
3766c4ab331c
To upload the image to Amazon ECR and create the Lambda function
-
Run the get-login-password
command to authenticate the Docker CLI to your Amazon ECR registry. -
Set the
--region
value to the AWS Region where you want to create the Amazon ECR repository. -
Replace
111122223333
with your AWS account ID.
aws ecr get-login-password --region
us-east-1
| docker login --username AWS --password-stdin111122223333
.dkr.ecr.us-east-1
.amazonaws.com -
-
Create a repository in Amazon ECR using the create-repository
command. aws ecr create-repository --repository-name
hello-world
--image-scanning-configuration scanOnPush=true --image-tag-mutability MUTABLEIf successful, you see a response like this:
{ "repository": { "repositoryArn": "arn:aws:ecr:us-east-1:111122223333:repository/hello-world", "registryId": "111122223333", "repositoryName": "hello-world", "repositoryUri": "111122223333.dkr.ecr.us-east-1.amazonaws.com/hello-world", "createdAt": "2023-03-09T10:39:01+00:00", "imageTagMutability": "MUTABLE", "imageScanningConfiguration": { "scanOnPush": true }, "encryptionConfiguration": { "encryptionType": "AES256" } } }
-
Copy the
repositoryUri
from the output in the previous step. -
Run the docker tag
command to tag your local image into your Amazon ECR repository as the latest version. In this command: -
Replace
docker-image:test
with the name and tagof your Docker image. -
Replace
<ECRrepositoryUri>
with therepositoryUri
that you copied. Make sure to include:latest
at the end of the URI.
docker tag docker-image:test <ECRrepositoryUri>:latest
Example:
docker tag
docker-image
:test
111122223333
.dkr.ecr.us-east-1
.amazonaws.com/hello-world
:latest -
-
Run the docker push
command to deploy your local image to the Amazon ECR repository. Make sure to include :latest
at the end of the repository URI.docker push
111122223333
.dkr.ecr.us-east-1
.amazonaws.com/hello-world
:latest -
Create an execution role for the function, if you don't already have one. You need the Amazon Resource Name (ARN) of the role in the next step.
-
Create the Lambda function. For
ImageUri
, specify the repository URI from earlier. Make sure to include:latest
at the end of the URI.aws lambda create-function \ --function-name
hello-world
\ --package-type Image \ --code ImageUri=111122223333
.dkr.ecr.us-east-1
.amazonaws.com/hello-world
:latest \ --rolearn:aws:iam::111122223333:role/lambda-ex
-
Invoke the function.
aws lambda invoke --function-name
hello-world
response.jsonYou should see a response like this:
{ "ExecutedVersion": "$LATEST", "StatusCode": 200 }
-
To see the output of the function, check the
response.json
file.
To update the function code, you must build the image again, upload the new image to the Amazon ECR repository, and then use the update-function-code
Using an alternative base image with the runtime interface client
If you use a base image for custom runtimes or an alternative base image, you must include the runtime interface client in your image. The runtime interface client extends the Lambda runtime API, which manages the interaction between Lambda and your function code.Install the Node.js runtime interface client
npm install aws-lambda-ric
You can also download the Node.js runtime interface client
14.x
16.x
18.x
The following example demonstrates how to build a container image for Node.js using a non-AWS base image. The example Dockerfile uses a buster
base image. The Dockerfile includes the runtime interface client.
To complete the steps in this section, you must have the following:
To create a container image from a non-AWS base image
-
Create a directory for the project, and then switch to that directory.
mkdir example cd example
-
Create a new Node.js project with
npm
. To accept the default options provided in the interactive experience, pressEnter
.npm init
-
Create a new file called
index.js
. You can add the following sample function code to the file for testing, or use your own.Example CommonJS handler
exports.handler = async (event) => { const response = { statusCode: 200, body: JSON.stringify('Hello from Lambda!'), }; return response; };
-
Create a new Dockerfile. The following Dockerfile uses a
buster
base image instead of an AWS base image. The Dockerfile includes the runtime interface client, which makes the image compatible with Lambda. The Dockerfile uses a multi-stage build . The first stage creates a build image, which is a standard Node.js environment where the function's dependencies are installed. The second stage creates a slimmer image which includes the function code and its dependencies. This reduces the final image size. -
Set the
FROM
property to the base image identifier. -
Use the
COPY
command to copy the function code and runtime dependencies. -
Set the
ENTRYPOINT
to the module that you want the Docker container to run when it starts. In this case, the module is the runtime interface client. -
Set the
CMD
argument to the Lambda function handler.
Example Dockerfile
# Define custom function directory ARG FUNCTION_DIR="/function" FROM
node:18-buster
as build-image # Include global arg in this stage of the build ARG FUNCTION_DIR # Install build dependencies RUN apt-get update && \ apt-get install -y \ g++ \ make \ cmake \ unzip \ libcurl4-openssl-dev # Copy function code RUN mkdir -p ${FUNCTION_DIR} COPY . ${FUNCTION_DIR} WORKDIR ${FUNCTION_DIR} # Install Node.js dependencies RUN npm install # Install the runtime interface client RUN npm install aws-lambda-ric # Grab a fresh slim copy of the image to reduce the final size FROMnode:18-buster-slim
# Required for Node runtimes which use npm@8.6.0+ because # by default npm writes logs under /home/.npm and Lambda fs is read-only ENV NPM_CONFIG_CACHE=/tmp/.npm # Include global arg in this stage of the build ARG FUNCTION_DIR # Set working directory to function root directory WORKDIR ${FUNCTION_DIR} # Copy in the built dependencies COPY --from=build-image ${FUNCTION_DIR} ${FUNCTION_DIR} # Set runtime interface client as default command for the container runtime ENTRYPOINT ["/usr/local/bin/npx", "aws-lambda-ric"
] # Pass the name of the function handler as an argument to the runtime CMD ["index.handler
"] -
-
Build the Docker image with the docker build
command. The following example names the image docker-image
and gives it thetest
tag. docker build --platform linux/amd64 -t
docker-image
:test
.Note
The command specifies the
--platform linux/amd64
option to ensure that your container is compatible with the Lambda execution environment regardless of the architecture of your build machine. If you intend to create a Lambda function using the ARM64 instruction set architecture, be sure to change the command to use the--platform linux/arm64
option instead.
Use the runtime interface emulator to locally test the image. You can build the emulator into your image or install it on your local machine.
To install and run the runtime interface emulator on your local machine
-
From your project directory, run the following command to download the runtime interface emulator (x86-64 architecture) from GitHub and install it on your local machine.
mkdir -p ~/.aws-lambda-rie && \ curl -Lo ~/.aws-lambda-rie/aws-lambda-rie https://github.com/aws/aws-lambda-runtime-interface-emulator/releases/latest/download/aws-lambda-rie && \ chmod +x ~/.aws-lambda-rie/aws-lambda-rie
To install the arm64 emulator, replace the GitHub repository URL in the previous command with the following:
https://github.com/aws/aws-lambda-runtime-interface-emulator/releases/latest/download/aws-lambda-rie-arm64
-
Start the Docker image with the docker run command. Note the following:
-
docker-image
is the image name andtest
is the tag. -
/usr/local/bin/npx aws-lambda-ric index.handler
is theENTRYPOINT
followed by theCMD
from your Dockerfile.
docker run -d -v ~/.aws-lambda-rie:/aws-lambda -p 9000:8080 \ --entrypoint /aws-lambda/aws-lambda-rie \
docker-image:test
\/usr/local/bin/npx aws-lambda-ric index.handler
This command runs the image as a container and creates a local endpoint at
localhost:9000/2015-03-31/functions/function/invocations
. -
-
Post an event to the following endpoint using a curl command:
curl "http://localhost:9000/2015-03-31/functions/function/invocations" -d '{}'
This command invokes the function with an empty event and returns a response. Some functions might require a JSON payload. Example:
curl "http://localhost:9000/2015-03-31/functions/function/invocations" -d '
{"payload":"hello world!"}
' -
Get the container ID.
docker ps
-
Use the docker kill
command to stop the container. In this command, replace 3766c4ab331c
with the container ID from the previous step.docker kill
3766c4ab331c
To upload the image to Amazon ECR and create the Lambda function
-
Run the get-login-password
command to authenticate the Docker CLI to your Amazon ECR registry. -
Set the
--region
value to the AWS Region where you want to create the Amazon ECR repository. -
Replace
111122223333
with your AWS account ID.
aws ecr get-login-password --region
us-east-1
| docker login --username AWS --password-stdin111122223333
.dkr.ecr.us-east-1
.amazonaws.com -
-
Create a repository in Amazon ECR using the create-repository
command. aws ecr create-repository --repository-name
hello-world
--image-scanning-configuration scanOnPush=true --image-tag-mutability MUTABLEIf successful, you see a response like this:
{ "repository": { "repositoryArn": "arn:aws:ecr:us-east-1:111122223333:repository/hello-world", "registryId": "111122223333", "repositoryName": "hello-world", "repositoryUri": "111122223333.dkr.ecr.us-east-1.amazonaws.com/hello-world", "createdAt": "2023-03-09T10:39:01+00:00", "imageTagMutability": "MUTABLE", "imageScanningConfiguration": { "scanOnPush": true }, "encryptionConfiguration": { "encryptionType": "AES256" } } }
-
Copy the
repositoryUri
from the output in the previous step. -
Run the docker tag
command to tag your local image into your Amazon ECR repository as the latest version. In this command: -
Replace
docker-image:test
with the name and tagof your Docker image. -
Replace
<ECRrepositoryUri>
with therepositoryUri
that you copied. Make sure to include:latest
at the end of the URI.
docker tag docker-image:test <ECRrepositoryUri>:latest
Example:
docker tag
docker-image
:test
111122223333
.dkr.ecr.us-east-1
.amazonaws.com/hello-world
:latest -
-
Run the docker push
command to deploy your local image to the Amazon ECR repository. Make sure to include :latest
at the end of the repository URI.docker push
111122223333
.dkr.ecr.us-east-1
.amazonaws.com/hello-world
:latest -
Create an execution role for the function, if you don't already have one. You need the Amazon Resource Name (ARN) of the role in the next step.
-
Create the Lambda function. For
ImageUri
, specify the repository URI from earlier. Make sure to include:latest
at the end of the URI.aws lambda create-function \ --function-name
hello-world
\ --package-type Image \ --code ImageUri=111122223333
.dkr.ecr.us-east-1
.amazonaws.com/hello-world
:latest \ --rolearn:aws:iam::111122223333:role/lambda-ex
-
Invoke the function.
aws lambda invoke --function-name
hello-world
response.jsonYou should see a response like this:
{ "ExecutedVersion": "$LATEST", "StatusCode": 200 }
-
To see the output of the function, check the
response.json
file.
To update the function code, you must build the image again, upload the new image to the Amazon ECR repository, and then use the update-function-code