Dragonfly

Running Redis on Kubernetes: Deployment, Scaling, and Operators

Master Redis on Kubernetes with our ultimate guide: deploy, manage, and scale with ease.

May 22, 2023

cover

Last reviewed: August 2026. Verified against Kubernetes 1.34, Redis 8.10, and Dragonfly Operator v1.3.1.

Running Redis on Kubernetes means running a stateful, single-threaded process inside an orchestrator built for stateless, horizontally scalable ones. It works, and plenty of teams do it at scale, but most of the operational difficulty comes from that mismatch rather than from Redis or Kubernetes individually.

This guide covers the three ways to deploy Redis on Kubernetes, what actually breaks in production, and how to decide between a StatefulSet, an operator, and a single vertically scaled node.

A note before you start: if you landed here from an older version of this page, several things in it were wrong. The autoscaling/v2beta2 HPA manifests stopped applying in Kubernetes 1.26. The Bitnami Helm instructions stopped working in September 2025. And it described Redis Cluster's 16384 hash slots as "shards," which is a different thing entirely. All three are corrected below, and we've explained why rather than quietly patching them.


Should you run Redis on Kubernetes at all?

Yes, if Redis is a cache and you already run everything else on Kubernetes. The operational overhead is small and the consistency of one deployment model is worth a lot.

Be more careful if Redis is a system of record, if you're running Redis Cluster, or if the workload is large enough that node sizing starts to matter. Kubernetes gives you scheduling, self-healing, and declarative config. It does not give you resharding, failover semantics, or an answer to what happens when your 64 GB Redis pod gets evicted and has to reload an RDB file from a network-attached volume.

The teams that have the worst time are usually the ones who deployed Redis to Kubernetes as though it were a stateless service, then discovered eighteen months later that a rolling node upgrade drops the cache and takes the application down with it.

When Kubernetes is a good fit for Redis:

  • Cache workloads where a cold start is survivable
  • Session storage with an acceptable rebuild path
  • Environments where you already have PVCs, storage classes, and a working backup story
  • Dev and staging, where the reproducibility is worth more than the performance

When it needs more thought:

  • Redis Cluster, where Kubernetes pod IPs and Redis's cluster bus assumptions fight each other
  • Multi-terabyte datasets, where the pod-to-node ratio stops being flexible
  • Anything where a failover that loses in-flight writes is a customer-visible incident

Three ways to deploy Redis on Kubernetes

Approach

What you write

Failover

Best for

Raw StatefulSet

Every manifest yourself

Manual, or none

Learning, single-instance caches, tightly controlled environments

Helm chart

A values.yaml

Depends on the chart

Teams already standardized on Helm, dev and staging

Operator

A custom resource

Automatic, controller-driven

Production HA, teams that want a control loop rather than a template

The short version: a StatefulSet gets you a Redis pod with stable identity and storage. Helm gets you a StatefulSet without writing the YAML. An operator gets you something that watches the cluster and does something when the primary dies.

Templates render once. Controllers keep running. That's the whole argument for operators, and it's why anything with a real availability requirement ends up on one.


The Bitnami problem, and why older Redis on Kubernetes guides no longer work

If you follow a Redis on Kubernetes tutorial written before late 2025, there's a good chance the Helm section fails with ImagePullBackOff. Here's what happened.

On 28 August 2025, Broadcom restructured the Bitnami public catalog. Versioned container images moved from docker.io/bitnami/ to docker.io/bitnamilegacy/, which receives no updates or security patches. The public docker.io/bitnami/ namespace now carries only a small hardened subset under latest tags. The old catalog was deleted on 29 September 2025.

The packaged Helm charts still exist at oci://registry-1.docker.io/bitnamicharts, but they're frozen and their default image references point at locations that no longer serve those tags.

This bites in a specific and nasty way. Existing pods keep running, because the image is already on the node. Everything looks fine. Then you drain a node, scale up, or trigger a rollout, Kubernetes tries to pull the image, and it fails. Teams have found this during an incident rather than before one.

If you're on a Bitnami Redis chart today, you have three options, in rough order of how much we'd recommend them:

  1. Move to an operator or a chart with a maintained image supply chain.
  2. Build the images yourself. The source is still Apache 2.0 at github.com/bitnami/containers.
  3. Pin to bitnamilegacy as a stopgap and accept that you're running unpatched images.
# Stopgap only. These images receive no security updates.
helm upgrade my-redis oci://registry-1.docker.io/bitnamicharts/redis \
  --set image.repository=bitnamilegacy/redis \
  --set volumePermissions.image.repository=bitnamilegacy/os-shell \
  --set metrics.image.repository=bitnamilegacy/redis-exporter

Note the three separate image overrides. Bitnami charts reference multiple images, and missing one is the usual reason the first fix attempt doesn't work.

Worth auditing your whole cluster for this, not just Redis. Bitnami charts are extremely common as subchart dependencies, so the reference is often two levels down in something you didn't know pulled it.


Deploying Redis with a StatefulSet

A StatefulSet is the right primitive for Redis because it gives each pod a stable network identity (redis-0, redis-1) and a PVC that survives rescheduling. A Deployment gives you neither, which is why a Deployment-based Redis will eventually surprise you.

Here's a single-instance Redis with persistence, verified against Kubernetes 1.34 and Redis 8.10:

apiVersion: v1
kind: ConfigMap
metadata:
  name: redis-config
data:
  redis.conf: |
    bind 0.0.0.0
    protected-mode no
    maxmemory-policy allkeys-lru
    appendonly yes
    appendfsync everysec
    save 900 1
    save 300 10
    save 60 10000
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: redis
spec:
  serviceName: redis
  replicas: 1
  selector:
    matchLabels:
      app: redis
  template:
    metadata:
      labels:
        app: redis
    spec:
      securityContext:
        runAsNonRoot: true
        runAsUser: 999
        fsGroup: 999
      containers:
        - name: redis
          image: redis:8.10
          command: ["redis-server", "/etc/redis/redis.conf"]
          ports:
            - containerPort: 6379
              name: redis
          resources:
            requests:
              cpu: "1"
              memory: 4Gi
            limits:
              memory: 4Gi
          securityContext:
            allowPrivilegeEscalation: false
            capabilities:
              drop: ["ALL"]
          livenessProbe:
            exec:
              command: ["redis-cli", "ping"]
            initialDelaySeconds: 15
            periodSeconds: 10
          readinessProbe:
            exec:
              command: ["redis-cli", "ping"]
            initialDelaySeconds: 5
            periodSeconds: 5
          volumeMounts:
            - name: config
              mountPath: /etc/redis
            - name: data
              mountPath: /data
      volumes:
        - name: config
          configMap:
            name: redis-config
  volumeClaimTemplates:
    - metadata:
        name: data
      spec:
        accessModes: ["ReadWriteOnce"]
        resources:
          requests:
            storage: 10Gi

Three things in there are deliberate and often get missed.

No CPU limit. Redis is single-threaded for command execution, so a CPU limit mostly buys you CFS throttling and latency spikes at exactly the wrong moment. Set a request so the scheduler reserves capacity. Leave the limit off.

Memory request equals memory limit. This puts the pod in the Guaranteed QoS class, which makes it the last thing evicted under node memory pressure. For a stateful cache that is worth more than the bin-packing efficiency you give up.

maxmemory is not set in the config. If you set it here it has to be kept in sync with the container limit by hand, and they will drift. Either set both together and treat them as one change, or set maxmemory to roughly 70 to 75% of the container limit to leave room for copy-on-write during snapshots. Getting this wrong is the single most common cause of Redis pods being OOMKilled during a BGSAVE.

Apply it and check:

kubectl apply -f redis-statefulset.yaml
kubectl rollout status statefulset/redis
kubectl exec -it redis-0 -- redis-cli INFO server | head -20

Redis Cluster on Kubernetes

Redis Cluster splits the keyspace into 16384 fixed hash slots. Those slots are distributed across your primary shards. The number of shards is your decision, usually three primaries minimum for a valid cluster, each with at least one replica.

This is worth stating plainly because it's widely misreported, including in an earlier version of this guide: 16384 is the slot count, not the shard count. You do not run 16384 anything.

Slot ownership is what makes Redis Cluster awkward on Kubernetes. When a pod is rescheduled it gets a new IP, and the cluster bus has to learn about it. The node ID in nodes.conf persists on the PVC, which is what lets a rescheduled pod rejoin rather than being treated as a new member, so nodes.conf must live on persistent storage.

apiVersion: v1
kind: ConfigMap
metadata:
  name: redis-cluster-config
data:
  redis.conf: |
    bind 0.0.0.0
    protected-mode no
    cluster-enabled yes
    cluster-config-file /data/nodes.conf
    cluster-node-timeout 15000
    cluster-require-full-coverage no
    cluster-migration-barrier 1
    appendonly yes
    appendfsync everysec
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: redis-cluster
spec:
  serviceName: redis-cluster
  replicas: 6
  podManagementPolicy: Parallel
  selector:
    matchLabels:
      app: redis-cluster
  template:
    metadata:
      labels:
        app: redis-cluster
    spec:
      topologySpreadConstraints:
        - maxSkew: 1
          topologyKey: topology.kubernetes.io/zone
          whenUnsatisfiable: DoNotSchedule
          labelSelector:
            matchLabels:
              app: redis-cluster
      containers:
        - name: redis
          image: redis:8.10
          command: ["redis-server", "/etc/redis/redis.conf"]
          ports:
            - containerPort: 6379
              name: client
            - containerPort: 16379
              name: gossip
          env:
            - name: POD_IP
              valueFrom:
                fieldRef:
                  fieldPath: status.podIP
          resources:
            requests:
              cpu: "1"
              memory: 4Gi
            limits:
              memory: 4Gi
          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: 10Gi

Once the pods are up, form the cluster:

kubectl exec -it redis-cluster-0 -- redis-cli --cluster create \
  $(for i in $(seq 0 5); do \
      kubectl get pod redis-cluster-$i -o jsonpath='{.status.podIP}:6379 '; \
    done) \
  --cluster-replicas 1 --cluster-yes

Then verify slot coverage:

kubectl exec -it redis-cluster-0 -- redis-cli --cluster check localhost:6379

The topologySpreadConstraints block matters more than it looks. Without it, Kubernetes is free to schedule a primary and its replica onto the same node, and you find out during a node failure that your replication topology was decorative.

cluster-require-full-coverage no is a judgment call. Set to yes (the default), the entire cluster stops serving if any slot range is uncovered. Set to no, the healthy portion keeps serving and requests for missing slots error out. For a cache, no is almost always what you want. For anything where partial reads are worse than no reads, leave it at yes.


Scaling Redis on Kubernetes

Horizontal scaling and the HorizontalPodAutoscaler trap

You cannot autoscale Redis Cluster with a HorizontalPodAutoscaler. This is the most important thing on this page and it contradicts a lot of published guidance, including what this guide used to say.

The HPA changes the replica count on a StatefulSet. It does not run redis-cli --cluster reshard. Adding a pod to a Redis Cluster StatefulSet gives you a running Redis process that owns zero hash slots and serves zero traffic. Removing one takes its slots offline. The autoscaler will happily do both while reporting success.

If you saw an autoscaling/v2beta2 HPA manifest in an older version of this guide, it also would not have applied: that API version was removed in Kubernetes 1.26, released December 2022. The current API is autoscaling/v2. But the correct fix isn't updating the API version. It's not using an HPA here at all.

Scaling Redis Cluster is a two-step operation, and the resharding step is the one that matters:

# 1. Scale the StatefulSet
kubectl scale statefulset redis-cluster --replicas=8

# 2. Add the new nodes to the cluster
kubectl exec -it redis-cluster-0 -- redis-cli --cluster add-node \
  <new-pod-ip>:6379 <existing-pod-ip>:6379

# 3. Move slots onto them. This is the part an HPA will never do for you.
kubectl exec -it redis-cluster-0 -- redis-cli --cluster reshard \
  <existing-pod-ip>:6379 --cluster-yes

Resharding moves keys between nodes while the cluster serves traffic. It's online, but it isn't free, and on a large dataset it's a maintenance window.

Vertical scaling

Vertical scaling is more useful for Redis than horizontal scaling, and also more limited. More memory means a larger dataset, straightforwardly. More CPU means very little, because Redis executes commands on one thread.

Redis 8 does have I/O threading, which moves socket reads and writes off the main thread and can meaningfully improve throughput on connection-heavy workloads. Command execution is still serialized. On a 16-core node, a Redis pod will leave most of those cores idle no matter how you size the request.

That ceiling is the reason most Redis-on-Kubernetes deployments eventually become Redis Cluster deployments, which is where the operational cost really starts.

As of Kubernetes 1.33, in-place pod resize is available, which lets you change CPU and memory on a running pod without recreating it. For Redis this is genuinely useful, since a restart means reloading the dataset. Check whether your cluster and node versions support it before planning around it.


Redis operators for Kubernetes

An operator encodes the operational knowledge that a StatefulSet doesn't have: which pod is the primary, what to do when it stops responding, how to sequence a rolling update so you don't lose quorum.

Three options are worth evaluating as of August 2026.

Operator

CRDs

Topologies

License

Notes

Spotahome redis-operator

RedisFailover

Sentinel only

Apache 2.0

Mature, narrow scope, does one thing reliably. No Redis Cluster support.

OT-Container-Kit (OpsTree) redis-operator

Redis, RedisReplication, RedisSentinel, RedisCluster

Standalone, replication, Sentinel, Cluster

Apache 2.0

Broadest topology coverage. Built-in redis-exporter metrics. Requires Redis 6+.

Redis Enterprise Operator

RedisEnterpriseCluster, RedisEnterpriseDatabase

Enterprise clustering

Commercial

Licensed product. Active-active geo-replication and modules. Different cost and support model.

Spotahome is the conservative pick if Sentinel-based HA is all you need. The RedisFailover resource is small, the behavior is predictable, and the project has been maintained for years without scope creep.

helm repo add redis-operator https://spotahome.github.io/redis-operator/
helm install redis-operator redis-operator/redis-operator

OT-Container-Kit is the one to look at if you need Redis Cluster managed declaratively. It covers more topologies than anything else in the open source landscape.

helm repo add ot-helm https://ot-container-kit.github.io/helm-charts/
helm install redis-operator ot-helm/redis-operator --namespace redis-operator --create-namespace

Redis Enterprise Operator is a different category. If you're evaluating it, you're evaluating Redis Enterprise, and the Kubernetes piece is not really the deciding factor.

One thing worth saying about all three: an operator makes Redis easier to run on Kubernetes. It doesn't change what Redis is. You still have one thread executing commands, you still have to reshard by hand when the cluster grows, and you still have a topology whose complexity scales with your data.


Persistence and storage

Redis offers two persistence mechanisms, and the Kubernetes-specific advice is mostly about how they interact with node behavior.

RDB snapshots fork the process and write a point-in-time dump. The fork means copy-on-write memory pressure proportional to your write rate during the snapshot. On a pod with a hard memory limit, a BGSAVE on a write-heavy instance is a plausible OOMKill.

AOF logs every write and replays it on startup. More durable, larger files, slower cold start. On Kubernetes, that slower cold start is the part to think about, because pod rescheduling is normal rather than exceptional.

appendonly yes
appendfsync everysec
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb

appendfsync everysec is the usual middle ground: at most one second of writes lost on an unclean stop, without the throughput cost of always.

Storage class choice matters more than most people expect. Network-attached storage such as EBS gp3 or Azure Managed Disks gives you volumes that survive node loss, which is what you want, but AOF fsync latency lands directly on your write path. Local NVMe is much faster and disappears with the node. For a cache, local storage plus a fast rebuild is often the better trade. For anything else, take the network-attached volume and size the IOPS deliberately.

A PodDisruptionBudget is not optional if you care about availability during node maintenance:

apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
  name: redis-cluster-pdb
spec:
  minAvailable: 4
  selector:
    matchLabels:
      app: redis-cluster

Without this, a cluster autoscaler consolidating nodes can drain several Redis pods at once. The pods come back. The cluster may not come back the way you left it.


Monitoring Redis on Kubernetes

Deploy redis_exporter as a sidecar and scrape it with Prometheus:

        - name: redis-exporter
          image: oliver006/redis_exporter:v1.69.0
          ports:
            - containerPort: 9121
              name: metrics
          env:
            - name: REDIS_ADDR
              value: "redis://localhost:6379"
          resources:
            requests:
              cpu: 50m
              memory: 64Mi

With Prometheus Operator installed, a ServiceMonitor picks it up:

apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
  name: redis
spec:
  selector:
    matchLabels:
      app: redis
  endpoints:
    - port: metrics
      interval: 30s

The metrics that actually predict incidents:

  • redis_memory_used_bytes against your container limit, not against maxmemory
  • redis_evicted_keys_total rising, which means you're undersized and silently losing data
  • redis_rdb_last_bgsave_status and redis_aof_last_write_status, both of which fail quietly
  • redis_connected_clients against maxclients
  • redis_mem_fragmentation_ratio above about 1.5, which is where you start paying for memory you aren't using

That last one is worth watching over weeks rather than minutes. Fragmentation creeps, and the usual first sign is a memory bill that stopped matching the dataset size.

Cache hit rate is worth deriving and alerting on:

rate(redis_keyspace_hits_total[5m])
  / (rate(redis_keyspace_hits_total[5m]) + rate(redis_keyspace_misses_total[5m]))

Securing Redis on Kubernetes

Redis has no meaningful default security. Everything below is something you have to add.

Authentication. Never put a password in a ConfigMap. Use a Secret and mount it:

kubectl create secret generic redis-auth --from-literal=password="$(openssl rand -base64 32)"

ACLs (Redis 6+) are better than a single shared password. Give your application a user that can run the commands it needs and nothing else:

user app on >APP_PASSWORD ~cache:* +@read +@write +@keyspace -@dangerous
user default off

Disabling the default user is the step people skip.

Network policy. Redis on Kubernetes is reachable from every pod in the cluster unless you say otherwise:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: redis-access
spec:
  podSelector:
    matchLabels:
      app: redis
  policyTypes: ["Ingress"]
  ingress:
    - from:
        - podSelector:
            matchLabels:
              redis-client: "true"
      ports:
        - protocol: TCP
          port: 6379

TLS. Redis 6+ supports TLS natively, so stunnel and spiped sidecars are no longer necessary. Mount a kubernetes.io/tls secret and point Redis at it with --tls-port 6379 --port 0 --tls-cert-file --tls-key-file --tls-ca-cert-file.

Keep current. Redis 8.0 reaches end of support on 1 December 2026. Anything on 7.0 or earlier is already past EOL and is not getting security patches. The July 2026 coordinated security release patched every supported line from 6.2 through 8.8, which is a reasonable indicator of how often this matters.


Common problems and how to diagnose them

Pod stuck in CrashLoopBackOff after a restart. Usually a corrupt AOF. Check kubectl logs redis-0 --previous. Redis 8 has auto-repair options for a broken AOF tail on startup; otherwise redis-check-aof --fix on the PVC.

ImagePullBackOff on a chart that worked last month. See the Bitnami section above. This is the most common cause in 2026.

OOMKilled during BGSAVE. The fork's copy-on-write allocation pushed the pod past its memory limit. Lower maxmemory relative to the container limit, or move snapshots to a replica.

Cluster shows CLUSTERDOWN after node maintenance. Slots are uncovered. redis-cli --cluster check will show which. If pods came back with new IPs and could not rejoin, verify that cluster-config-file is on the PVC and not in an ephemeral path.

Latency spikes with no obvious cause. Check for CFS throttling with container_cpu_cfs_throttled_seconds_total. If you set a CPU limit on Redis, this is very likely your answer.

Replica never finishes syncing. Usually the primary's client-output-buffer-limit for replicas is too low for the write rate, and the replica gets disconnected mid-sync and starts over. Look for Client ... scheduled to be closed ASAP in the primary's logs.


The alternative: one node instead of six

Everything above is real, current, and works. It's also a lot of machinery, and most of it exists to work around one property of Redis: command execution happens on a single thread, so the only way past one core is to shard.

Dragonfly takes the other path. It's a drop-in replacement for the Redis and Memcached APIs built on a shared-nothing, thread-per-core architecture, so a single instance uses every core on the machine. Same RESP protocol, same clients, no application changes.

On Kubernetes, that changes the shape of the problem rather than the tooling. A six-pod Redis Cluster StatefulSet with slot management, resharding runbooks, and a PodDisruptionBudget tuned to protect quorum becomes a primary and a replica, or a single pod with a replica for failover.

Instacart made exactly this move on their ad-serving feature store. Moving from Redis to Dragonfly cut their node count by roughly 80% and improved latency by about 50%. The node reduction is the part that matters for a Kubernetes discussion, because every node is scheduling surface, resharding work, and a thing that can be drained at the wrong moment.

Deploying with the Dragonfly Operator

The Dragonfly Operator manages instances through a Dragonfly custom resource (dragonflies.dragonflydb.io, API group dragonflydb.io/v1alpha1). Install it:

kubectl apply -f https://raw.githubusercontent.com/dragonflydb/dragonfly-operator/main/manifests/dragonfly-operator.yaml

That creates the CRD, the dragonfly-operator-system namespace, RBAC, and the controller manager. There's also a Helm chart published as an OCI artifact to GHCR, currently v1.3.1, if you'd rather manage it that way.

A production instance with authentication, persistence, and replicas spread across zones:

apiVersion: dragonflydb.io/v1alpha1
kind: Dragonfly
metadata:
  name: dragonfly
spec:
  replicas: 2
  resources:
    requests:
      cpu: "8"
      memory: 32Gi
    limits:
      memory: 32Gi
  authentication:
    passwordFromSecret:
      name: dragonfly-auth
      key: password
  snapshot:
    cron: "0 */6 * * *"
    dir: /data
    enableOnMasterOnly: true
    persistentVolumeClaimSpec:
      accessModes: ["ReadWriteOnce"]
      resources:
        requests:
          storage: 64Gi
  topologySpreadConstraints:
    - maxSkew: 1
      topologyKey: topology.kubernetes.io/zone
      whenUnsatisfiable: DoNotSchedule
      labelSelector:
        matchLabels:
          app: dragonfly

The operator generates the StatefulSet, a Service that always points at the current primary, PVCs where snapshots or tiering need them, and a PodDisruptionBudget for multi-replica instances. Pod index 0 becomes the primary; the rest are configured as replicas automatically.

Failover uses Dragonfly's REPLTAKEOVER, which promotes a replica and repoints the Service selector. No Sentinel quorum to size, no separate monitoring tier to run.

A few fields worth knowing about:

  • snapshot.enableOnMasterOnly: true keeps snapshot work off the primary's replicas. On a large dataset this is the difference between a predictable p99 and a periodic latency cliff.
  • tiering.persistentVolumeClaimSpec enables SSD offload for cold data, which lets a dataset exceed RAM without moving to a sharded topology.
  • memcachedPort exposes the Memcached protocol alongside RESP on 6379, which is occasionally the cheapest way to consolidate two caching tiers.

Check status and scale the same way you would anything else:

kubectl describe dragonflies.dragonflydb.io dragonfly
kubectl patch dragonfly dragonfly --type merge -p '{"spec":{"replicas":3}}'

Connect at <name>.<namespace>.svc.cluster.local with any Redis client. The Service follows the primary through failover, so your application doesn't need to know a failover happened.

For datasets beyond what a single node can hold, Dragonfly Swarm provides multi-shard clustering, but the threshold where you need it sits far higher than with Redis, because a single Dragonfly node scales to the whole machine first.

Being fair about it

If you're running a 2 GB session cache on a StatefulSet and it hasn't given you trouble, this is not a problem you have. Redis on Kubernetes is fine at that size and the migration wouldn't pay for itself.

The calculus changes when you're maintaining a resharding runbook, when node count is driving your bill, or when a Kubernetes node upgrade has become a scheduled risk event because of what it does to your cache tier. That's the point where the number of moving parts is the actual cost, and reducing it is worth more than any single optimization.


Frequently asked questions

Can you run Redis on Kubernetes in production?

Yes. Use a StatefulSet rather than a Deployment for stable pod identity and persistent volumes, add an operator for automatic failover, and set a PodDisruptionBudget so node maintenance doesn't take down multiple pods at once. The main risks are cold starts after rescheduling and the fact that Redis Cluster resharding is not something Kubernetes does for you.

What is the difference between a StatefulSet and a Deployment for Redis?

A StatefulSet gives each pod a stable name and network identity (redis-0, redis-1) and binds it to a specific PersistentVolumeClaim that survives rescheduling. A Deployment treats pods as interchangeable and does not guarantee either. Redis needs stable identity for replication and cluster membership, so a StatefulSet is the correct choice.

How many hash slots does Redis Cluster have?

Redis Cluster has 16384 hash slots, always. Every key maps to a slot via CRC16(key) mod 16384, and slots are distributed across your primary shards. The slot count is fixed and unrelated to the number of nodes you run. A minimum viable Redis Cluster is three primaries.

Can you use a HorizontalPodAutoscaler with Redis?

Not usefully. An HPA changes the replica count on a StatefulSet but does not reshard Redis Cluster, so a scaled-up pod owns zero hash slots and serves no traffic, and a scaled-down pod takes its slots offline. Scale Redis Cluster manually with redis-cli --cluster add-node followed by redis-cli --cluster reshard.

Why did my Bitnami Redis Helm chart stop working?

Broadcom moved Bitnami's versioned container images to docker.io/bitnamilegacy on 28 August 2025 and deleted the original public catalog on 29 September 2025. Charts still reference the old locations, so image pulls fail. Running pods keep working until something triggers a new pull, which is why the failure often shows up during a node drain or rollout rather than immediately.

Should you use AOF or RDB persistence on Kubernetes?

Use both, with AOF as the primary durability mechanism (appendonly yes, appendfsync everysec) and RDB snapshots for faster restores. On Kubernetes, weight the decision toward restart time, since pod rescheduling is routine. AOF replay on a large dataset can leave a pod unavailable for minutes.

Which Redis operator should you use for Kubernetes?

Spotahome's redis-operator if Sentinel-based HA covers your needs and you want the smallest, most predictable option. OT-Container-Kit's redis-operator if you need Redis Cluster managed declaratively, since it supports standalone, replication, Sentinel, and Cluster topologies. Redis Enterprise Operator if you're already buying Redis Enterprise.

Does Redis use multiple CPU cores on Kubernetes?

Command execution is single-threaded regardless of how many cores the pod requests. Redis 8 uses I/O threading for socket reads and writes, which helps on connection-heavy workloads, but the command path is still serialized. Allocating more than a couple of cores to a Redis pod mostly wastes them. Multi-threaded alternatives such as Dragonfly use every core on a single instance.

How much memory should you give a Redis pod?

Set the memory request equal to the limit so the pod lands in the Guaranteed QoS class, then configure Redis maxmemory at roughly 70 to 75% of that limit. The headroom covers copy-on-write during BGSAVE forks and replication buffers. Setting maxmemory equal to the container limit is the usual cause of pods being OOMKilled during snapshots.

Should you set a CPU limit on a Redis pod?

No. Set a CPU request so the scheduler reserves capacity, but leave the limit unset. A CPU limit triggers CFS throttling, and because Redis executes commands on one thread, throttling shows up directly as latency spikes on the command path.

How do you connect to Redis from another pod in the cluster?

Use the Service DNS name: <service-name>.<namespace>.svc.cluster.local:6379. For a StatefulSet with a headless Service you can address individual pods at <pod-name>.<service-name>.<namespace>.svc.cluster.local, which is what replication configuration uses. Redis Cluster clients need the cluster-aware mode of their library so they can follow MOVED and ASK redirects.

What happens to Redis data when a Kubernetes pod is rescheduled?

If the pod is part of a StatefulSet with a volumeClaimTemplate, the PersistentVolumeClaim reattaches and Redis reloads from the AOF or RDB file on that volume. Without persistent storage, the data is gone. For Redis Cluster, cluster-config-file must also live on the persistent volume so the rescheduled pod keeps its node ID and can rejoin rather than being treated as a new member.


Was this content helpful?

Help us improve by giving us your feedback.

Switch & save up to 80%

Dragonfly is fully compatible with the Redis ecosystem and requires no code changes to implement. Instantly experience up to a 25X boost in performance and 80% reduction in cost