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 keys
paragraph and click onCreate access key
button. Then copyAccess key ID
andSecret access key
in some secure place -- they will be needed another step. -
create AWS Lambda role
On the same IAM page navigate to
Roles
section (from the menu on the left). Click onCreate role
button. ChooseTrusted entity type
to beAWS service
andUse case
to beLambda
. Click on theNext
button. SelectAWSLambdaBasicExecutionRole
and click on theNext
button. Enterlambda-role
in theRole name
field. Click on theCreate role
button. More instructions are in AWS Developer Guide. Now on theRoles
page click onlambda-role
and 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 ID
andSecret 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-role
with 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 NONE
Save the returned URL for further
curl
requests. -
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 NONE
Note 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.