Running Redis Cluster on Kubernetes

Update (2018–08–22): as some people pointed out in the comments, the cluster breaks when one of the nodes is restarted and gets a new IP address assigned. I updated the post with a script that should fix this.

Update (2018–08–22): @riaan53 pointed out that the cluster commands previously handled by redis-trib will become part of the official redis-cli in Redis 5.0. I updated the example to use the latest 5.0 RC instead of a custom image.

Note: the full example can be found here

After successfully running a single Redis GCE instance to manage our inter-service communication for a couple of years, we finally started to run into scaling issues. To solve these, we started working out a way to reliably run a set of Redis instances as a cluster in our Kubernetes cluster.

As you may or may not know, Redis Cluster is a set of Redis instances working together to make your data storage scale across nodes while also making it a bit more resilient. Data is automatically split across nodes and it supports a master/slave setup for increased availability in case of a failure. For more information, check their excellent tutorial.

Getting Redis Cluster to work in Kubernetes can become a bit cumbersome, though, as each Redis instance relies on a configuration file that keeps track of other cluster instances and their roles. This means that instances have a certain amount of state, which does not fit easily into the stateless paradigm of Kubernetes pods. Luckily, a combination of Kubernetes’ StatefulSets and PersistentVolumes gets us a long way.

Initially, we set up a group of individual Redis servers in cluster mode using a StatefulSet, each configured to receive their own PersistentVolumeClaim. These claims are automatically provisioned through a volumeClaimTemplate , and will be forever linked to that specific instance of the Redis cluster. So, should one or more instances crash, be moved or even removed during scale operations, when they come back they will still be part of the cluster and will update automatically.

StatefulSet configuration. Click here for the full example

Note that we use the built-in redis-cli tool for our health- and readiness probes to make sure our pods are working as intended. Kubernetes also wants us to define a serviceName to bind to, which makes it a lot easier for cluster-friendly Redis clients to connect to our cluster: since they only need a single node for the discovery, they can just use the Kubernetes service name as host!

In order to fix a known bug in Redis, we also include the following entry point script that fixes its own IP address in the local nodes.conf , which is needed for the cluster to remain stable in case a Pod is rescheduled:

Entrypoint script. Click here for the full example

Configuration of the Redis cluster is also done through the redis-cli, which helps you set up the cluster, as well as manage which instances contain which slots. This makes creating a cluster from a group of Redis instances as easy as this oneliner:

kubectl exec -it redis-cluster-0 -- redis-cli --cluster create --cluster-replicas 1 \
$(kubectl get pods -l app=redis-cluster -o jsonpath='{range.items[*]}{.status.podIP}:6379 ')

Since we created the StatefulSet with 6 replicas, this command will create a cluster with 3 master and 3 slave nodes due to the --cluster-replicas 1 flag. After that, the cluster pretty much manages itself. Should one of the master pods fail, its replicated slave node will automatically be appointed as a new master node, making sure no data is lost. When the failing pod comes back, it will automatically replicate the newly appointed master and run in slave mode.

The only thing that has to be done manually is scaling up and down, because new pods will not automatically join the cluster (and even if they did, there is no way (yet) to auto-balance the cluster, so new pods will not receive any shards anyway). These steps are documented in the example.

  • If you would like to try this for yourself, you can check out the full example on GitHub, which you can run using the excellent minikube platform or by starting a Kubernetes cluster in the newer versions of Docker for Mac/Windows.
  • Although this setup works great if you just store values, you will run into scaling issues as soon as you start using Redis PubSub. This is because PubSub channels are not hashed the way normal keys are, but every message is automatically published to every node. There is some discussion going on about this and it might be solved in Redis 4.0, but until then there is no good way of combining PubSub with Redis Cluster if you have a lot of messages going through.



Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Sander Ploegsma

Senior Software Engineer at Topic Embedded Systems, currently positioned at ASML