Redis: Spotahome's Redis Operator
For Redis deployment management we use Spotahome Redis Operator.
Architecture Decision Record
One thing we didn't anticipate when we started building our platform was that Redis would turn out to be the most annoying piece of software to manage. Redis has two approaches to solve high availability: Sentinel and Cluster. Cluster mode requires a minimum of 6 Redis server instances while the Sentinel approach requires 2 Redis servers and 3 Sentinel servers to handle failover.
For Ruby on Rails applications where Sidekiq is commonly used, Cluster mode isn't supported, so we had to find an operator that supported Sentinel. At the time there was only one open source operator available for this: Spotahome Redis Operator, so that's the one we went with.
Pros
- The only open source operator with Sentinel support (no longer true, see Opstree's Redis Operator)
- Meets our minimum requirements to deploy highly available Redis clusters
Cons
- Has a fundamental architectural issue in that it relies on a single Kubernetes StatefulSet per cluster to manage Replicas (see this GitHub issue)
- Has a really scary bug that can cause Sentinel clusters to accidently join each other and cause Redis instances from different clusters to start following eachother (see this GitHub issue))
- No built in backup / restore system
- Runs 3 sentinels per Redis deployment, could have used 3 sentinels for the entire Kubernetes cluster
- Doesn't come with a proxy solution to easily use a single
REDIS_URL
(that said, once you have true Sentinel support client side you won't want to use theREDIS_URL
approach any more) - Sparsely documented
Alternatives Considered
Redis Enterprise Operator
Requires a paid license. Very enterprisey. Unclear if the custom HA model they offer is suitable to us or not. I tried asking a simple question in their sales chat and they ended up trying to call me every day for about a month (I never picked up).
OpsTree Redis Operator
Only supported Redis Cluster for HA at the time of our evaluation. We would love to revisit this one at some point.
KubeDB
See comments on the PostgreSQL alternatives considered.
Creating a database
In your DevOps repository, run k generate resource <application-name> redis
to generate a new database resource. This will add a RedisFailover
template under applications/<application-name>/templates
and output some Helm configuration for you to manually add into applications/<application-name>/values.yaml
.
You can inspect our default generator template here: https://github.com/reclaim-the-stack/get-started/blob/master/generators/resources/redis.yaml. By modifying this template in your own GitOps repository you can tweak the default configuration for all Redis deployments created with k generate
in your cluster.
Connecting to a database
From inside Kubernetes
Run k redis:url <cluster-name>
to get a URL you can use to connect to a redis cluster inside Kubernetes.
Run k redis:sentinel-url <cluster-name>
to get a sentinel URL you can use in conjunction with Sentinel supported clients. Note: there is no standard format for sentinel URL's so you'll have to parse it and integrate it yourself.
To provide URLs via ENV variables to an application you can add an entry in the following style to the env
array in your application's values.yaml
:
env:
- name: REDIS_URL
value: "redis://<cluster-name>-redis-master.default.svc:6379"
# Note: there is no standard Sentinel URL, you'll have to integrate it in your app yourself
- name: SENTINEL_URL
value: "redis-sentinel://redis-sentinel://rfs-<cluster-name>:26379/mymaster"
From your local machine
Run k redis:cli <cluster-name>
.
Import an external database
In this guide we will use an RDB dump to import an external Redis database into our cluster. There are other ways to do this, such as via real time replication, but that is not always possible and thus out of scope for this documentation.
Step 1. Get an RDB dump
Depending on the service provider you may or may not have privilege to execute an RDB dump. If you do have privileges, you can get a dump with:
redis-cli -u <REDIS_URL> --rdb dump.rdb
If you don't, you may be able to request a backup and download a dump from the service providers UI dashboard (this is the case with Redis Labs).
Step 2. Import the dump
To import the dump we will use the open source tool rmt
(from https://github.com/leonchen83/redis-rdb-cli):
wget https://github.com/leonchen83/redis-rdb-cli/releases/download/v0.9.3/redis-rdb-cli-release.zip
unzip redis-rdb-cli-release.zip
rm redis-rdb-cli-release.zip
cd redis-rdb-cli/bin
kubectl port-forward services/<redis-resource>-master 9999:6379
./rmt -s </path/to/dump.rdb> -m redis://localhost:9999
# clean up the redis-rdb-cli directory as you wish
Security Considerations
Our default redis template does not create passwords for new Redis databases. We omit this because Redis is not exposed to the public internet by default and our general security policy is to blindly trust the private network. We also want our default configuration to be as simple as possible.
That said, if you have stricter security requirements and would like to add a password to your Redis database, you can read about how to do that in the Enabling Redis Auth section of the operator documentation.