Spring Boot Microservices , Docker and Kubernetes workshop – part1

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.

First we need to define a problem statement to begin with. Let’s say we want to build an order management system.

Identifying domains

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

  1. Orders
  2. Products
  3. Customers or Users
  4. Shopping Cart

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

In this workshop, we would be using the following

  1. Spring boot for micro services
  2. Postgres for Database
  3. Gradle for build
  4. Docker for containers

First Microservice : Products
Let’s 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 generate a gradle project with Java and SpringBoot 2.1.0
And provide the following values :

group id : com.anirudhbhatnagar
artifact : productService
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 :

spring.datasource.url=jdbc:postgresql://localhost:5432/products_db
spring.datasource.username=dbuser
spring.datasource.password=password
spring.jpa.hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect

Now, that we have configured the database for our application, let’s 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, let’s add some code.

NOTE : if you are getting this error while running the application:

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)

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 received in controller to repository to fetch and persist.

@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

See the entire code here.

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

FROM openjdk:8-jdk-alpine
VOLUME /tmp
COPY build/libs/*.jar app.jar
ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar"]
EXPOSE 8080

Build :

docker build .

Run :

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

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 :

  1. Spring cloud, Ribbon for Service Discovery and client side load balancing
  2. OpenFeign Client
  3. Kubernetes for container management
  4. API gateways
Advertisement

2 thoughts on “Spring Boot Microservices , Docker and Kubernetes workshop – part1

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.