Deploy Redis Cluster on Kubernetes
Learn to deploy a Redis cluster on Kubernetes with this hands-on tutorial. Covers core concepts, step-by-step deployment, troubleshooting, and next steps in the Redis learning path.
Focus: deploy redis cluster on kubernetes
Deploying a Redis cluster on Kubernetes can feel like orchestrating a symphony of stateful nodes—getting it wrong means data loss, split brains, or endless crash loops. This lesson cuts through the YAML noise to give you a battle-tested approach for running a production-grade Redis cluster inside Kubernetes, so you stop fighting infrastructure and start scaling.
The problem this lesson solves
Running a single Redis pod is easy. Running a Redis cluster—six or more nodes with automatic sharding, replication, and failover—inside Kubernetes is a different beast. The default redis-cluster setup expects static IPs and direct node-to-node communication. Kubernetes gives you ephemeral pods with dynamic IPs. Without careful orchestration, your cluster will never form, or worse, it will form and then silently lose data.
Pain point: You need a Redis cluster for high availability and horizontal scaling, but you keep seeing
CLUSTERDOWN The cluster is downerrors in your logs.
Core concept / mental model
Think of a Redis cluster as a team of librarians. Each librarian (node) manages a subset of the books (hash slots). Kubernetes is the library building that can reassign rooms (pods) whenever it wants. To make this work, you need three things:
- Stable networking – Each pod must know the exact IP of every other pod before the cluster forms.
- Headless service – A Kubernetes Service that gives each pod a predictable DNS name like
redis-cluster-0.redis-cluster.default.svc.cluster.local. - StatefulSet – A controller that assigns stable identities and persistent storage to each pod.
Definitions
| Term | Meaning |
|---|---|
| StatefulSet | Kubernetes controller for stateful apps with stable network IDs. |
| Headless Service | A Service with clusterIP: None that exposes pod DNS names without load balancing. |
| Redis cluster bus | The internal channel Redis nodes use for gossip and failover. |
| Hash slot | A unit of data ownership—Redis cluster has 16,384 slots. |
How it works step by step
- Provision a StatefulSet with 6 replicas (3 masters, 3 replicas) using a headless Service.
- Mount a PersistentVolumeClaim for each pod to store
appendonly.aofanddump.rdb. - Configure each pod via a ConfigMap. Enable cluster mode:
cluster-enabled yesandcluster-require-full-coverage nofor resiliency. - Wait for all pods to become Ready (their IPs are resolvable via DNS).
- Run
redis-cli --cluster createfrom inside one pod, pointing to all six pod DNS names. - Verify the cluster with
redis-cli cluster infoand try aSET/GET.
Pro tip: Always use
cluster-require-full-coverage noin production. If one master goes down, the entire cluster won't stop serving reads.
Hands-on walkthrough
Prerequisites
- A Kubernetes cluster (minikube or cloud) with
kubectlconfigured. helminstalled (optional, but makes life easier).
Step 1: Create a namespace
kubectl create namespace redis
Step 2: Create the ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
name: redis-cluster-config
namespace: redis
data:
redis.conf: |
cluster-enabled yes
cluster-require-full-coverage no
cluster-node-timeout 5000
appendonly yes
protected-mode no
bind 0.0.0.0
port 6379
Save as redis-config.yaml and apply:
kubectl apply -f redis-config.yaml
Step 3: Deploy the headless Service and StatefulSet
---
apiVersion: v1
kind: Service
metadata:
name: redis-cluster
namespace: redis
labels:
app: redis-cluster
spec:
clusterIP: None
ports:
- port: 6379
targetPort: 6379
name: client
- port: 16379
targetPort: 16379
name: gossip
selector:
app: redis-cluster
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: redis-cluster
namespace: redis
spec:
serviceName: redis-cluster
replicas: 6
selector:
matchLabels:
app: redis-cluster
template:
metadata:
labels:
app: redis-cluster
spec:
containers:
- name: redis
image: redis:7.2
command: ["/bin/sh", "-c"]
args:
- |
IP=$(hostname -i)
sed -i "s/^# bind 0.0.0.0/bind $IP/" /etc/redis/redis.conf
redis-server /etc/redis/redis.conf
ports:
- containerPort: 6379
name: client
- containerPort: 16379
name: gossip
volumeMounts:
- name: config
mountPath: /etc/redis
- name: data
mountPath: /data
volumes:
- name: config
configMap:
name: redis-cluster-config
volumeClaimTemplates:
- metadata:
name: data
spec:
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 1Gi
Save as redis-cluster.yaml and apply:
kubectl apply -f redis-cluster.yaml
Step 4: Wait for all pods to be Ready
kubectl get pods -n redis -w
Wait until all 6 pods show Running.
Step 5: Create the cluster
kubectl exec -it -n redis redis-cluster-0 -- redis-cli --cluster create \
redis-cluster-0.redis-cluster.default.svc.cluster.local:6379 \
redis-cluster-1.redis-cluster.default.svc.cluster.local:6379 \
redis-cluster-2.redis-cluster.default.svc.cluster.local:6379 \
redis-cluster-3.redis-cluster.default.svc.cluster.local:6379 \
redis-cluster-4.redis-cluster.default.svc.cluster.local:6379 \
redis-cluster-5.redis-cluster.default.svc.cluster.local:6379 \
--cluster-replicas 1
You should see output like:
>>> Performing hash slots allocation on 6 nodes...
Master[0] -> Slots 0 - 5460
Master[1] -> Slots 5461 - 10922
Master[2] -> Slots 10923 - 16383
Adding replica redis-cluster-3 to redis-cluster-0
Adding replica redis-cluster-4 to redis-cluster-1
Adding replica redis-cluster-5 to redis-cluster-2
>>> OK
Step 6: Test the cluster
# Write a key
kubectl exec -n redis redis-cluster-0 -- redis-cli -c set mykey "hello"
# Should return -> OK
# Read from a different pod
kubectl exec -n redis redis-cluster-2 -- redis-cli -c get mykey
# Should return -> "hello"
- Success! Your Redis cluster is now running on Kubernetes.
Compare options / when to choose what
| Approach | Pros | Cons | Best for |
|---|---|---|---|
| Manual via StatefulSet + exec | Full control, no extra tooling | Manual cluster creation, harder to automate | Learning, small dev clusters |
| Helm chart (bitnami/redis-cluster) | One-command install, auto-cluster formation | Opacity, hard to customize | Production, teams familiar with Helm |
| Redis Operator (e.g., OLM) | Self-healing, backups built-in | Operator lifecycle complexity | Large-scale, multi-cluster deployments |
- Use the manual approach for labs and understanding internals.
- Use Helm when you need a stable, configurable cluster fast.
- Use an Operator when you want automated failover recovery without manual
redis-clicommands.
Troubleshooting & edge cases
"Waiting for the cluster to join..." hangs forever
- Cause: Pods cannot resolve each other's DNS.
- Fix: Ensure the Headless Service has
clusterIP: Noneand that your cluster DNS is healthy. Try:bash kubectl exec -n redis redis-cluster-0 -- nslookup redis-cluster-0.redis-cluster
"[ERR] Node is not empty" when creating cluster
- Cause: A pod already has old AOF or RDB files from a previous cluster.
- Fix: Delete the PVC and let it recreate:
bash kubectl delete pvc data-redis-cluster-0 -n redisThen re-runredis-cli --cluster create.
One master goes down and cluster stops serving writes
- Cause:
cluster-require-full-coverage yes(default). - Fix: Set it to
noin the ConfigMap. The cluster will serve writes on remaining masters.
Pod IP changes after restart and cluster breaks
- Cause: The cluster was created using pod IPs instead of DNS names.
- Fix: Always use the full service DNS name (
<pod>.<service>.<namespace>.svc.cluster.local) during--cluster create.
Pro tip: When using StatefulSets, the pod hostname is guaranteed to be
<name>-<ordinal>, but the DNS resolution depends on the headless service.
What you learned & what's next
You now know how to deploy a Redis cluster on Kubernetes from scratch. You understand:
- The core components: StatefulSet, Headless Service, and ConfigMap.
- The difference between static IPs and DNS-based node discovery.
- How to create the cluster with
redis-cli --cluster create. - How to troubleshoot common failures like DNS issues or unclean node state.
This skill is critical because it lets you run Redis at scale without locking yourself to a specific cloud provider. Next up in your Redis learning path, you'll explore scaling the cluster dynamically—adding and removing nodes without downtime—and setting up automated failover with Redis Sentinel on Kubernetes.
Remember: a Redis cluster on Kubernetes is production-ready only when you have persistent storage, proper DNS, and a failover strategy. Now go make your data resilient.
Practice recap
Try scaling your cluster to 9 pods (6 masters, 3 replicas) using the same StatefulSet approach. Then, manually fail over a master by killing one pod with kubectl delete pod redis-cluster-0 -n redis and verify the cluster heals using redis-cli cluster nodes.
Common mistakes
- Forgetting to set the
hostname -ibind address inside the container, causing the cluster to form on 127.0.0.1 and then refuse external connections. - Running
redis-cli --cluster createwith pod IPs instead of the headless service DNS names—when pods restart, the cluster fails to rejoin. - Setting
cluster-require-full-coverage yes(default) and then losing one master—this takes the entire cluster offline for writes. - Not using a PersistentVolumeClaim—when a pod dies, all data is lost, forcing a full cluster rebuild.
Variations
- Use Helm stable/redis-cluster chart for an automated one-command deployment that handles cluster formation.
- Deploy using the Redis Operator (from OLM) which offers automated failover, upgrades, and backup integrations.
- Run the cluster on a DaemonSet with hostNetwork: true for bare-metal-like performance (not recommended for multi-tenant clusters).
Real-world use cases
- E-commerce session store: A Redis cluster shards user sessions across nodes, ensuring no single point of failure during Black Friday traffic spikes.
- Real-time leaderboard: Gaming companies use a 6-node Redis cluster on Kubernetes to keep leaderboards sorted and replicated with minimal read latency.
- Message queue for microservices: Redis streams backed by a cluster allow multiple producers and consumers with automatic failover, even when pods reschedule.
Key takeaways
- Headless Services + StatefulSets give Redis pods stable DNS names required for cluster discovery.
- Always bind to the pod's own IP, not 0.0.0.0, to avoid loopback issues in Redis cluster mode.
- Use
cluster-require-full-coverage noto avoid total outage when a master fails. - The
redis-cli --cluster createcommand must use full DNS names (e.g.,pod.service.namespace.svc.cluster.local) for resilience. - PersistentVolumeClaims are mandatory—without them, a pod restart wipes all cluster data.
Keep learning
Related tutorials, quizzes, and articles for this topic.
Discussion
Questions, corrections, and tips help everyone reading this page.
0 comments
Add a comment
No comments yet — start the thread.