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:

  1. Create and package sample Lambda code
  2. Deploy to AWS with API Gateway
  3. Connect to MultiTool and run a canary deployment

Tools

Prerequisites

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

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:

  1. Create a workspace
  2. Create an application with the following values:
NameValue
Application Namequickstart-app
Regionus-east-2
REST API gateway namemultitool-quickstart-apig
Gateway stageprod
Resource methodGET
Resource path/demo
Lambda namemultitool-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}