SHARE

Run Amazon Lambda Locally with Docker

Published:
Sep 5, 2021
srvrlss.io Team
Updated:
Dec 13, 2022

In this post, we’ll turn a simple AWS Lambda function into a running Docker container so you can test your functions locally on your own machine. This greatly improves efficiency testing and speeds up your development process.

Last update: Dec 13, 2022

The setup

Debugging Lambdas is not easy. How can we run functions locally for easier testing?

Let’s say you have a folder that contains just two files for an AWS function:

1
2
3
4
$ ls -lash
 0 drwxr-xr-x  26 srvrlss  srvrlss   832B Aug 25 11:53 .
 8 -rw-r--r--   1 srvrlss  srvrlss   500K Aug 24 12:02 index.js
 8 -rw-r--r--   1 srvrlss  srvrlss   156B Aug 24 13:54 package.json

Contents of index.js:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
exports.handler = async (event, context) => {
  let body = JSON.stringify({hello: "world"});
  let statusCode = 200;
  console.log("body stringified" + body);

  return {
    statusCode,
    body,
    // headers
  };
};

Adding a Dockerfile

First, add a Docker file with Amazon’s basic Node.js Lambda image, as you see on line 1:

1
2
3
4
5
6
7
8
FROM amazon/aws-lambda-nodejs:14

COPY package.json ${LAMBDA_TASK_ROOT}
RUN npm install

COPY index.js ${LAMBDA_TASK_ROOT}

CMD ["index.handler"]
  • On line 3, we copy package.json into the container.
  • On line 4, we run the command to install any packages required for your function.
  • On line 6, we add your index.js file.
  • Finally, on line 8, we define what our function "handler" is.

*Note that ${LAMBDA_TASK_ROOT} is a variable that’s defined in the base Amazon image, so you don’t need to define it.

AWS automatically detects which of their supported languages you’re using based on the image specified on line 1 of the Docker file.

Building and Running the container

Now that we have a Docker file we can build this image with:

1
docker build . -t mylambda:latest

And execute it by running:

1
docker run -t mylambda:latest

If everything went well, you should see something in the likes of:

1
INFO[0000] exec '/var/runtime/bootstrap' (cwd=/var/task, handler=)

You now have you lambda running! Perfect, let’s restart, but now we’ll connect Lambdas' default port to our host so we can interact with it.

1
docker run -p 8080:8080 -t mylambda:latest

Intuitively, you’re inclined to open your browser and go directly to the page. However, that’s not how Amazon’s Lambdas work. They’re routed internally, so we can’t directly access them. Instead, we have to use a tool like Postman for example to execute a post request to a specific URL (someone from Amazon, please explain to me why this works like this):

1
/2015-03-31/functions/function/invocations

We need that URL to send the json contents we want the function to execute.

Interacting with your function

So we just learned that functions are a little hidden. No stress, we can still reach the function.

Here’s a simple curl call that will just invoke the function without anything else:

1
curl -XPOST "http://localhost:8080/2015-03-31/functions/function/invocations" -d '{}'

Response

If your container is running correctly, your function shell should now show a few extra lines with Amazon information, plus any other logging you might have added.

1
2
3
4
5
6
INFO[0003] extensionsDisabledByLayer(/opt/disable-extensions-jwigqn8j) -> stat /opt/disable-extensions-jwigqn8j: no such file or directory
WARN[0003] Cannot list external agents                   error="open /opt/extensions: no such file or directory"
START RequestId: 2e60c804-664b-4edf-9050-aa7fca84bb8b Version: $LATEST
2021-09-05T13:12:31.465Z	2e60c804-664b-4edf-9050-aa7fca84bb8b	INFO	body stringified{"hello":"world"}
END RequestId: 2e60c804-664b-4edf-9050-aa7fca84bb8b
REPORT RequestId: 2e60c804-664b-4edf-9050-aa7fca84bb8b	Init Duration: 0.41 ms	Duration: 113.84 ms	Billed Duration: 114 ms	Memory Size: 3008 MB	Max Memory Used: 3008 MB

That’s it!

Note: I added a console.log in the index.js file, which is the reason you will see the body stringified text in the response. It should contain the result of your executed code. Results may vary depending on your index.js contents.

Sadly, the solution feels rather hacky, and if you know of a better way to do this, we’re all ears. Share your thoughts with us!

We have also written a tutorial to run a Cloudflare Worker Locally

If you like this kind of content and would like more detailed or complex scenarios, help us by sharing this article or reaching out via the contact form!