Spring Cloud Kubernetes Guide

1. Overview of Spring Cloud Kubernetes

In this guide, we will walk you through the process of consuming Kubernetes native services using the Spring Cloud common interface. Spring Cloud Kubernetes facilitates the integration of Spring Cloud and Spring Boot applications running on Kubernetes.

1.1. Why use Spring Cloud Kubernetes?

If we have already decided to use Kubernetes as our preferred container manager for our microservices but we are still interested in some features offered by Spring Cloud then Spring Cloud Kubernetes might be a good solution.

In fact, this project provides easier integration of these two popular container managers and deployment platforms.

2. Get Started

In this guide, we will build a demo together to demonstrate how to handle:

  • Service Discovery
  • Configuration Management using ConfigMaps
  • Load Balancing with Ribbon

Specifically, in this demo we’ll first install Minikube to create a local Kubernetes environment.

Then we will develop a simple microservice scenario where we’ll have two individual Spring Boot applications communicating via REST.

  1. recipe-data-service: A service with access to a repository of recipes and related nutritional information.
  2. fitness-client-service: A service that needs updated information from the Recipe Data Service to provide fitness-related information.

Finally, we’ll be deploying the application a one-node cluster on Minikube.

3. Service Discovery with DiscoveryClient Implementation for Kubernetes

Each service will be exposed by Kubernetes into a collection of endpoints called pods. Internally, these pods can be accessed with a unique address that is invisible externally. In fact, the client will access the service as http://recipe-data-service:8080.

Furthermore, Spring Cloud Kubernetes Ribbon can be used to load balance between the different pods.

In order to use this feature we just need to add this in the Spring Boot application that needs to consume this service. In our case, we’ll add this to our fitness-client-service:

<dependency>
     <groupId>org.springframework.cloud</groupId> 
     <artifactId>spring-cloud-starter-kubernetes</artifactId> 
</dependency>

Additionally, the @EnableDisoveryClient annotation should be added on the application class

@SpringBootApplication
@EnableDiscoveryClient
public class Application {
  public static void main(String... args) {
    SpringApplication.run(Application.class, args);
  }
}

Then, you get hold of the DiscoveryClient in your desired class by adding @Autowired to the property as follows:

@Autowired
private DiscoveryClient discoveryClient;

4. Kubernetes Native Service Discovery

Kubernetes offers its own native discovery service on the server-side ensuring compatibility with other tools such as Istio. Istio is a service mainly used for load balancing, ribbon, circuit breaking, and failover capabilities.

Additionally, Netflix Hystrix framework library can also be used for circuit breaking and failover functionality. Similar to Istio it also helps to build more resilient applications using fail-fast techniques.

Let’s use Hystrix in our recipe-data-service to specify exactly how to deal quickly with a fallback. Through the @HystrixCommand annotation we can easily specify the fallback method to be used to recover quickly.

@HystrixCommand(fallbackMethod = "getFallbackName", commandProperties = { 
    @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "1250") })
public String getRecipes() {
    return this.restTemplate.getForObject("http://recipe-data-servie:8080/recipes", String.class);
}
 
private String getFallbackName() {
    return "Fallback";
}

5. Kubernetes PropertySource Implementations

Let’s discuss ways of how to manage configurations using Spring Cloud Kubernetes project.

The two distinct ways are ConfigMap and Secret, where the former is advisable for unencrypted information while Secret as the name implies is meant for more sensitive encrypted information.

5.1. ConfigMap

ConfigMap is a resource provided by Kubernetes for configuration management typically required by microservices. By using an application.yaml (or application.properties) we can externalize the parameters to pass to our application.

Let’s say we need a configurable property for our fitness-client-service, what we do is create a configuration class using Spring annotations @Configuration and @ConfigurationProperties.

@Configuration
@ConfigurationProperties(prefix = "bean")
public class FitnessClientConfig {
 
    private String message = "Message from fitness-client-service: %s <br/> Services : %s";
 
    // getters and setters
}

For example, we can create a ConfigMap for our fitness-client-service using this fitness-client-config.yaml file

apiVersion: v1
kind: ConfigMap
metadata:
  name: fitness-client-service
data:
  application.properties: |-
    bean.message=Message from fitness-client-service: %s <br/> Services : %s

To create the ConfigMap on Kubernetes we need to execute the following command:

kubectl create -f fitness-client-config.yaml

If you need to edit the ConfigMap, this can be done through the kubectl edit command as follows:

kubectl edit configmap fitness-client-service

The configuration in ConfigMap instances is updated through Spring Cloud Kubernetes during bootstrapping and reloading of the Spring Context. Noteworthy, the name of the ConfigMap should match exactly that of the application name e.g. fitness-client-service.

5.2. Secrets

As already mentioned, these are more suitable for more sensitive information such as passwords or database information.

For example, let’s create a Secret db-credentials-secret.yaml for our recipe-data-service holding database username and password.

apiVersion: v1
kind: Secret
metadata:
  name: db-credentials-secret
data:
  username: dXNlcg==
  password: cDQ1NXcwcmQ=

To create the Secret on the recipe-data-service Kubernetes’ cluster we need to execute the following command:

kubectl apply -f db-credentials-secret.yaml

6. Ribbon Discovery in Kubernetes

As already hinted, Spring Cloud Kubernetes Ribbon uses a mechanism by which it discovers all the pods/endpoints which expose a specific service. Subsequently, it populates what is called a Ribbon ServerList with endpoint related information and also takes care of load-balancing between the various endpoints.

Adding RibbonClient is very simple. We need to:

  • add the pom dependency in our fitness-client-service,
  • add @RibbonClient annotation from the class where we need to use a reference of the RibbonClient,
  • Enable the ribbon client in the application properties
<dependency>
   <groupId>org.springframework.cloud</groupId>
   <artifactId>spring-cloud-starter-kubernetes-ribbon</artifactId>
</dependency>

In the service layer of fitness-client-service, add the reference for RibbonClient to gather all the info on the recipe-data-service endpoints.

@RibbonClient(name = "recipe-data-service")

Finally, add this in applications.yaml property file, so that you enable the ribbon client.

ribbon.http.client.enabled=true

7. Environment Setup

7.1. Minikube Setup

I suggest starting by installing VirtualBox on your machine or your preferred VM driver. Then, it’s the turn of installing Minikube from the Kubernetes site.

7.1.1. Starting a Single Node Kubernetes Cluster

minikube start --vm-driver=virtualbox

kubectl config use-context minikube

This command will restart the existing virtualbox VM cluster for Minikube or create a new one if it doesn’t exist. Then we switch to the Minikube cluster using the kubectl config use-context command.

7.1.2. Connecting to Kubernetes Dashboard

minikube dashboard

By connecting to the Minikube dashboard, we’ll be able to access log files, services, and pods. Additionally, if configured we can also access ConfigMaps and/or Secrets.

7.2. Deployment

In order to build the services on the remote on Minikube’s cluster docker environment execute the following script:

### build the repository
mvn clean install
 
### set docker env
eval $(minikube docker-env)
 
### build the docker images on minikube
cd recipe-data-service
docker build -t recipe-data-service .
cd ../fitness-client-service
docker build -t fitness-client-service .
cd ..
 
### secret
kubectl delete -f recipe-data-service/secret.yaml 
kubectl create -f recipe-data-service/secret.yaml
 
### recipe-data-service
kubectl delete -f recipe-data-service/recipe-data-deployment.yaml
kubectl create -f recipe-data-service/recipe-data-deployment.yaml
 
### fitness-client-service
kubectl delete configmap fitness-client-service
kubectl delete -f fitness-client-service/fitness-client-deployment.yaml
 
kubectl create -f fitness-client-service/fitness-client-config.yaml
kubectl create -f fitness-client-service/fitness-client-deployment.yaml
 
# Check that the pods are running
kubectl get pods

8. Conclusion

This is a simple guide for Spring Cloud Kubernetes project. By now you will have an idea whether you are interested in trying this out for your microservices architecture. Actually, this is an excellent solution for people who have already chosen to use Kubernetes as their microservices deployment solution but still root for Spring Cloud features.

Let me know if you have any problems or queries at [email protected] or send a message to the Facebook Page

Leave a Reply

Your email address will not be published. Required fields are marked *