Tutorial: deploy a Lambda function with MultiTool
This tutorial walks through deploying a simple AWS Lambda function behind an API Gateway. You’ll simulate user traffic to the API, and the MultiTool agent will automatically decide whether to promote or roll back the deployment based on the observed error rate.
You will:
- Create and package sample Lambda code
- Deploy to AWS with API Gateway
- Connect to MultiTool and run a canary deployment
Tools
-
AWS Lambda - to run sample server code
-
AWS API Gateway REST API - to make the Lambda function publicly accessible
-
AWS CloudWatch - to read metrics used by MultiTool during deployment
-
MultiTool - to automate safe deployments
Prerequisites
- A free MultiTool account
-
An AWS account with read and write permissions for Lambda, API Gateway, and CloudWatch
-
AWS CLI installed
-
Create an Access Key
-
Run
aws configure
and follow the prompts to login to AWS
-
-
MultiTool CLI installed
- Run
multi login
to authenticate
- Run
Step 1: Create and package the Lambda code
This tutorial simulates two versions of a Lambda function:
- A “healthy” version that always returns a
200
HTTP status code - A “buggy” version that randomly fails with a
400
HTTP status code 10% of the time
File must be named index.js
to execute correctly.
Create the healthy version
This version always returns a 200
HTTP status code response.
cat << EOF > index.js
exports.handler = function (_, context) {
return context.succeed({
statusCode: 200,
body: JSON.stringify({
message: "Hello World",
}),
});
};
EOF
Zip the code:
zip -j 0%_failures.zip index.js
Create the buggy version
This version introduces a simulated bug by returning a 400
HTTP status code 10% of the time.
cat << EOF > index.js
exports.handler = function (_, context) {
const rand = Math.random();
if (rand < 0.9) {
return context.succeed({
statusCode: 200,
body: JSON.stringify({
message: "Hello World",
}),
});
} else {
return context.succeed({
statusCode: 400,
body: JSON.stringify({
error: "Something went wrong",
}),
});
}
};
EOF
Zip the code:
zip -j 10%_failures.zip index.js
## Step 2: Create a Lambda execution IAM role
AWS needs permission to run the Lambda function.
Create a new IAM role for Lambda execution:
```bash
LAMBDA_EXECUTION_ROLE_ARN=$(aws iam create-role \
--role-name lambda-execution \
--assume-role-policy-document '{"Version": "2012-10-17","Statement": [{ "Effect": "Allow", "Principal": {"Service": "lambda.amazonaws.com"}, "Action": "sts:AssumeRole"}]}' --output text --query Role.Arn)
If you’ve already created this role before, you can retrieve it instead:
LAMBDA_EXECUTION_ROLE_ARN=$(aws iam get-role \
--role-name lambda-execution \
--output text \
--query Role.Arn)
Step 3: Create the Lambda function
Upload the healthy version of the code to create the function in AWS:
LAMBDA_ARN=$(aws lambda create-function \
--function-name multitool-quickstart-lambda \
--runtime nodejs22.x \
--handler index.handler \
--role ${LAMBDA_EXECUTION_ROLE_ARN} \
--zip-file fileb://0%_failures.zip \
--publish \
--output text \
--query FunctionArn)
Step 4: Test that the Lambda is working
Before moving on, make sure the Lambda function returns the expected response.
aws lambda invoke --function-name multitool-quickstart-lambda out.txt >/dev/null && cat out.txt
You should see:
{
"statusCode": 200,
"body": "{\"message\":\"Hello World\"}"
}
Step 5: Set up API Gateway
Expose the Lambda to the public internet by creating an API Gateway REST API:
API_ID=$(aws apigateway create-rest-api --name multitool-quickstart-apig --output text --query id)
Get the auto-generated root resource ID:
ROOT_RESOURCE_ID=$(aws apigateway get-resources --rest-api-id ${API_ID} --output text --query 'items[0].id')
Next, create an API resource and route.
Create the new path:
RESOURCE_ID=$(aws apigateway create-resource --rest-api-id ${API_ID} --parent-id ${ROOT_RESOURCE_ID} --path-part "demo" --output text --query 'id')
Add a GET method:
aws apigateway put-method --rest-api-id ${API_ID} --resource-id ${RESOURCE_ID} --http-method GET --authorization-type "NONE"
Step 6: Connect API Gateway to Lambda
Link the API Gateway to the Lambda so it can forward incoming requests:
aws apigateway put-integration \
--rest-api-id ${API_ID} \
--resource-id ${RESOURCE_ID} \
--http-method GET \
--type AWS_PROXY \
--integration-http-method POST \
--uri arn:aws:apigateway:${AWS_REGION:=us-east-2}:lambda:path/2015-03-31/functions/${LAMBDA_ARN}/invocations
Deploy the API:
aws apigateway create-deployment --rest-api-id $API_ID --stage-name prod
Get the new public URL:
MY_URL="https://${API_ID}.execute-api.${AWS_REGION:=us-east-2}.amazonaws.com/prod/demo"
Save the URL to a file for later:
cat << EOF > url.txt
$MY_URL
EOF
Finally, give API Gateway permission to invoke the Lambda:
aws lambda add-permission \
--function-name multitool-quickstart-lambda \
--statement-id apigateway-permission-${API_ID} \
--action lambda:InvokeFunction \
--principal apigateway.amazonaws.com
Step 7: Connect the app to MultiTool
Now that the Lambda is deployed and accessible via API Gateway, create the app in MultiTool.
From the MultiTool app:
- Create a workspace
- Create an application with the following values:
Name | Value |
---|---|
Application Name | quickstart-app |
Region | us-east-2 |
REST API gateway name | multitool-quickstart-apig |
Gateway stage | prod |
Resource method | GET |
Resource path | /demo |
Lambda name | multitool-quickstart-lambda |
After the application is set up, login to the MultiTool CLI if needed:
multi login
Step 8: Deploy healthy code and simulate stable traffic
To test a successful deployment, use the 0%_failures.zip
file.
Start the deployment using the healhty build artifact and replacing the placeholder with your MultiTool workspace name:
multi run --workspace ${MY_WORKSPACE_NAME} --application quickstart-app 0%_failures.zip
In a separate terminal window, load the public URL from Step 6 to use in the next step:
MY_URL=$(cat url.txt)
Simulate traffic to the /demo
endpoint using one of these options:
Option A: Using curl
for i in $(seq 1 1500);do echo -n "Request $i completed with status: ";code=$(curl -s -o /dev/null -w "%{http_code}" "$MY_URL");echo "$code";sleep 1;done
Option B: Using Bombardier
bombardier -c 5 -n 20 ${MY_URL}
As traffic hits the new version, MultiTool will evaluate its behavior and promote it to 100% traffic once it confirms stability.
Step 9: Deploy buggy code and simulate errors
To test a broken deployment, use the 10%_failures.zip
file.
Start the deployment using the buggy build artifact and replacing the placeholder with your MultiTool workspace name:
multi run --workspace ${MY_WORKSPACE_NAME} --application quickstart-app 10%_failures.zip
In a separate terminal window, load the public URL from Step 6 to use in the next step:
MY_URL=$(cat url.txt)
Simulate traffic to the /demo
endpoint using one of these options:
Option A: Using curl
for i in $(seq 1 1500);do echo -n "Request $i completed with status: ";code=$(curl -s -o /dev/null -w "%{http_code}" "$MY_URL");echo "$code";sleep 1;done
Option B: Using Bombardier
bombardier -c 5 -n 20 ${MY_URL}
MultiTool will detect the increase in errors and automatically trigger a rollback.
Step 10: Cleanup
After you've tested MultiTool, be sure to clean up the demo resources created as part of this guide.
Delete the Lambda function:
aws lambda delete-function --function-name multitool-quickstart-lambda
Delete the API Gateway:
aws apigateway delete-rest-api --rest-api-id ${API_ID}