The duo you want for your microservices

Many java developers use the Spring framework to create web-services in the blink of an eye. But maintaining it running in production can be quite a challenge, so many ways to run it, so many cloud providers. Sure you can use services like aws elastic beanstalk to keep it running with autoscaling, zero downtime deployments, little infrastructure experience required to deploy a new version, etc. However these services can cost a lot to those with a low budget while also losing a lot of control over the service infrastructure.

That was our problem at GoBots, we had a low budget and I wanted to have all the benefits from an elastic beanstalk at a low cost. That's when I discovered Kubernetes. It does all that I wanted and its open source! Perfect right? Well first things first.

1 — Generating the Docker Image

I will not enter in details on how Kubernetes work on this article, you can access their documentation to learn more. But let me summarise how it works. You create a Docker image from your application and "tell" Kubernetes to launch one or more instances of the image you created. So our first step was to create a image from our Spring Boot service.

Spring got this covered on this tutorial, this step was very straight forward and very easy to perform. Below is an example of the Dockerfile we are using nowadays.

Our current Dockerfile

With that and the docker build plugin we can run gradle clean buildDocker (or use the maven docker plugin) and build our docker image. Note that it will create a image with a version tag for the version you got configured on gradle.properties or build.gradle . We are currently using the gradle release plugin to create the image on the release task.

2 — Creating the Deployment and our Pods

All right! We created or image, now to put it on Kubernetes we need to upload it on a registry. We could upload to the public docker registry (easier method), however that image would be accessible to everyone! As our service is private, we need to upload to a private registry. Luckily for us Gcloud has a private registry for your account. How to upload a image there is covered in this tutorial.

With that out of the way we can finally put or service on the Kubernetes cluster! As we are using Gcloud it's very easy to create a cluster with GKE, follow this tutorial to do that (or this to setup the cluster on AWS, Azure, Bluemix, etc). After the cluster is created and we configure our command line to connect to it, we need to create a deployment (or a replication controller) for our application to be scalable. We used the following configuration as our inicial configuration.

Considering we configured the Kubernetes command line interface (kubectl) on the last step, we can use kubectl apply -f Deployment.yml for the Kubernetes cluster to create a new deployment with this configuration. After a while you can check the status of the deployment with kubectl get deployment spring-boot-deployment and the pods with kubectl get pods spring-boot-app , if you want to check the logs of a pod you can use the kubectl log command.

3 — Exposing our Pods with Services

Now with our pods running we need to create a service to expose our pods to the world. The following configuration was used to create our service.

As you can see the service configuration is very simple. However this configuration is not exposed to the world. We could set the service type to LoadBalancer as gcloud would automatically create a real load balancer and an external ip for our service. We actually tried to do this, but with this configuration we could not set TLS and HTTPS properly. We wanted our service to only be accessed by HTTPS protocol. But how can we do that?

4 — Routing with Ingress

So I dug deeper and found the Kubernetes Ingress. It is a newer feature but it works very well. It works almost as a service with type LoadBalancer, but you can set custom routing rules. Bellow is our configuration for the Ingress.

As you can see we set the ingress to allow only HTTPS connections with kubernetes.io/ingress.allow-http: "false" . But if you are paying attention you can see that there is a TLS configuration on this file. We need to create first a Secret which holds our ssl certificates data for the ingress to access. Use the following config to do just that.

5 — Secrets

After applying all configs we can check the external ip of our app with the kubectl get ingress spring-boot-ingress command. Access it via HTTPS and voulá, our Spring Boot app is running on a Kubernetes cluster!

IMPORTANT! Kubernetes services perform health checks on the default pod port and endpoint "/". If you don't have that endpoint mapped or if it's secured, you need to include livenessProbe and readinessProbe configuration. Here is how to do that.

I would recommend testing these settings with minikube before deploying to production so you can get familiar with the Kubernetes environment. There are very good tutorials on the documentation page.

To deploy a new version use kubectl set image deployment/spring-boot-deployment spring-boot-app=your-new-image or simply edit the configuration with kubectl edit deployment spring-boot-deployment . With the second command you can update the image and the number of pods at the same time. If you want just to scale the app run kubectl scale deployment spring-boot-deployment --replicas=10 or create an autoscaling configuration.

Updating the deployment cause Kubernetes to rollout an update with zero downtime as it takes care of everything and you can just sit back relax. After changing out infrastructure to GKE we could worry less about the health of the app and more on it's development. Kubernetes is really easy to use with CI tools such as Jenkins, GitLab CI, BitBucket Pipelines, etc. We are currently integrating with GitLab CI which has great support for Kubernetes and will provide us more agility to deploy our applications.

Hope my research on migrating a Spring Boot service to a Kubernetes cluster help you (and myself) out in the future :).