Skip to content

What is the correct way to run a custom runtime on AWS Lambda?

0

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!"
asked a year ago940 views
1 Answer
0

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:

  1. 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.

  2. Package your function: Include your Haskell executable and the bootstrap file in a .zip file.

  3. Create a Lambda function: Use the 'provided' or 'provided.al2' runtime when creating your function in AWS Lambda.

  4. Upload your package: Upload the .zip file as your function code.

Your current setup is close, but there are a few issues:

  1. Runtime API: Your Haskell code isn't interacting with the Lambda Runtime API. It needs to handle getting invocations, processing them, and sending responses.

  2. Error handling: The function is exiting without providing a proper response, causing the "Runtime exited without providing a reason" error.

  3. Execution flow: The function seems to run twice, which suggests an issue with how it's handling invocations.

To improve your setup:

  1. 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.

  2. Update your bootstrap script to properly handle the Lambda environment variables and pass them to your Haskell executable.

  3. Ensure your Haskell code doesn't exit after processing a single request, but instead loops to handle multiple invocations.

  4. 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 a year ago

You are not logged in. Log in to post an answer.

A good answer clearly answers the question and provides constructive feedback and encourages professional growth in the question asker.