Apart from all the recent discussions about Kubernetes and whether you should Dockerize your database or not, today I would like to show you why those two things might be good solutions when scalability and elasticity is a big requirement in your architecture.

The secret sauce here is simple: deploying both your application and database on Kubernetes and a combination of NoSQL and Spring Data.

Why NoSQL and Spring Data?

With document databases, you can avoid lots of unnecessary joins as the whole structure is stored in a single document. Therefore, it will naturally perform faster than a relational model as your data grows.

If you are using any of the JVM languages, Spring Data might be something quite familiar to you. Thus, you can quickly start with NoSQL even without any previous knowledge.

Why Kubernetes?

Kubernetes allows you to scale up and down your stateless application in a cloud-agnostic environment. In the last few versions, K8s also added the ability to run stateful applications such as databases in it, that is one of the (many) reasons why it is such a hot topic nowadays.

I have shown in my previous blog post how to deploy Couchbase on K8s and how to make it “elastic” by easily scaling up and down. If you haven’t read it yet, please spend a few extra minutes going through the video transcript as it is an important part of what we are going to talk about here.

Creating a User Profile Microservice

In the majority of the systems, the user (and all related entities) is the most frequently accessed data. Consequently, it is one of the first parts of the system that has to go through some sort of optimization as your data grows.

Adding a Cache layer is the first type of optimization we can think of. However, it is not the “final solution” yet. Things might get a little bit more complicated if you have thousands of users, or if you need to store user-related entities also in memory.

Managing massive amounts of user profiles is a well-known good fit for document databases. Just take a look at the Pokémon Go use case, for instance. Therefore, building a highly scalable and elastic User Profile Service seems to be a challenge good enough to demonstrate how to design a highly scalable microservice.

image: deniswsrosa/kubernetes-starter-kit -> The docker image we have created before.

containers: name: -> Here is where we define the name of the container running our application. You will use this name in Kubernetes whenever you want to define how many instances should be running, autoscaling strategies, load balancing, etc.

env: -> Here is where we define the environment variables of our app. Note that we are also referring to the secret we created before.

Run the following command to deploy our app:

kubectl create -f spring-boot-app.yaml

In a few seconds, you will notice that both instances of your application are already running:

Finally, let’s expose our microservice to the outside world. There are dozens of different possibilities of how it can be done. In our case, let’s simply create a Load Balancer:

The load balancer will take a few minutes to be up and redirecting traffic to our pods. You can run the following command to check its status:

kubectl describe service spring-boot-load-balancer

As you can see in the image above, our Load Balancer is accessible at ad84a916d65ad11e884a20266aaa53c9-1223617270.us-west-2.elb.amazonaws.com, and the targetPort 8080 will redirect traffic to two endpoints: 10.2.1.6:8080 and 10.2.2.7:8080

Finally, we can access our application and start sending requests to it:

Inserting a new user:

Searching for users:

What About Being Elastic?

This is where things get really interesting. What if we need to scale up the whole of our microservice? Let’s say the Black Friday is coming and we need to prepare our infrastructure to support this massive flow of users coming to our website. Well, that is an easy problem to solve:

To scale up our application, we just need to change the number of replicas in the spring-boot-app.yaml file.

Auto-Scaling Microservices on Kubernetes

I will make a deep dive into this topic in part 2 of this article. In the meantime, you can check this video about pod autoscaling.

Troubleshooting Your Kubernetes Deployment

If your Pods fail to start, there are many ways to troubleshoot the problem. In the case below, both applications failed to start:

Since they are part of the deployment, let’s describe the deployment to try understanding what is happening:

kubectl describe deployment spring-boot-deployment

Well, nothing is really relevant in this case. Let’s look at one of the pod’s logs then:

kubectl log spring-boot-deployment-74649f869d-74sq8

Gotcha! The application did not start because we forgot to create the user on Couchbase. By just creating the user, the pods will be up in a few seconds:

Conclusion

Databases are stateful applications, and scaling them is not as fast as scaling stateless ones (and probably it will never be), but if you need to make a truly elastic architecture, you should plan to scale all components of your infrastructure. Otherwise, you are just creating bottleneck somewhere else.

In this article, I tried to show just a small introduction about how you can make both your application and database on Kubernetes elastic. However, it is not a production-ready architecture yet. There are a plenty of other things to consider still, and I will address some of them in the upcoming articles.