AdBlock Detected

It looks like you're using an ad-blocker!

Our team work realy hard to produce quality content on this website and we noticed you have ad-blocking enabled. Advertisements and advertising enable us to continue working and provide high-quality content.

When we decided to build a microservices architecture, we chose to use Spring Cloud and Kubernetes as the platform to deploy them. These are good solutions. In this article, “Microservices with Spring Cloud Kubernetes“, we will explore the fairly recent project by Pivotal, Spring Cloud Kubernetes. If you need an introduction to Kubernetes, you might find these articles helpful. Although we will be using other components such as MongoDB, circuit breaker, and communication via WebClient, this article will focus on deployment and configuration in Kubernetes, with mention of the other created functionalities.

What do we need to get started?

  • A Kubernetes installation. In our case, we are using Minikube, configured and running.
  • Two Spring Boot applications that can communicate via REST.

However, you can find everything you need on our GitHub.

What are we going to build and use?

The example we have created involves the communication between two microservices: a shop that places orders. It’s a very simple example, but it covers the necessary concepts to take advantage of Kubernetes. We will use a Service Discovery and Load Balancer provided by Kubernetes, and we will also use Hystrix as a circuit breaker with fallback capability in case there is an error when making a call to another microservice using WebClient.

In our example, we will use the following:

  • Secrets: Kubernetes secrets allow us to store sensitive information such as passwords, OAuth tokens, SSH keys, etc. In our case, we will store the password and username for the MongoDB database.
  • ConfigMaps: This object is used to store non-sensitive data in a key-value format. In our case, it will store a text to display the services.
  • Load Balancer: In this case, we will use Ribbon to balance the load between two instances.
  • Service Discovery: The Kubernetes dependency of Spring Cloud helps us discover deployed instances or services.

Kubernetes and Spring Cloud Example

Maven Dependencies

Here are the necessary dependencies for Kubernetes in the applications:

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

In addition, some more dependencies from the Netflix stack, as well as the MongoDB and Spring Cloud versions (Hoxton.SR8), have been added.

Service Discovery and Load Balancer Configuration

To make use of service discovery and the load balancer with Ribbon, we need to enable them in the main class of the application:

@RibbonClient(name = "order-service", configuration = RibbonConfiguration.class)
@EnableDiscoveryClient

With the above annotations in the Spring project’s main class, we have enabled the load balancer with Ribbon to balance the requests between instances.

ConfigMap and Secrets Configuration

In Spring Cloud, we can use the Config Server to store non-sensitive information and Vault to store secrets or sensitive information like passwords. However, with Spring Cloud Kubernetes, we can utilize Kubernetes’ Secrets and ConfigMaps objects for this type of information.

ConfigMap

To make use of Kubernetes’ ConfigMap, we first need to deploy a YAML file like this:

apiVersion: v1
kind: ConfigMap
metadata:
  name: shop-service
data:
  application.properties: |-
    configmap.message=Services : %s

Then, to read the information from this file (from the data section), we need to map it to the application:

@Configuration
@ConfigurationProperties(prefix = "configmap")
public class ShopConfig {

  private String message = "Services : %s";

In this way, we will be able to display the text from the configmap in the message field. It is important to note that the name of the configmap must match the name of the service for it to be accessible.

kubectl apply -f configmap.yaml

Secrets

As we have mentioned, secrets in Kubernetes are a type of object where we store sensitive information, similar to how we would use Vault with Spring.

To create objects for sensitive information such as the username and password for MongoDB, we can create a Secrets object as follows:

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

Once we have deployed this object, we can use this information wherever it is needed.

kubectl apply -f secret.yaml

Using Kubernetes Secrets

Once we have deployed the secrets, let’s see how to use them with a MongoDB image in Kubernetes:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: mongo
spec:
  replicas: 1
  selector:
    matchLabels:
      service: mongo
  template:
    metadata:
      labels:
        service: mongo
      name: mongodb-service
    spec:
      containers:
        - args:
            - mongod
          image: mongo:latest
          name: mongo
          env:
            - name: MONGO_INITDB_ROOT_USERNAME
              valueFrom:
                secretKeyRef:
                  name: db-secret
                  key: username
            - name: MONGO_INITDB_ROOT_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: db-secret
                  key: password
kubectl create -f mongo-deployment.yaml

In the above object, we are using the username and password created in the secret. It is important to note that the secret’s name should match the name of the deployed secret, which in our case is “db-secret.”

Configuring the Service to Use Secrets

Once we have deployed both the secrets object and the deployment that uses the secrets (in our case, MongoDB), we need to configure the application to apply the secrets:

spring:
  application:
    name: order-service
  cloud:
    kubernetes:
      reload:
        enabled: true
    secrets:
      name: db-secret
  data:
    mongodb:
      host: mongodb-service
      port: 27017
      database: admin
      username: ${MONGO_USERNAME}
      password: ${MONGO_PASSWORD}

In this configuration, we specify where the secrets are located, and we do not write the actual username and password.

Configuring Role-Based Access

As a final configuration step, without which our applications would not function properly, we need to set up role-based access within the cluster. This ensures that a Pod running with spring-cloud-kubernetes has access to the Kubernetes API and can, for example, retrieve all services.

kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  namespace: default
  name: namespace-reader
rules:
  - apiGroups: ["", "extensions", "apps"]
    resources: ["configmaps", "pods", "services", "endpoints", "secrets"]
    verbs: ["get", "list", "watch"]

---

kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: namespace-reader-binding
  namespace: default
subjects:
  - kind: ServiceAccount
    name: default
    apiGroup: ""
roleRef:
  kind: Role
  name: namespace-reader
  apiGroup: ""

Deploying Spring Cloud Application on Kubernetes

Once we have created all our Kubernetes objects such as services, secrets, configmaps, and deployments, it’s time to create the deployments for the applications we have developed in Spring.

First, we’ll have the service to expose an application running in a set of Pods.

apiVersion: v1
kind: Service
metadata:
  name: order-service
spec:
  selector:
    app: order-service
  ports:
    - protocol: TCP
      port: 8080
      nodePort: 30081
  type: NodePort
  externalIPs:
    - 1.2.4.120

Next, we’ll have the deployment for the application itself. However, before that, we need to create the Docker image for the application. This deployment will reference the service, and the following deployment definition will include the MongoDB username and password as variables, which we have specified in the application.yaml file of the application:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: order-service
spec:
  selector:
    matchLabels:
      app: order-service
  replicas: 2
  template:
    metadata:
      labels:
        app: order-service
    spec:
      containers:
        - name: order-service
          image: order-service:latest
          imagePullPolicy: Never
          ports:
            - containerPort: 8080
          env:
            - name: MONGO_USERNAME
              valueFrom:
                secretKeyRef:
                  name: db-secret
                  key: username
            - name: MONGO_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: db-secret
                  key: password

This deployment references the “order-service” image, which should have been created beforehand using a Dockerfile within the application.

kubectl create -f deployment.yaml

Verifying the Proper Functioning of All Pods

We can verify that our pods are running by executing the following command:

kubectl get pods

or alternatively,

kubectl get po

If the status is not “Running,” we can execute

kubectl logs -f &lt;pod-name&gt;

to view the application logs.

If everything is correct, we can open a terminal and run

minikube service shop-service

to launch the browser and see what it displays.

Conclusion

In this Microservices with Spring Cloud Kubernetes tutorial, we have seen how to quickly and effectively set up an architecture using the key features provided by Kubernetes. You can find the entire project on our GitHub.

If you need more information, you can leave us a comment or send an email to refactorizando.web@gmail.com You can also contact us through our social media channels on Facebook or twitter and we will be happy to assist you!!

Leave a Reply

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