AWS is an essential tool in many developersโ toolboxes, but using AWS in a development environment can be tricky. Developers who just want to write some code are often frustrated using the AWS console and setting up AWS services.
LocalStack to the rescue!
LocalStack is a service that mocks AWS locally in a docker container on the your computer. With LocalStack, you don't need to worry about connecting to an actual AWS server. This post will walk you through setting up a docker container running LocalStack so that you can run AWS services locally.
If youโd like to jump straight into the final code, check out the Github repo. Or, keep reading for a step-by-step guide to running AWS services locally.
Make sure you have Docker and AWS CLI installed on your computer. You will be using the following AWS services: Lambda, SQS, SNS, S3, and IAM.
Setting Up LocalStack
Create a docker-compose.yml file in your root directory.
Here you will add LocalStack to services and set the environmental variables.
docker-compose.yml
version: '3.8' |
In SERVICES
, you declare which AWS services you will be using, such as in this example: sqs, sns, iam, s3, and lambda.
The AWS_DEFAULT_REGION, AWS_ACCESS_KEY, and AWS_SECRET_ACCESS_KEY are required by LocalStack and are filled with dummy data.
Next, create a create-resources.sh file.
create-resources.sh
echo "All resources initialized! ๐" |
This shell script will run on container startup. Right now, it's empty, but you're going to fill it with commands.
Run docker-compose up
and see that All resources initialized! ๐
.
You can also see the status of all AWS services hosted by LocalStack by going to:
Thatโs it. You have now set up LocalStack on your computer. Now it's time to add some resources to create-resources.sh and test them out.
First create a SQS queue named testQueue:
echo "Create SQS queue testQueue" |
If you stop and start docker-compose, you can test that this is working by running:
aws sqs send-message --endpoint-url=http://localhost:4566 --queue-url http://localhost:4576/000000000000/testQueue --region us-east-1 --message-body 'Test Message!'
LocalStack will return:
Next create an SNS topic named testTopic and subscribe testQueue to it:
echo "Create SNS Topic testTopic" |
The sns subscribe
command will subscribe testQueue to testTopic. When you publish a message to testTopic, it will be passed on to testQueue.
This can be modified to accommodate different services such as SMS or email by changing
--protocol sqs
to your preferred service.
Lets quickly test these commands by running docker-compose down
and then docker-compose up
to rerun our newly updated script. You should see this in your terminal:
You can see that testQueue, testTopic and a subscription were all created and are ready to be used.
Sending a test SQS message by running:
aws sns publish--endpoint-url=http://localhost:4566 --topic-arn arn:aws:sns:us-east-1:000000000000:testTopic --region us-east-1 --message 'Test Topic!'
should return:
Creating Your Lambda
The first thing you will do is set up the lambda function handler. Create a src directory and then create index.js inside of it.
index.js
const dayjs = require('dayjs'); |
The function above receives an event and prints out the eventโs details alongside printing a message using an external package: dayjs.
Create package.json in the src directory.
package.json
{ |
Add any external dependencies your lambda function uses to the dependencies list.
AWS lambda expects a zip file with the function handler inside. You can do this with in a Dockerfile.
Create a Dockerfile and add this:
Dockerfile
FROM node:15 as lambda |
This will install any external dependencies and zip the src directory. It will then move the zip file into the LocalStack directory.
Change your docker-compose.yml to include the Dockerfile by removing:
image: localstack/localstack |
adding:
network_mode: bridge |
and adding - LAMBDA_EXECUTOR=local
to environment
.
Your docker-compose.yml should now look like this:
version: '3.8'services: |
LAMBDA_EXECUTOR
supports 3 different options:
local: runs the lambda in the current LocalStack container.
docker: creates a new lambda container, everytime the lambda is invoked. This is the default option .
docker-reuse: creates a new lambda container that stays open for future lambda invocations.
Back in create-resources.sh, add these commands:
echo "Create admin" |
These commands will create an admin role using IAM, make an S3 bucket and upload the lambda handler function to the bucket.
Finally, you will create the lambda function and then set an event source mapper to it.
echo "Create the lambda exampleLambda" |
You can see that the S3 bucket and zip file are both declared here and the handler function is declared.
In the event source mapping command, the testQueue Arn is used for triggering the lambda.
With this file, your lambda function will be ready to receive messages from testTopic and testQueue.
Testing Your Lambda
Run docker-compose down
to remove the container and docker-compose up
to build the container again.
You will see the container startup, LocalStack initializing, and your create-resources.sh running in your terminal.
Once all your resources are created, run the following command in your CLI to publish an SNS message to testTopic:
aws sns publish --endpoint-url=http://localhost:4566 --topic-arn arn:aws:sns:us-east-1:000000000000:testTopic --region us-east-1 --message 'Test Topic!'
Alternatively, you can send an SQS message directly to testQueue:
aws sqs send-message --endpoint-url=http://localhost:4566 --queue-url http://localhost:4576/000000000000/testQueue --region us-east-1 --message-body 'Test Message!'
You should see that the lambda was triggered, the dependency was used, and the message was logged.
Congratulations, you have successfully triggered your lambda!
You now know how to create a lambda function with an external dependency, initialize LocalStack on your computer, and execute AWS commands from your CLI.
LocalStack can utilize other AWS services such as DynamoDB and API Gateway, and many others. We're AWS Lambda and Node.js experts at Bitovi, so if you have any other posts you'd like to see on these topics, let us know.
Do you have thoughts?
Weโd love to hear them! Join our Community Discord to continue the conversation.