Using with AWS Lambda - v0.14+
Martin can run in AWS Lambda. This is useful if you want to serve tiles from a serverless environment, while accessing “nearby” data from a PostgreSQL database or PMTiles file in S3, without exposing the raw file to the world to prevent download abuse and improve performance.
Lambda has two deployment models: zip file and container-based. When using zip file deployment, there is an online code editor to edit the yaml configuration. When using container-based deployment, we can pass our configuration on the command line or environment variables.
Everything can be performed via AWS CloudShell, or you can install the AWS CLI and the AWS SAM CLI, and configure authentication. The CloudShell also runs in a particular AWS region.
Container deployment
Lambda images must come from a public or private ECR registry. Pull the image from GHCR and push it to ECR.
$ docker pull ghcr.io/maplibre/martin:latest --platform linux/arm64
$ aws ecr create-repository --repository-name martin
[…]
"repositoryUri": "493749042871.dkr.ecr.us-east-2.amazonaws.com/martin",
# Read the repositoryUri which includes your account number
$ docker tag ghcr.io/maplibre/martin:latest 493749042871.dkr.ecr.us-east-2.amazonaws.com/martin:latest
$ aws ecr get-login-password --region us-east-2 | docker login --username AWS --password-stdin 493749042871.dkr.ecr.us-east-2.amazonaws.com
$ docker push 493749042871.dkr.ecr.us-east-2.amazonaws.com/martin:latest
Open Lambda console and create your function:
- Click “Create function”.
- Choose “Container image”.
- Put something in “Function name”.
- Note: This is an internal identifier, not exposed in the function URL.
- Click “Browse images”, and select your repository and the tag.
- If you cannot find it, see if you are in the same region?
- Expand “Container image overrides”, and under CMD put the URL of a
.pmtiles
file. - Set “Architecture” to
arm64
to match the platform that we pulled. Lambda has better ARM CPUs than x86. - Click “Create function”.
- Find the “Configuration” tab, select “Function URL”, “Create function URL”.
- Set “Auth type” to
NONE
- Do not enable
CORS
. Martin already hasCORS
support, so it will create incorrect duplicate headers.
- Do not enable
- Click on the “Function URL”.
- To debug an issue, open the “Monitor” tab, “View CloudWatch logs”, find the most recent Log stream.
Zip deployment
It’s possible to deploy the entire codebase from the AWS console, but we will use Serverless Application Model. Our function will consist of a “Layer”, containing the Martin binary, and our function itself will contain the configuration in yaml format.
The layer
Download the binary and place it in your staging directory. The bin
directory of your Layer will be added to the PATH.
mkdir -p martin_layer/src/bin/
cd martin_layer
curl -OL https://github.com/maplibre/martin/releases/latest/download/martin-aarch64-unknown-linux-musl.tar.gz
tar -C src/bin/ -xzf martin-aarch64-unknown-linux-musl.tar.gz martin
Every zip-based Lambda function runs a file called bootstrap
.
cat <<EOF >src/bootstrap
#!/bin/sh
set -eu
exec martin --config \${_HANDLER}.yaml
EOF
Write the SAM template.
cat <<EOF >template.yaml
AWSTemplateFormatVersion: 2010-09-09
Transform: 'AWS::Serverless-2016-10-31'
Resources:
martin:
Type: 'AWS::Serverless::LayerVersion'
DeletionPolicy: Delete
Properties:
ContentUri: src
CompatibleRuntimes:
- provided.al2023
CompatibleArchitectures:
- arm64
Outputs:
LayerArn:
Value: !Ref MartinLayer
Export:
Name: !Sub "${AWS::StackName}-LayerArn"
EOF
Run sam deploy --guided
.
- Stack Name: Name your CloudFormation stack something like
martin-layer
. - Press enter for everything else
- The settings are saved to
samconfig.toml
, so you can later dosam deploy
to update the version, orsam delete
.
Now if you visit the Lambda console and select “Layers”, you should see your layer.
The function
- Select “Functions”, “Create function”.
- Put something in “Function name”.
- Set “Runtime” to “Amazon Linux 2023”.
- Set “Architecture” to “arm64”.
- Under “Advanced settings”, choose “Enable function URL” with “Auth type” of “NONE”.
- Click “Create function”.
Add your layer:
- Click “add a layer” (green banner at the top, or the very bottom).
- Choose “Custom layers”, and select your layer and its version.
- Click “Add”.
Add your configuration file in the function source code:
-
Code tab, File, New File:
hello.handler.yaml
.pmtiles: sources: demotiles: <url to a pmtiles file>
-
Click Deploy, wait for the success banner, and visit your function URL.
TODO
AWS Lambda support is preliminary; there are features to add to Martin, configuration to tweak, and documentation to improve. Your help is welcome.
- Lambda has a default timeout of 3 seconds, and 128 MB of memory, maybe this is suboptimal.
- Document how to connect to a PostgreSQL database on RDS.
- Set up a CloudFront CDN, this is a whole thing, but explain the motivation and the basics.
- Grant the execution role permission to read objects from an S3 bucket, and teach Martin how to make authenticated requests to S3.
- Teach Martin how to serve all PMTiles files from an S3 bucket rather than having to list them at startup.
- Teach Martin how to set the Cache-Control and Etag headers for better defaults.