Spring Boot Rest API on AWS Lambda

Serverless and Cloud :

If you are reading this article you probably know what serverless compute architecture brings to the table. But if you don’t let me explain it in simple terms.

In cloud computing, We put our computing logic(a.k.a Code) to run on a cloud resource( a computer far up in the cloud owned by someone else we trust- Amazon,google,Microsoft,Hashicorp,Alibaba,etc) just like we do on a traditional server owned by our company somewhere in the basement.

Now just like the server in the basement, cloud resource is expected to be available all the time. that means you are expected to pay for that time. If it breaks, you have to have a plan to replace it.

With the move towards microservice architecture, organisations are inclining towards breaking their applications into smaller independent chunks rather than one monolithic piece of application which breaks even if a simple functionality breaks.

This approach is also inspired by the fact that not every part of your application is demanded equally. So just to have a section of the app available all the time, you don’t want the entire app to be deployed and costing you.

Without going deep into the Pros and Cons of microservice vs traditional architecture, on microservices side, we might have some functionality that does not need to be up and running all the time.

(Example: Get me the list of colors in a rainbow). These applications are typically not very process intensive and takes less time to complete.

Now that we have the premise defined for our story. Lets see how it was done in a traditional cloud application in AWS.

We can put our code to run on a EC2 (traditional computer on cloud) or ECS(traditional distributed set of computers). Both are cool but expensive.You have to pay for the time they are up, even if your code is not executing.

AWS Lambda provide you with a low cost , managed service which charges you for the time you compute. It scales(multiples) according to your demand. Its managed, so you don’t have to worry about fixing it if it breaks.

Now its all sunshine and rainbow till, but what does it take to deploy a standard java application to lambda.

In this article, we will discuss how to build, deploy and monitor a simple spring boot java application on AWS Lambda which will get you the color of rainbows you deserve.

Code Base:

I have the code for this article in here.
The repository has 2 branches: master and lambda
The master provides you with the basic java spring boot code with a single rest end point and a docker file for you to make container on your local system and test it out.
The instructions are in the READ.me file. If things go as planned , you will see all the colors of a rainbow in a JSON format.

[{"state":"Violet"},{"state":"Indigo"},{"state":"Blue"},{"state":"Green"},{"state":"Yellow"},{"state":"Orange"},{"state":"Red"}]

The Lambda branch is what we are interested in. Checkout the lambda branch of the code and will go over some key changes that we made to make it a AWS Lambda.

Dependencies:

Going through the very well documented AWS Serverless Java Container , we go through the Spring boot quick start branch of it. 
The first step is to import the Spring implementation of the library:

<dependency>
<groupId>com.amazonaws.serverless</groupId>
<artifactId>aws-serverless-java-container-spring</artifactId>
<version>1.1</version>
</dependency>

This will automatically also import the aws-serverless-java-container-core and aws-lambda-java-core libraries.

By default, Spring Boot projects include the spring-boot-maven-plugin and an embedded Tomcat application server. To package the Spring Boot application for AWS Lambda, we do not need the Spring Boot maven plugin and we can configure the shade plugin to exclude the embedded Tomcat - the server-less-java-container library takes its place. Copy the Pom Build section of the documentation as is.
See the profiles section of our pom.xml. The default build profile is now to build for Lamda, while a command line option on MVN will build a standard Spring Boot application running Tomcat.

mvn package -Dboot

Section 2: Create the Lambda handler explains well how we can create a LambdaHandler class to compliment the traditional Application entry point of Spring boot. Its created in the same package and is the same as documented just with an additional profile handler
handler.activateSpringProfiles("lambda");

Create a standard Spring Boot configuration class Config. We are disabling beans used for HTTP handling and optimizing for Lambda execution. @EnableWebMvc is required for Lambda deployment. The @Profile annotation makes these beans only load when the Lambda profile is enabled. Thus, the code can still run as a Spring Boot application outside of Lambda.

Deployment with AWS SAM:

AWS SAM(Serverless Applications Model) simplifies cloudformation template(infrastructure-as-code) for the servlerless deployments. We have create a sam.yaml in the project same as pom.xml and dockerfile.
For deployments we use AWS CLI from our local bash. If you have not used them before install and configure them before you go any further. The IAM role that you assign to your CLI must be capable of creating S3, Cloudformation stack, API Gateway , AWS Lambda. For convinience, I just assigned it the admin role.

  • Clean and Build a shaded jar
    mvn clean package
  • Create an S3 bucket to put the serverless deploy code. S3 are unique, so choose your own bucket name.
aws s3 mb s3://spring-lambda-java-aws
  • Copy the code into the s3 bucket
aws cloudformation package --template-file sam.yaml --output-template-file target/output-sam.yaml --s3-bucket spring-lambda-java-aws
  • Deploy the code in the bucket into a Cloudformation, which deploys the Lambda, makes a API Gateway endpoint and cloudwatch log for you.
    Pretty cool eh ! ?
aws cloudformation deploy --template-file target/output-sam.yaml --stack-name spring-lambda-java-aws --capabilities CAPABILITY_IAM

Note: We are applying the IAM capabilities through the command. Make sure your IAM role has the capabilities else you will get an error such as

An error occurred (AccessDenied) when calling the CreateChangeSet operation: User: arn:aws:iam::XXXXXXXXXX:user/AwsCli 
is not authorized to perform: cloudformation:CreateChangeSet on resource: arn:aws:cloudformation:us-east-2:XXXXXXXXXXXXXX:stack/spring-lambda-java-aws/*
  • visit the Cloudformation stack in your AWS account and find the link too the API in the output tab , or describe the stack through your CLI to get he output API link
aws cloudformation describe-stacks --stack-name spring-lambda-java-aws

the output has something such as :

spring-lambda-java-aws-LambdaSpringBootFunction-XXX010X0X01

You can watch the logs in the cloudwatch, the link to which will be in the resource section of the Cloudformation stack. Or you can go to the Lambda section of AWS console, open the particular lambda and there will be a monitoring tab. This tab explains a graphical representation of your Lambda execution and there is also a very raw log file attached to it, whichever you prefer.

  • What if you want to update the jar. Well, you can update the jar file through the update stack command:
aws lambda update-function-code --function-name spring-lambda-java-aws-LambdaSpringBootFunction-CP110TA711CZ --zip-file fileb://target/lambdaSpringBootJavaApp.jar

But this just updates the JAR file that the lambda functions holds. It wont rebuild the stack from scratch. Like i just updated the Colors in my rainbow.
So if there is some breaking change that we have to make, we have to go through the entire deployment process again.

Something really interesting with Serverless codes are the Cold starts and the number of concurrent executions. Cold start basically means that the first lambda takes time to run, but all the subsequent calls are much quicker to be executed. Concurrent execution restricts the number of Lambda running in parallel. These are out of scope for this article, so I will save them for the next one.