Spring Boot Microservices , Docker and Kubernetes workshop

In this series of workshop we will build few micro services using spring boot, docker and then deploy them into Kubernetes. So, Lets get started.

Spring Boot Microservices , Docker and Kubernetes workshop

First we need to define a problem statement to begin with. Lets say we want to build a order management system.

If you want to Gain In-depth Knowledge on Spring Boot, please go through this link Spring Boot Training

Identifying domains

First step would be to understand what domains are required, for simplicity lets assume we need the following domains:

• Orders
• Products
• Customers or Users
• Shopping Cart

Now that we know what we are building, let’s start developing.

In this workshop, we would be using the following

  • Spring boot for micro services

  • Postgres for Database

  • Gradle for build

  • Docker for containers

First Microservice : Products
Lets build our first micro-service for products, we will call it product service, this will contain the details of the products.

Step 1: Set up spring boot application using spring initialiser.
Go to https://start.spring.io/ and genereate a gradle project with Java and SpringBoot 2.1.0 And provide the following values :

  1. group id : com.anirudhbhatnagar

  2. artifact : productService

  3. dependecies : Web, Jpa, postgresSQL

Click generate project and download the zipped project. Create a new directory called “order_management_system”. Unzip the project in a folder and copy its contents into a this new directory.

Import the project into your favourite IDE and we are good to start. Check if the setup is working fine by running the project in a terminal:

./gradlew build

The build would fail with DataSourceBeanCreationException, this happened because we added PostgresSQL dependency in our project but did not configure the data source by giving the DB credentials and its uri. Lets do that in next step.

Step 2: Configure database
We need a database to persist the product details for the product service.
For this we need 2 things :
– A running postgres database
– Configure its details in spring
Lets first create a local postgres database. We can use a docker image to have a local postgres DB running. In order to have a postgres database server running as docker image, we need to have docker in our system. Use this link to install docker in your mac (Similar links can be found for Windows and Linux).
Once docker is installed in your machine. Pull a latest postgres image and run it in your local. We will also initialise a database with username and password to be used. Run the following command in your terminal :

$ docker run --name oms_postgres -p 5432:5432 -e POSTGRES_USER=dbuser -e POSTGRES_DB=products_db -e POSTGRES_PASSWORD=password -d postgres

This will start a postgres server on port 5432 in your local and initialise an empty DB “postgres_db” with username “dbuser” and password “password”. Once the database is up and running, we will now configure the datasource our spring boot application. One the ways and perhaps the easiest one with spring boot is to define data source URI and database credentials in the application.properties file. Spring boot will auto configure the data source using these credentials.

Open the application.properties file in the project and add below :

  1. spring.datasource.url=jdbc:postgresql://localhost:5432/products_db

  2. spring.datasource.username=dbuser

  3. spring.datasource.password=password

  4. spring.jpa.hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect

Now, that we have configured the database for our application, lets run the gradle build again. Build :

./gradlew build

If everything is fine, then this time the build should pass. Run :

./gradlew bootRun

Now we will have an application running at : http://localhost:8080/ But as we have not implemented any service it will give a 404. In order to get it working, lets add some code.

NOTE : if you are using postgres version you may get this error :

java.sql.SQLFeatureNotSupportedException: Method org.postgresql.jdbc.PgConnection.createClob() is not yet implemented.

This exception appears because JPA (Hibernate) supported by Atomikos is trying to verify PostgreSQL CLOB feature. This feature is not implemented by JDBC driver, so driver throws an unimportant exception. to fix this, add following to your application.properties file :

spring.jpa.properties.hibernate.jdbc.lob.non_contextual_creation=true

This will disable driver’s feature detection (we will not be using this feature anyways) Lets See What Is Spring Boot

Step 3: Add the code in product service
Now that our service and database is setup, we can start writing some code for our product service. Make a package with the name : “domain” inside the package “com.anirudhbhatnagar.productService” and create a new Java class “Product” with attributes:

id

name

description

sku

Lombok
We would use Lombok to add constructors, getter, setter, and builder methods for our bean. To use lombok add its dependency to build.gradle file :

compileOnly 'org.projectlombok:lombok:1.18.4'

The add the annotations on the class “Product”

  • @Entity

  • @Builder

  • @AllArgsConstructor

  • @NoArgsConstructor

  • @Getter

  • public class Product {

  • @Id

  • @GeneratedValue(strategy = GenerationType.AUTO)

  • private Long id;

  • private String name;

  • private String description;

  • private String sku;

  • }

The meaning of annotations:
1. @Entity tell spring boot JPA to treat this class as an entity and persist it the database.
2. @Builder – this lmobok annotation adds builder method to our class for creating objects using builder pattern.
3. @AllArgsConstructor – this lmobok annotation adds an all arguments constructor to the class, Builder method needs this method.
4. @NoArgsConstructor – this lmobok annotation adds a default constructor to the class, JPA needs this constructor to fetch the entities.
5. @Getter – this lombok annotation adds getters to all the fields in the class, this is required to fetch individual attributes of the product, this is also used by Jackson to serialise/deserialise the fields.

And in order to create this table in the database, we need to set jpa hibernate auto-ddl as true. To do that add the following line to application.properties file :

spring.jpa.hibernate.ddl-auto=create

We also added : @GeneratedValue and @Id to the field Id, to tell hibernate to auto generate value for the id when creating a new entry in the table.

Add Controller
Add a controller to implement expose web services and serialise/deserialise the request using Jackson. Make a package with the name : “controller” inside the package “com.anirudhbhatnagar.productService” and create a new Java class “ProductController” inside it.

Annotate the class with “@RestController” to extend this class into a Servlet which exposes the webservices. Create the endpoints with the annotation ” @GetMapping”

@RestController

public class ProductController {

@GetMapping("/products")

public List getProducts() {

return Collections.EMPTY_LIST;

}

@PostMapping("/products")

public Product save(@RequestBody Product product) {

return null;

}

}

Add Repository
Add JPA repository to persist products in the database. Make a package with the name : “repository” inside the package “com.anirudhbhatnagar.productService” and create a new interface “ProductRepository” inside it:

public interface ProductRepository extends JpaRepository {

}

Inject productRepository into ProductController so that we can use productRepository in ProductController to pass product request object re

@RestController

public class ProductController {

private ProductRepository productRepository;

@Autowired

public ProductController(ProductRepository productRepository) {

this.productRepository = productRepository;

}

@GetMapping("/products")

public List getProducts() {

return productRepository.findAll();

}

@PostMapping("/products")

public Product save(@RequestBody Product product) {

return productRepository.save(product);

}

}

Now we have product service up and running with following endpoints :

GET /products – gets all the products
POST /products – creates a new product

Dockerise the app
Create a file named “dockerFile” in the root folder of the application and add the following contents into it :

  1. FROM openjdk:8-jdk-alpine

  2. VOLUME /tmp

  3. COPY build/libs/*.jar app.jar

  4. ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar"]

  5. EXPOSE 8080

Build :

docker build .

Run :

docker run -p 8080:8080 [image-id]

Take your career to new heights of success with an Spring Boot Certification

This should start a service at localhost:8080

Test the application :
Using postman or any other similar tool, submit this request to create a product :

Http POST http://localhost:8080/products. Header : Content-Type application/json

{

"name" : "Nike shoes",

"description" : "mens shoes size 10",

"sku" : "1234asc"

}

And the products can be fetched by : GET http://localhost:8080/products

In the next workshop, we would look into the following :

Spring cloud, Ribbon for Service Discovery and client side load balancing
OpenFeign Client
Kubernetes for container management
API gateways