Spring Boot Microservices with Docker Tutorial

In this tutorial, we will create a simple Spring Boot microservices architecture with two services: employee-service and department-service. We will containerize these services using Docker and manage them with Docker Compose.

Prerequisites

Before we start, ensure you have the following:

  • Java Development Kit (JDK) installed
  • Apache Maven installed
  • Docker installed
  • Docker Compose installed
  • An IDE (such as IntelliJ IDEA, Eclipse, or VS Code) installed

Overview of the Microservices

We will create two Spring Boot microservices:

  1. Employee Service: Manages employee information.
  2. Department Service: Manages department information.

Additionally, we will create an API Gateway to route requests to these services.

Step 1: Creating the Microservices

1.1 Create the Employee Service

  1. Open Spring Initializr:

  2. Configure Project Metadata:

    • Project: Maven Project
    • Language: Java
    • Spring Boot: Select the latest version of Spring Boot 3.2
    • Group: com.example
    • Artifact: employee-service
    • Name: employee-service
    • Description: Employee Service
    • Package Name: com.example.employeeservice
    • Packaging: Jar
    • Java Version: 17 (or your preferred version)
    • Click Next.
  3. Select Dependencies:

    • On the Dependencies screen, select the dependencies you need:
      • Spring Web
      • Spring Data JPA
      • H2 Database
    • Click Next.
  4. Generate the Project:

    • Click Generate to download the project zip file.
    • Extract the zip file to your desired location.
  5. Open the Project in Your IDE:

    • Open your IDE and import the project as a Maven project.

1.1.1 Update application.properties

Open the application.properties file located in the src/main/resources directory and add the following configuration:

server.port=8081
spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=password
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
spring.h2.console.enabled=true
spring.jpa.hibernate.ddl-auto=update

1.1.2 Create Employee Entity

Create an Employee entity class in the com.example.employeeservice.model package:

package com.example.employeeservice.model;

import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;

@Entity
public class Employee {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;
    private String department;

    // Getters and Setters
}

1.1.3 Create Employee Repository

Create an EmployeeRepository interface in the com.example.employeeservice.repository package:

package com.example.employeeservice.repository;

import com.example.employeeservice.model.Employee;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface EmployeeRepository extends JpaRepository<Employee, Long> {
}

1.1.4 Create Employee Controller

Create an EmployeeController class in the com.example.employeeservice.controller package:

package com.example.employeeservice.controller;

import com.example.employeeservice.model.Employee;
import com.example.employeeservice.repository.EmployeeRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
@RequestMapping("/employees")
public class EmployeeController {

    private final EmployeeRepository employeeRepository;

    @Autowired
    public EmployeeController(EmployeeRepository employeeRepository) {
        this.employeeRepository = employeeRepository;
    }

    @GetMapping
    public List<Employee> getAllEmployees() {
        return employeeRepository.findAll();
    }

    @PostMapping
    public Employee createEmployee(@RequestBody Employee employee) {
        return employeeRepository.save(employee);
    }
}

1.2 Create the Department Service

  1. Open Spring Initializr:

  2. Configure Project Metadata:

    • Project: Maven Project
    • Language: Java
    • Spring Boot: Select the latest version of Spring Boot 3.2
    • Group: com.example
    • Artifact: department-service
    • Name: department-service
    • Description: Department Service
    • Package Name: com.example.departmentservice
    • Packaging: Jar
    • Java Version: 17 (or your preferred version)
    • Click Next.
  3. Select Dependencies:

    • On the Dependencies screen, select the dependencies you need:
      • Spring Web
      • Spring Data JPA
      • H2 Database
    • Click Next.
  4. Generate the Project:

    • Click Generate to download the project zip file.
    • Extract the zip file to your desired location.
  5. Open the Project in Your IDE:

    • Open your IDE and import the project as a Maven project.

1.2.1 Update application.properties

Open the application.properties file located in the src/main/resources directory and add the following configuration:

server.port=8082
spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=password
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
spring.h2.console.enabled=true
spring.jpa.hibernate.ddl-auto=update

1.2.2 Create Department Entity

Create a Department entity class in the com.example.departmentservice.model package:

package com.example.departmentservice.model;

import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;

@Entity
public class Department {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;

    // Getters and Setters
}

1.2.3 Create Department Repository

Create a DepartmentRepository interface in the com.example.departmentservice.repository package:

package com.example.departmentservice.repository;

import com.example.departmentservice.model.Department;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface DepartmentRepository extends JpaRepository<Department, Long> {
}

1.2.4 Create Department Controller

Create a DepartmentController class in the com.example.departmentservice.controller package:

package com.example.departmentservice.controller;

import com.example.departmentservice.model.Department;
import com.example.departmentservice.repository.DepartmentRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
@RequestMapping("/departments")
public class DepartmentController {

    private final DepartmentRepository departmentRepository;

    @Autowired
    public DepartmentController(DepartmentRepository departmentRepository) {
        this.departmentRepository = departmentRepository;
    }

    @GetMapping
    public List<Department> getAllDepartments() {
        return departmentRepository.findAll();
    }

    @PostMapping
    public Department createDepartment(@RequestBody Department department) {
        return departmentRepository.save(department);
    }
}

1.3 Create the API Gateway

  1. Open Spring Initializr:

  2. Configure Project Metadata:

    • Project: Maven Project
    • Language: Java
    • Spring Boot: Select the latest version of Spring Boot 3.2
    • Group: com.example
    • Artifact: api-gateway
    • Name: api-gateway
    • Description: API Gateway
    • Package Name: com.example.apigateway
    • Packaging: Jar
    • Java Version: 17 (or your preferred version)
    • Click Next.
  3. Select Dependencies:

    • On the Dependencies screen, select the dependencies you need:
      • Spring Cloud Gateway
      • Spring Boot DevTools
    • Click Next.
  4. Generate the Project:

    • Click Generate to download the project zip file.
    • Extract the zip file to your desired location.
  5. Open the Project in Your IDE:

    • Open your IDE and import the project as a Maven project.

1.3.1 Update application.yml

Create an application.yml file in the src/main/resources directory and configure it as follows:

server:
  port: 8080

spring:
  application:
    name: api-gateway

  cloud:
    gateway:
      routes:
        - id: employee_service
          uri: http://localhost:8081
          predicates:
            - Path=/employees/**
        - id: department_service
          uri: http://localhost:8082
          predicates:
            - Path=/departments/**

Step 2: Containerizing the Microservices with

Docker

2.1 Create Dockerfiles

Create a Dockerfile in the root directory of each microservice (employee-service, department-service, and api-gateway).

2.1.1 Employee Service Dockerfile

# Start with a base image containing Java runtime
FROM openjdk:17-jdk-alpine

# Add a volume pointing to /tmp
VOLUME /tmp

# Make port 8081 available to the world outside this container
EXPOSE 8081

# The application's jar file
ARG JAR_FILE=target/employee-service-0.0.1-SNAPSHOT.jar

# Add the application's jar to the container
ADD ${JAR_FILE} app.jar

# Run the jar file
ENTRYPOINT ["java","-jar","/app.jar"]

2.1.2 Department Service Dockerfile

# Start with a base image containing Java runtime
FROM openjdk:17-jdk-alpine

# Add a volume pointing to /tmp
VOLUME /tmp

# Make port 8082 available to the world outside this container
EXPOSE 8082

# The application's jar file
ARG JAR_FILE=target/department-service-0.0.1-SNAPSHOT.jar

# Add the application's jar to the container
ADD ${JAR_FILE} app.jar

# Run the jar file
ENTRYPOINT ["java","-jar","/app.jar"]

2.1.3 API Gateway Dockerfile

# Start with a base image containing Java runtime
FROM openjdk:17-jdk-alpine

# Add a volume pointing to /tmp
VOLUME /tmp

# Make port 8080 available to the world outside this container
EXPOSE 8080

# The application's jar file
ARG JAR_FILE=target/api-gateway-0.0.1-SNAPSHOT.jar

# Add the application's jar to the container
ADD ${JAR_FILE} app.jar

# Run the jar file
ENTRYPOINT ["java","-jar","/app.jar"]

2.2 Build Docker Images

Open a terminal and navigate to each project's root directory, then build the Docker images using the following commands:

2.2.1 Employee Service

mvn clean package
docker build -t employee-service .

2.2.2 Department Service

mvn clean package
docker build -t department-service .

2.2.3 API Gateway

mvn clean package
docker build -t api-gateway .

Step 3: Managing Containers with Docker Compose

3.1 Create docker-compose.yml

In the root directory of your project (outside all microservice directories), create a docker-compose.yml file:

version: '3.8'

services:
  employee-service:
    image: employee-service
    container_name: employee-service
    ports:
      - "8081:8081"

  department-service:
    image: department-service
    container_name: department-service
    ports:
      - "8082:8082"

  api-gateway:
    image: api-gateway
    container_name: api-gateway
    ports:
      - "8080:8080"
    depends_on:
      - employee-service
      - department-service

3.2 Run Docker Compose

In the terminal, navigate to the directory containing the docker-compose.yml file and run the following command to start all services:

docker-compose up

Step 4: Testing the Application

Once all services are up and running, you can test the application using a tool like Postman or your web browser.

4.1 Access the Employee Service

Open your browser or Postman and navigate to http://localhost:8080/employees. You should see the list of employees.

4.2 Access the Department Service

Open your browser or Postman and navigate to http://localhost:8080/departments. You should see the list of departments.

Conclusion

In this tutorial, we created a simple microservices architecture using Spring Boot. We containerized the microservices with Docker and managed them using Docker Compose. This setup provides a solid foundation for developing more complex microservices architectures and deploying them using Docker.

Comments