AWS: Part I— Deploy Kotlin Spring Boot Reactive App on Elastic Beanstalk
Let’s build a sample application to learn about different AWS services.
The Practice Problem
For this, we will build a quiz application which will show list of quizzes on home page and on selection of a quiz will present the quiz questions with options to the user where they would be able to select an answer which will be validated on click of a submit button.
In the end we will show all the questions with their right answers and whether user did answer them correctly or not.
The tech stack
- Backend — Kotlin, Spring Boot Reactive
- Frontend — VueJS
- Database — AWS RDS
The beginning
To begin with, we will start with a simple REST API in Spring Boot Reactive to return list of Quizzes. For now we will not fetch data from the database, but will use in memory hard-coded data.
In subsequent articles, we will extend our solution to slowly build and integrate UI and database.
quiz-service
Let’s bootstraps the spring boot app from: https://start.spring.io/
We will use gradle as the build tool, Kotlin as the programming language, and the latest stable version of spring boot.
Select jar as packaging and the JDK version. I am using JDK 8.
Add Spring Reactive Web and Spring Boot Actuator dependency.
Open the project in Intellij / any other IDE and build it.
GET /quizzes
Let’s begin with a test for QuizService.
QuizServiceTest.java
package com.sujit.quiz.serviceimport com.sujit.quiz.domain.Quiz
import org.junit.jupiter.api.Test
import reactor.test.StepVerifierclass QuizServiceTest { @Test
fun `it Should return all quizzes`() {
val quizService = QuizService()
val quizzes = quizService.getAllQuizzes()
val expected = listOf(
Quiz("Kotlin Quiz", "Quiz about Kotlin"),
Quiz("Scala Quiz", "Quiz about Scala")
) StepVerifier.create(quizzes).expectNextSequence(expected)
}
}
QuizService.java
package com.sujit.quiz.serviceimport com.sujit.quiz.domain.Quiz
import org.springframework.stereotype.Service
import reactor.core.publisher.Flux@Service
class QuizService {
fun getAllQuizzes(): Flux<Quiz> {
return Flux.fromIterable(listOf(
Quiz("Kotlin Quiz", "Quiz about Kotlin"),
Quiz("Scala Quiz", "Quiz about Scala")
))
}
}
QuizControllerTest.java
package com.sujit.quiz.controllerimport com.sujit.quiz.domain.Quiz
import com.sujit.quiz.service.QuizService
import io.mockk.every
import io.mockk.mockk
import org.junit.jupiter.api.Test
import reactor.core.publisher.Flux
import reactor.test.StepVerifierclass QuizControllerTest { @Test
fun `it Should return all quizzes`() {
val quizService = mockk<QuizService>()
val quizController = QuizController(quizService) val expected = listOf(
Quiz("Kotlin Quiz", "Quiz about Kotlin"),
Quiz("Scala Quiz", "Quiz about Scala")
) every { quizService.getAllQuizzes() } returns Flux.fromIterable(expected) val quizzes = quizController.getAllQuizzes() StepVerifier.create(quizzes).expectNextSequence(expected)
}
}
QuizController.java
package com.sujit.quiz.controllerimport com.sujit.quiz.domain.Quiz
import com.sujit.quiz.service.QuizService
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.RestController
import reactor.core.publisher.Flux@RestController
class
QuizController(private val quizService: QuizService) { @GetMapping("/quizzes")
fun getAllQuizzes(): Flux<Quiz> {
return quizService.getAllQuizzes()
}
}
Run QuizApplication and hit http://localhost:8080/quizzes in browser. It should return the hard coded list of quizzes.
Deploy to Elastic Beanstalk
Our first REST API is ready. Let’s manually deploy our application on the AWS Elastic Beanstalk.
1. Build the runnable jar
Run ./gradlew bootJar in project home directory. The runnable Jar would be generated at path build/libs/quiz-0.0.1-SNAPSHOT.jar in the project directory. We will use this file to manually crate an Elastic Beanstalk application.
2. Create a new Elastic Beanstalk application
2.1 Create Elastic Beanstalk application
Go to AWS management console and select Elastic Beanstalk. Click on Create application.
- Enter Application Name
- Enter appropriate tags
- Select Java as platform
- Select Java 8 running 64bit Amazon Linux as platform branch.
- Select the recommended version of the platform.
- In source code origin, upload the runnable jar file we generated earlier.
Note: We need to do additional configurations to be able to successfully deploy and access the quiz service. If you create application at this stage without configuring some of the settings we are going to see next, the application might not be accessible and you might see a standard nginx error page: 502 Bad Gateway
This happens because the application load balancer by default points to the Port 80 of the nginx server in EC2 instance. The nginx is configured to forward requests to Port 5000 by default, whereas out application server runs on Port 8080.
This can be achieved by configuring an Environment Property named PORT pointing to 8080, while creating the beanstalk application.
Refer: https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/java-se-nginx.html
2.2 Configure More Options
- Edit software configuration
Edit software configuration and add an Environment Property named PORT and point it to the port on which the application server is running (8080).
Click on Save and Create Application.
It will take some time to elastic beanstalk to create the environment.
After some time the environment will be created successfully
2.3 Hit the environment URL
Check the health of the service by hitting /actuator/health on the environment url
e.g. http://quizservice-env-1.eba-5b72tmpp.ap-south-1.elasticbeanstalk.com/ is the quiz-service of our environment
2.4. Test the /quizzes endpoint
Next Steps…
In this article we created a micro service using Spring Boot Reactive Web and Kotlin and successfully deployed it on Elastic Beanstalk environment on AWS.
In the next article (https://medium.com/beingprofessional/aws-part-ii-deploy-kotlin-spring-boot-reactive-app-on-elastic-beanstalk-using-codepipeline-dec01267db6a) we will create a CodePipeline to automate the build and deployment of the quiz-service on the elastic beanstalk.