Testing Lambda container images locally - AWS Lambda

Testing Lambda container images locally

You can use the Lambda runtime interface emulator to locally test a container image function before uploading it to Amazon Elastic Container Registry (Amazon ECR) and deploying it to Lambda. The emulator is a proxy for the Lambda runtime API. It's a lightweight web server that converts HTTP requests into JSON events to pass to the Lambda function in the container image.

The AWS base images and base images for custom runtimes include the runtime interface emulator. If you use an alternative base image, such as an Alpine Linux or Debian image, you can build the emulator into your image or install it on your local machine.

The runtime interface emulator is available on the AWS GitHub repository. There are separate packages for the x86-64 and arm64 architectures.

Guidelines for using the runtime interface emulator

Note the following guidelines when using the runtime interface emulator:

  • The RIE does not emulate Lambda security and authentication configurations, or Lambda orchestration.

  • Lambda provides an emulator for each of the instruction set architectures.

  • The emulator does not support AWS X-Ray tracing or other Lambda integrations.

Environment variables

The runtime interface emulator supports a subset of environment variables for the Lambda function in the local running image.

If your function uses security credentials, you can configure the credentials by setting the following environment variables:

  • AWS_ACCESS_KEY_ID

  • AWS_SECRET_ACCESS_KEY

  • AWS_SESSION_TOKEN

  • AWS_DEFAULT_REGION

To set the function timeout, configure AWS_LAMBDA_FUNCTION_TIMEOUT. Enter the maximum number of seconds that you want to allow the function to run.

The emulator does not populate the following Lambda environment variables. However, you can set them to match the values that you expect when the function runs in the Lambda service:

  • AWS_LAMBDA_FUNCTION_VERSION

  • AWS_LAMBDA_FUNCTION_NAME

  • AWS_LAMBDA_FUNCTION_MEMORY_SIZE

Testing images built from AWS base images

The AWS base images for Lambda include the runtime interface emulator. After building your Docker image, follow these steps to test it locally.

  1. Start the Docker image with the docker run command. In this example, docker-image is the image name and test 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.

  2. 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!"}'
  3. Get the container ID.

    docker ps
  4. 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

Testing images built from the provided.al2 base image

The base images for custom runtimes include the runtime interface emulator. After building your Docker image, follow these steps to test it locally.

  1. Start the Docker image with the docker run command.

    Node.js
    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
    • /usr/local/bin/npx aws-lambda-ric: The npx command to start the Node.js runtime interface client

    • index.handler: The Lambda function handler (usually the CMD in your Dockerfile)

    Python
    docker run -d -v ~/.aws-lambda-rie:/aws-lambda -p 9000:8080 \ --entrypoint /aws-lambda/aws-lambda-rie \ docker-image:test \ /usr/local/bin/python -m awslambdaric app.handler
    • usr/local/bin/python -m awslambdaric: The Python interpreter command to run the Python runtime interface client as a script

    • app.handler: The Lambda function handler (usually the CMD in your Dockerfile)

    Java
    docker run -d -v ~/.aws-lambda-rie:/aws-lambda -p 9000:8080 \ --entrypoint /aws-lambda/aws-lambda-rie \ docker-image:test \ /usr/bin/java -cp './*' com.amazonaws.services.lambda.runtime.api.client.AWSLambda example.App::sayHello
    • /usr/bin/java -cp './*' com.amazonaws.services.lambda.runtime.api.client.AWSLambda: Sets the classpath to the Java runtime interface client

    • app.handlerexample.App::sayHello: The Lambda function handler (usually the CMD in your Dockerfile)

    Go

    In the following example, /main is the binary that is compiled during the Docker build.

    docker run -d -v ~/.aws-lambda-rie:/aws-lambda -p 9000:8080 \ --entrypoint /aws-lambda/aws-lambda-rie \ docker-image:test \ /main
    Ruby
    docker run -d -v ~/.aws-lambda-rie:/aws-lambda -p 9000:8080 \ --entrypoint /aws-lambda/aws-lambda-rie \ docker-image:test \ aws_lambda_ric index.LambdaFunction::Handler.process
    • aws_lambda_ric: The Ruby runtime interface client

    • index.LambdaFunction::Handler.process: The Lambda function handler (usually the CMD in your Dockerfile)

    This command runs the image as a container and creates a local endpoint at localhost:9000/2015-03-31/functions/function/invocations.

  2. 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!"}'
  3. Get the container ID.

    docker ps
  4. 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

Testing images built from alternative base images

If you use an alternative base image, such as an Alpine Linux or Debian image, you can build the emulator into your image or install it on your local machine.

Building the runtime interface emulator into an image

To build the emulator into your image
  1. Create a script and save it in your project directory. Set execution permissions for the script file.

    The script checks for the presence of the AWS_LAMBDA_RUNTIME_API environment variable, which indicates the presence of the runtime API. If the runtime API is present, the script runs the runtime interface client. Otherwise, the script runs the runtime interface emulator.

    Choose your language to see an example script:

    Node.js

    In the following example, /usr/local/bin/npx aws-lambda-ric is the npx command to start the Node.js runtime interface client.

    Example entry_script.sh
    #!/bin/sh if [ -z "${AWS_LAMBDA_RUNTIME_API}" ]; then exec /usr/local/bin/aws-lambda-rie /usr/local/bin/npx aws-lambda-ric $@ else exec /usr/local/bin/npx aws-lambda-ric $@ fi
    Python

    In the following example, /usr/local/bin/python -m awslambdaric is the Python interpreter command to run the Python runtime interface client as a script.

    Example entry_script.sh
    #!/bin/sh if [ -z "${AWS_LAMBDA_RUNTIME_API}" ]; then exec /usr/local/bin/aws-lambda-rie /usr/local/bin/python -m awslambdaric $@ else exec /usr/local/bin/python -m awslambdaric $@ fi
    Java

    In the following example, /usr/bin/java -cp './*' com.amazonaws.services.lambda.runtime.api.client.AWSLambda sets the classpath to the Java runtime interface client.

    Example entry_script.sh
    #!/bin/sh if [ -z "${AWS_LAMBDA_RUNTIME_API}" ]; then exec /usr/local/bin/aws-lambda-rie /usr/bin/java -cp './*' com.amazonaws.services.lambda.runtime.api.client.AWSLambda $@ else exec /usr/bin/java -cp './*' com.amazonaws.services.lambda.runtime.api.client.AWSLambda $@ fi
    Go

    In the following example, /main is the binary that is compiled during the Docker build.

    Example entry_script.sh
    #!/bin/sh if [ -z "${AWS_LAMBDA_RUNTIME_API}" ]; then exec /usr/local/bin/aws-lambda-rie /main $@ else exec /main $@ fi
    Ruby

    In the following example, aws_lambda_ric is the Ruby runtime interface client.

    Example entry_script.sh
    #!/bin/sh if [ -z "${AWS_LAMBDA_RUNTIME_API}" ]; then exec /usr/local/bin/aws-lambda-rie aws_lambda_ric $@ else exec aws_lambda_ric $@ fi
  2. Download the runtime interface emulator for your target architecture from GitHub into your project directory. Lambda provides an emulator for each of the instruction set architectures.

    curl -Lo aws-lambda-rie https://github.com/aws/aws-lambda-runtime-interface-emulator/releases/latest/download/aws-lambda-rie \ && chmod +x 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
  3. Copy the script, install the emulator package, and change the ENTRYPOINT to the new script by adding the following lines to your Dockerfile.

    Example — Lines to add to Dockerfile
    COPY ./entry_script.sh /entry_script.sh ADD aws-lambda-rie /usr/local/bin/aws-lambda-rie ENTRYPOINT [ "/entry_script.sh" ]
  4. 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 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.

  5. Start the Docker image with the docker run command.

    Node.js
    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
    • /usr/local/bin/npx aws-lambda-ric: The npx command to start the Node.js runtime interface client

    • index.handler: The Lambda function handler (usually the CMD in your Dockerfile)

    Python
    docker run -d -v ~/.aws-lambda-rie:/aws-lambda -p 9000:8080 \ --entrypoint /aws-lambda/aws-lambda-rie \ docker-image:test \ /usr/local/bin/python -m awslambdaric app.handler
    • usr/local/bin/python -m awslambdaric: The Python interpreter command to run the Python runtime interface client as a script

    • app.handler: The Lambda function handler (usually the CMD in your Dockerfile)

    Java
    docker run -d -v ~/.aws-lambda-rie:/aws-lambda -p 9000:8080 \ --entrypoint /aws-lambda/aws-lambda-rie \ docker-image:test \ /usr/bin/java -cp './*' com.amazonaws.services.lambda.runtime.api.client.AWSLambda example.App::sayHello
    • /usr/bin/java -cp './*' com.amazonaws.services.lambda.runtime.api.client.AWSLambda: Sets the classpath to the Java runtime interface client

    • app.handlerexample.App::sayHello: The Lambda function handler (usually the CMD in your Dockerfile)

    Go

    In the following example, /main is the binary that is compiled during the Docker build.

    docker run -d -v ~/.aws-lambda-rie:/aws-lambda -p 9000:8080 \ --entrypoint /aws-lambda/aws-lambda-rie \ docker-image:test \ /main
    Ruby
    docker run -d -v ~/.aws-lambda-rie:/aws-lambda -p 9000:8080 \ --entrypoint /aws-lambda/aws-lambda-rie \ docker-image:test \ aws_lambda_ric index.LambdaFunction::Handler.process
    • aws_lambda_ric: The Ruby runtime interface client

    • index.LambdaFunction::Handler.process: The Lambda function handler (usually the CMD in your Dockerfile)

    This command runs the image as a container and creates a local endpoint at localhost:9000/2015-03-31/functions/function/invocations.

  6. 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!"}'
  7. Get the container ID.

    docker ps
  8. 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

Install the runtime interface emulator locally

To install the runtime interface emulator on your local machine, download the package for your preferred architecture from GitHub. Then, use the docker run command to start the container image and set the --entrypoint to the emulator. For more information, choose the instructions for your preferred language: