What is the correct way to run a custom runtime on AWS Lambda?
I am currently trying to execute Haskell code as an AWS Lambda function to test how well it runs. I am not totally familiar with docker and less familiar with AWS. I have been trying to follow a few guides for deploying Haskell as a custom runtime specifically, however I'm not super proficient and they seem to be outdated in places.
My question is, am I approaching this correctly for running Haskell performance experiments on AWS? I have seen a video from AWS on youtube that shows a user executing powershell (.ps1) files by using a runtime layer and changing the handler in the function settings. I want to test how Haskell is performing on AWS when it is as close to a native AWS runtime as I can make it without doing a bunch of hacking. I wont be running a lot of complex code I can happily contain all my logic within a function and upload runtimes built in docker containers if I need to. Are there approaches to this task that I am not exploring?
I have attached my current multistage docker file that I am using to build a hello world Haskell file and then zip it to "function.zip" for uploading to AWS Lambda. I had issues with zipping on windows and uploading so I decided to use the same amazonlinux 2023 runtime as I will be using when creating a function in AWS. I had attempted to setup stack and cabal in the dockerfile but ran into issues and instead opted to just build from the latest Haskell and build the code that I copied into the image.
The lambda function technically fails and appears to run twice but I can see that it is printing my "Hello, Haskell!" message when I run test. Within my docker container I zip my haskell build and bootstrap file for uploading to AWS.
RESULT OF RUNNING TEST IN AWS LAMBDA UI
Test Event Name: helloWorld
Response:
{
"errorType": "Runtime.ExitError",
"errorMessage": "RequestId: ... Error: Runtime exited without providing a reason"
}
Function Logs:
Running bootstrap script...
Found Haskell binary, executing...
Hello, Haskell!
INIT_REPORT Init Duration: 31.97 ms Phase: init Status: error Error Type: Runtime.ExitError
Running bootstrap script...
Found Haskell binary, executing...
Hello, Haskell!
INIT_REPORT Init Duration: 179.92 ms Phase: invoke Status: error Error Type: Runtime.ExitError
START RequestId: ... Version: $LATEST
RequestId: ... Error: Runtime exited without providing a reason Runtime.ExitError
END RequestId: ...
REPORT RequestId: ... Duration: 181.62 ms Billed Duration: 182 ms Memory Size: 128 MB Max Memory Used: 4 MB
DOCKERFILE
FROM haskell:latest as build
RUN mkdir -p /aws_lambda_runtime_wjs
WORKDIR /aws_lambda_runtime_wjs
COPY . .
RUN stack setup && \
stack build --install-ghc --copy-bins
RUN BINARY_PATH=$(stack path --local-install-root)/bin/aws-lambda-runtime && \
echo "Binary located at: $BINARY_PATH" && \
cp $BINARY_PATH /aws_lambda_runtime_wjs/aws-lambda-runtime-wjs
FROM amazonlinux:2023
RUN yum -y update && \
yum -y install zlib gmp ncurses-libs xz zip
RUN mkdir -p /var/task
COPY --from=build /aws_lambda_runtime_wjs/aws-lambda-runtime-wjs /var/task/aws-lambda-runtime-wjs
COPY --from=build /aws_lambda_runtime_wjs/bootstrap /var/task/bootstrap
RUN chmod +x /var/task/bootstrap
RUN chmod +x /var/task/aws-lambda-runtime-wjs
WORKDIR /var/task
RUN zip -r9 function.zip bootstrap aws-lambda-runtime-wjs
ENTRYPOINT ["/var/task/bootstrap"]
BOOTSTRAP
#!/bin/sh
# Debugging information
echo "Running bootstrap script..."
# Ensure the Haskell binary exists before running
if [ -f /var/task/aws-lambda-runtime-wjs ]; then
echo "Found Haskell binary, executing..."
# Execute the Haskell binary
exec /var/task/aws-lambda-runtime-wjs
else
echo "Haskell binary not found!"
exit 1
fi
HASKELL CODE COPIED TO DOCKER CONTAINER
module Main where
-- A simple main function that prints a string
main :: IO ()
main = putStrLn "Hello, Haskell!"
- Topics
- ServerlessCompute
- Tags
- AWS Lambda
- Language
- English
asked 2 years ago1.1K views
- Newest
- Most votes
- Most comments
You're on the right track with your approach to running Haskell on AWS Lambda using a custom runtime, but there are a few adjustments you can make to improve your setup and ensure it works correctly.
To run a custom runtime on AWS Lambda:
-
Create a custom runtime: This involves creating an executable file named 'bootstrap' that can run your Haskell code. Your bootstrap script is a good start, but it needs to handle the Lambda runtime API.
-
Package your function: Include your Haskell executable and the bootstrap file in a .zip file.
-
Create a Lambda function: Use the 'provided' or 'provided.al2' runtime when creating your function in AWS Lambda.
-
Upload your package: Upload the .zip file as your function code.
Your current setup is close, but there are a few issues:
-
Runtime API: Your Haskell code isn't interacting with the Lambda Runtime API. It needs to handle getting invocations, processing them, and sending responses.
-
Error handling: The function is exiting without providing a proper response, causing the "Runtime exited without providing a reason" error.
-
Execution flow: The function seems to run twice, which suggests an issue with how it's handling invocations.
To improve your setup:
-
Modify your Haskell code to interact with the Lambda Runtime API. This involves making HTTP requests to the runtime API endpoints to get invocations and send responses.
-
Update your bootstrap script to properly handle the Lambda environment variables and pass them to your Haskell executable.
-
Ensure your Haskell code doesn't exit after processing a single request, but instead loops to handle multiple invocations.
-
Consider using a Haskell Lambda runtime library if available, as it can simplify the process of interacting with the Lambda environment.
For performance testing, this approach of using a custom runtime is appropriate. It allows you to run Haskell code on AWS Lambda in a way that's as close to a native runtime as possible without extensive modifications.
Remember to set the handler in your Lambda function configuration to match your bootstrap file (typically just "bootstrap" if it's in the root of your deployment package).
Your Dockerfile looks good for building the Haskell executable, but make sure you're including all necessary dependencies in the final image. The bootstrap file should be executable (which you've correctly set with chmod +x).
By making these adjustments, you should be able to successfully run and test your Haskell code on AWS Lambda using a custom runtime.
Sources
Building a custom runtime for AWS Lambda - AWS Lambda
Building Lambda functions with custom runtimes in AWS SAM - AWS Serverless Application Model
Choosing and managing runtimes in Lambda functions - AWS Lambda
Tutorial: Building a custom runtime - AWS Lambda
answered 2 years ago
Relevant content
asked a year ago
