Quarkus - Amazon Lambda with Resteasy, Undertow, or Vert.x Web
The quarkus-amazon-lambda-http
extension allows you to write microservices with Resteasy (JAX-RS),Undertow (servlet), or Vert.x Web and make these microservices deployable as an Amazon Lambdausing Amazon’s API Gateway and Amazon’s SAM framework.
You can deploy your Lambda as a pure Java jar, or you can compile your project to a native image (GraalVM) and deploy that for a smallermemory footprint and startup time.
Prerequisites
To complete this guide, you need:
less than 30 minutes
JDK 1.8 (AWS requires JDK 1.8)
Apache Maven 3.5.3+
Getting Started
This guide walks you through generating an example Java project via a maven archetype. Later on it walks through the structureof the project so you can adapt any existing projects you have to use Amazon Lambda.
Installing AWS bits
Installing all the AWS bits is probably the most difficult thing about this guide. Make sure that you follow all the stepsfor installing AWS SAM CLI.
Creating the Maven Deployment Project
Create the Quarkus AWS Lambda maven project using our Maven Archetype.
mvn archetype:generate \
-DarchetypeGroupId=io.quarkus \
-DarchetypeArtifactId=quarkus-amazon-lambda-http-archetype \
-DarchetypeVersion=1.0.0.CR1
Build and Deploy
Build the project using maven.
mvn clean install
This will compile the code and run the unit tests included within the generated project.Unit testing is all regular local Java and does not require running on Amazon. Quarkus dev-mode is alsousable.
If you want to build for native too, make sure you have GraalVM installed correctly and just add a native
propertyto the build
mvn clean install -Dnative
Simulate Amazon Lambda Deployment
The AWS SAM CLI allows you to run your lambda’s locally on your laptop in a simulated Lambda environment. This requires docker to be installed (see their install docs).After you have built your maven project, execute this command
sam local start-api --template sam.jvm.yaml
This will start a docker container that mimic’s Amazon’s Lamba’s deployment environment. Once the environmentis started, you can invoke the example lambda in your browser by going to
In the console you’ll see startup messages of the example lambda. This particular deployment starts a JVM and loads yourlambda as pure Java.
If you want to deploy a native GraalVM executable of your lambda, use a different yaml template that is provided in yourgenerated project:
sam local start-api --template sam.native.yaml
Deploy to AWS
There are a few steps to get your lambda running on AWS.
Package your deployment.
sam package --template-file sam.jvm.yaml --output-template-file packaged.yaml --s3-bucket <YOUR_S3_BUCKET>
Type the simple name of your S3 bucket you created during. If you’ve built a native executable, replacesam.jvm.yaml
with sam.native.yaml
.
Deploy your package
sam deploy --template-file packaged.yaml --capabilities CAPABILITY_IAM --stack-name <YOUR_STACK_NAME>
The stack name can be anything you want.
Debugging AWS Deployment Problems
If sam deploy
, run the describe-stack-events
commandto get information about your deployment and what happened.
aws cloudformation describe-stack-events --stack-name <YOUR_STACK_NAME>
One common issue that you may run across is that your S3 bucket has to be in the same region as Amazon Lambda.Look for this error from describe-stack-events
output:
Error occurred while GetObject. S3 Error Code: AuthorizationHeaderMalformed. S3 Error Message:
The authorization header is malformed; the region 'us-east-1' is wrong; expecting 'us-east-2'
(Service: AWSLambdaInternal; Status Code: 400; Error Code: InvalidParameterValueException;
Request ID: aefcf978-ad2a-4b53-9ffe-cea3fcd0f868)
The above error is stating that my S3 bucket should be in us-east-2
, not us-east-1
.To fix this error you’ll need to create an S3 bucket in that region and redo steps 1 and 2 from above.
Another annoying this is that if there is an error in deployment, you also have to completely deleteit before trying to deploy again:
aws cloudformation delete-stack --stack-name <YOUR_STACK_NAME>
Execute your REST Lambda on AWS
To get the root URL for your service, type the following command and see the following output:
aws cloudformation describe-stacks --stack-name <YOUR_STACK_NAME>
It should give you something like the following output:
{
"Stacks": [
{
"StackId": "arn:aws:cloudformation:us-east-1:502833056128:stack/QuarkusNativeRestExample2/b35b0200-f685-11e9-aaa0-0e8cd4caae34",
"DriftInformation": {
"StackDriftStatus": "NOT_CHECKED"
},
"Description": "AWS Serverless Quarkus HTTP - io.demo::rest-example",
"Tags": [],
"Outputs": [
{
"Description": "URL for application",
"ExportName": "RestExampleNativeApi",
"OutputKey": "RestExampleNativeApi",
"OutputValue": "https://234234234.execute-api.us-east-1.amazonaws.com/Prod/"
}
],
The OutputValue
attribute is the root URL for your lambda. Copy it to your browser and add hello
at the end.
Examine the POM
If you want to adapt an existing Resteasy, Undertow, or Vert.x Web project to Amazon Lambda, there’s a coupleof things you need to do. Take a look at the generate example project to get an example of what you need to adapt.
Include the
quarkus-amazon-lambda-http
extension as a pom dependencyConfigure Quarkus build an
uber-jar
If you are doing a native GraalVM build, Amazon requires you to rename your executable to
bootstrap
and zip it up. Notice that thepom.xml
uses themaven-assemby-plugin
to perform this requirement.
Examine sam.yaml
The sam.yaml
syntax is beyond the scope of this document. There’s a couple of things to note though that are particularto the quarkus-amazon-lambda-http
extension.
Amazon’s API Gateway assumes that HTTP response bodies are text unless you explicitly tell it which media types arebinary through configuration. To make things easier, the Quarkus extension forces a binary (base 64) encoding of allHTTP response messages and the sam.yaml
file must configure the API Gateway to assume all media types are binary:
Globals:
Api:
EndpointConfiguration: REGIONAL
BinaryMediaTypes:
- "*/*"
Another thing to note is that for pure Java lambda deployments, do not change the Lambda handler name.
Properties:
Handler: io.quarkus.amazon.lambda.runtime.QuarkusStreamHandler::handleRequest
Runtime: java8
This particular handler handles all the intricacies of integrating with the Quarkus runtime. So you must use thathandler.
Finally, there’s an environment variable that must be set for native GraalVM deployments. If you look at sam.native.yaml
you’ll see this:
Environment:
Variables:
DISABLE_SIGNAL_HANDLERS: true
This environment variable resolves some incompatibilites between GraalVM and the Amazon Lambda Custom Runtime environment.