Skip to content

vertx-howtos/aws-native-image-lambda-howto

Repository files navigation

Deploying a Vert.x Native function with AWS Lambda

This how-to shows you how to deploy a Vert.x-based native image function served by AWS Lambda.

What you will build

  • You will write a function that accepts returns a Quote Of The Day (similar to the UNIX tool).

  • This function will be written in Java.

  • The code will be compiled to native with the help of GraalVM.

  • A function will be created with AWS Command Line Interface.

  • This function will be deployed with AWS Lambda.

What you need

  • A text editor or IDE

  • GraalVM (>= 1.0.0-rc13)

  • Maven

  • AWS CLI tools

  • A AWS account to deploy your function.

What is a AWS Lambda function and why is Vert.x a good match?

AWS Lambda is a service which takes care of computing your code without any knowledge on the server environment. It is said to be serverless compute. The code is executed based on the response of events in AWS services like adding /removing files in S3 bucket, updating Amazon DynamoDB tables, HTTP request from Amazon Api gateway etc.

AWS Lambda code can be written in Java using the Amazon SDK. However due to the nature of the JVM and typical Java frameworks startup time can become a huge bottleneck to the performance of the function. To workaround this usually Java functions would be run on a Java server container, waiting for requests (defeating the whole serverless aspect).

Enter Vert.x and GraalVM. Vert.x is ideal for writing functions on GraalVM native-images, because:

  1. Vert.x applications start very fast since there is no magic happening at run time,

  2. GraalVM is used compilation to further reduce the startup and memory footprint,

  3. Vert.x applications are resource-efficient and remain responsive even under heavy load,

  4. Vert.x offers a large ecosystem of reactive clients to other middlewares (databases, messaging, etc),

  5. a single functional interface implementation suffices to bootstrap a Vert.x application!

Create a project

Start by cloning the following github project: https://github.com/pmlopes/aws-lambda-native-vertx

After that let’s walk over the important parts of the project. Here is the content of the pom.xml file that you should be using:

link:aws-lambda-vertx-runtime/pom.xml[role=include]
  1. We need svm-driver to handle code incompatibilities with substrateVM.

  2. We need vertx-webclient to interact with the lambda environment.

  3. GraalVM configuration to produce an image.

Writing the function

The function receives the incoming HTTP headers and the HTTP body. A random QOTD is selected. For each request, the random quote is sent:

link:aws-lambda-vertx-runtime/src/main/java/lambda/QOTDLambda.java[role=include]
  1. We declare a array of quotes.

  2. Implement the Lambda interface which returns a Future to allow asynchronous processing.

  3. The implementation receives the current Vertx instance and the request headers and body.

  4. For each request we return a resolved future with a random quote.

Testing the function

link:aws-lambda-vertx-runtime/src/test/java/lambda/QOTDLambdaTest.java[role=include]
  1. Call the function with empty headers and body.

  2. Fail the test if the call fails.

  3. Verify that there’s a quote.

  4. Terminate the test.

We can easily test that the function works:

  1. from your IDE, run the junit test, or

  2. with Maven: mvn test.

Preparing your AWS dev environment

Create a Lambda role

Bofore being able to deploy to AWS you need to have a role capable of accessing the service. In order to do this create a temp json file (/tmp/trust-policy.json) with:

link:trust-policy.json[role=include]

And deploy it with:

$ aws iam create-role \
    --role-name lambda-role \
    --path "/service-role/" \
    --assume-role-policy-document file:///tmp/trust-policy.json

Building your function

Building the function is running the usual maven command:

$ mvn clean package
$ zip -r function.zip bootstrap target/lambda

The final zip is the base layer used by the functions.

Deploying the runtime layer

This layer will be installed on top of the Amazon Linux in the /opt directory.

$ aws lambda publish-layer-version \
    --layer-name vertx-native-example \
    --zip-file fileb://function.zip

This will install the lambda entrypoint /opt/bootstrap and the native image ELF containing all the functions.

Deploying the function

You will need to provide a function zip file, in our case this is not useful as all code lives in the base layer so we can upload "again" the same zip or upload an empty file.

$ aws lambda create-function --function-name vertxNativeTester \
    --zip-file fileb://function.zip --handler lambda.EchoLambda --runtime provided \
    --role arn:aws:iam::<YOUR-ARN>:role/service-role/lambda-role

This could be useful if your function requires file resources. In this case you could package the resources for each function on a separate zip file.

Since the deployment was done with a custom runtime we need to link the 2:

$ aws lambda update-function-configuration --function-name vertxNativeTester \
    --layers arn:aws:lambda:eu-central-1:<YOUR-ARN>:layer:vertx-native-example:1

Testing the function

Congratulations you just published your first native function. In order to quickly test it use the toolkit:

$ aws lambda invoke --function-name vertxNativeTester \
    --payload '{"message":"Hello World"}' \
    --log-type Tail response.txt | grep "LogResult" | awk -F'"' '{print $4}' | base64 --decode

Summary

  • We wrote a native function with Vert.x that returns a QOTD.

  • We built a AWS lambda package.

  • We deployed this function with AWS CLI.