A Comprehensive Guide To Deploying A Website In Kubernetes

With a primer on Blue Green vs Rolling update strategy

Recently, we at Grofers took a decision to migrate all our services to Kubernetes.

Now during the process of migrating our frontend website to Kubernetes, we realised that the default Rolling Update deployment strategy doesn’t work that well and we had to shift to Blue Green strategy instead (we’ll go over the details later).

This blog stands as a guide for those who are looking to do the same, as it might save their time and efforts given the lack of resources out there on this topic currently.

We cover some basics first, then a step-by-step guide on its implementation, and later look at how we can validate the different strategies ourselves by running load tests.

What is Kubernetes?

Kubernetes is an open-source container-orchestration system for automating application deployment, scaling, and management.

I won’t cover all the basics on Kubernetes (there are a lot more other good resources on it). Here I want to cover two very common deployment strategies.

First is the Blue Green strategy. This is the recommended strategy to be used for deploying a Single Page website application (considering the website uses versioned assets).

The other deployment strategy, which is perhaps the most common deployment strategy in Kubernetes and which is being used by all the backend services at Grofers, is the Rolling Update (or Ramped/ Slow Rollout) strategy.

Blue Green vs Rolling Update

Rolling Update

Rolling Update makes the deployment by incrementally replacing older pods with new ones.

As we see in the diagram above, the Load Balancer service is the yellow diamond in middle that distributes the traffic to the pods (single instances of your application).

So at any given time, your app may contain both the new and old version of the pods.

Blue Green

The Blue Green strategy creates a completely new deployment in parallel with the older. The Load Balancer service is then configured to switch traffic to the newer deployment and stop serving to the older one. The older deployment is then deleted.

What deployment strategy do we use at Grofers?

Since our backend services are all stateless, rolling update strategy makes more sense there which provides faster rollouts and ability to do phased rollouts.

But for our website, we figured out that rolling update strategy won’t be a zero-downtime strategy for making a new deployment. There are a couple of reasons for it:

If both blue and green pods are present at the same time (the case for rolling update strategy), that might create an issue for serving our versioned assets. The assets corresponding to the index.html served by newer deployment might not be present in the container running in older deployment. This is well explained in the diagram below. We also have a small Node.js API server running alongside our frontend server. So it’s basically a small monolith running for our website. Now suppose we add a new API endpoint in the node server. For rolling update deployments, a frontend code served by newer deployment will then be hitting on a route that will not be existing in the backend served by older deployment.

Point #1, explained

It became quite clear to us that we needed to run a deployment containing only one version of the pods and not have both versions running simultaneously (in the case of rolling update).

Blue Green deployment strategy was the way to go for us for deploying our website. Next, we will dive into some code and look at how we can implement it in our tooling.

Step-by-step Guide

The idea is to deploy a new deployment with the latest green version (we use git commit hash for versioning).

Then when it is up and running we update the service to point to this new deployment and delete the previous deployment.

Deployment snippet

Service snippet

Makefile snippet

We use make for building and deploying in our CI/CD pipelines. The steps remain the same no matter what tooling you use.

First, we get the blue version (previously used git commit hash) by querying the already running service for the deployment’s version it is using.

$(eval BlueVersion=$(shell kubectl get service ${KUBE_APP_NAME} -o=jsonpath='{.spec.selector.version}' -n ${ENV_KUBE_NAMESPACE}))

2. Green version is nothing but the latest git commit hash.

$(eval GreenVersion=${LATEST_GIT_COMMIT_ID})

3. Next, we get the current deployment, apply changes to it by replacing the blue version with the green version.

kubectl get deployment ${KUBE_APP_NAME}-${BlueVersion} -o=yaml -n ${ENV_KUBE_NAMESPACE} | sed -e "s/${BlueVersion}/${GreenVersion}/g" | kubectl apply -f - -n ${ENV_KUBE_NAMESPACE}

4. Then we wait for the green deployment to complete before proceeding.

kubectl rollout status deployment/${KUBE_APP_NAME}-${GreenVersion} -n ${ENV_KUBE_NAMESPACE}

5. Next, we get the current service and configure it to use green version instead of the blue version.

kubectl get service ${KUBE_APP_NAME} -o=yaml -n ${ENV_KUBE_NAMESPACE} | sed -e "s/${BlueVersion}/${GreenVersion}/g" | kubectl apply -f - -n ${ENV_KUBE_NAMESPACE}

6. Lastly, we delete the older blue deployment.

kubectl delete deployment ${KUBE_APP_NAME}-${BlueVersion} -n ${ENV_KUBE_NAMESPACE}

And that’s it.

What’s next?

This is how we achieve a zero-downtime deployment for our website using the Blue Green deployment strategy.

In the next blog post, we’ll dive into ways in which we can load test our website and validate the different strategies ourselves.

We’ll be using tools like JMeter along with Selenium WebDriver plugin to open multiple browser clients in parallel (it supports only Firefox as of now), load test while rolling out a new deployment. We’ll also perform a simple action like clicking a dialog and see how many failures we get during deployment for both Rolling Update and Blue Green.

Stay tuned 👋

Ashish is the Lead Web Developer at Grofers. He works out of our HQs in Gurgaon, India.