This is a template for building and deploying a haskell.nix project to AWS Lambda.
It shows the minimalist example for creating a Lambda function, which responds to HTTP queries at Function URL (which AWS provides for each Lambda function if configured).
Nix installed (multi-user installation) with flakes enabled.
The template uses nix flake based on the IOHK haskell.nix infrastructure. And also it heavily relies on aws-lambda-haskell-runtime project.
Run $ nix develop in order to get all required dependencies and tools for development into your bash shell.
Warning! First invocation of nix develop (or nix build) will build lots of dependencies from sources which may take a few hours depending on the number of CPU cores. In fact, there are instructions to avoid builds from source, but I couldn't achieve this despite caches being set up and reachable...
When inside the $ nix develop you can use typical cabal commands like cabal repl and cabal build in order to develop and build the project manually. This is most suitable for development (but not for deployment).
$ nix develop already provides AWS CLI (specified in flake.nix). But, as time goes on, Amazon might break backwards compatibility with the version pinned here, so it might require you to install AWS CLI system wide, or using something like nix-shell -p awscli2 or upgrading nixpkgs (in flake.lock) altogether for the project, etc.
-
create new AWS Access key
Log into your AWS account in web browser. Click on your account name in the top right corner and then click on
Security credentials-- browser should navigate to IAM page. FindAccess keysparagraph and click onCreate access keybutton. Then copyAccess key IDandSecret access keyin some secure place -- they will be needed another step. -
create AWS Lambda role
On the same IAM page navigate to
Rolessection (from the menu on the left). Click onCreate rolebutton. ChooseTrusted entity typeto beAWS serviceandUse caseto beLambda. Click on theNextbutton. SelectAWSLambdaBasicExecutionRoleand click on theNextbutton. Enterlambda-rolein theRole namefield. Click on theCreate rolebutton. More instructions are in AWS Developer Guide. Now on theRolespage click onlambda-roleand you will text underARN, which will be needed later when managing functions with AWS CLI. It seems to be possible to configure roles using AWS CLI, but I haven't tested this. -
configure AWS CLI
Run
$ aws configure- it will ask you to enterAccess key IDandSecret access key. Also it asks for region and AWS CLI output format (I recommendtable). As a result it creates configuration files in$HOME/.aws/.
$ nix build .#aws-lambda.x86_64-linux
As a result, symlink ./result will be created to a folder with zip archive, containing custom bootstrap runtime with all required libraries.
-
create Lambda function
$ aws lambda create-function --function-name test-hs-runtime-standalone --zip-file fileb://result/*.zip --handler standaloneHandler --runtime provided --role arn:aws:iam::123456789012:role/lambda-role(replacearn:aws:iam::123456789012:role/lambda-rolewith your ARN obtained earlier)Note that handler must match the one, specified in haskell code as the first argument to
addStandaloneLambdaHandler. -
create Function URL
$ aws lambda create-function-url-config --function-name test-hs-runtime-standalone --auth-type NONESave the returned URL for further
curlrequests. -
add permission to invoke Lambda function by HTTP request at specific URL
$ aws lambda add-permission --function-name test-hs-runtime-standalone --statement-id allow-invokeFunctionUrl-publicly --action lambda:InvokeFunctionUrl --principal "*" --function-url-auth-type NONENote that everybody will be able to access this URL, invoking your function, because none Auth type is specified here.
$ nix build .#aws-lambda.x86_64-linux && aws lambda update-function-code --function-name test-hs-runtime-standalone --zip-file fileb://result/*.zip
Just use your Function URL obtained earlier. Example:
$ curl -i https://1234567890abcdefghijklmnopqrstuv.lambda-url.eu-north-1.on.aws/?param=go
The Lambda function should respond with date it was loaded on AWS and the value of param HTTP query parameter. The date should stay the same among multiple invocations, clearly demonstrating that AWS does not load/unload the binary on each invocation, but keeps it running and waiting for the next one.
If param HTTP query parameter is missing, the function should crash with an error message in stdout, captured by AWS and displayed in AWS CloudWatch for the chosen Lambda function.