Redis on Kubernetes

by Afanasy Barbarov

Simple Redis deployment on Kubernetes without the bloat.

Why Not Helm?

Most Redis Helm charts (Bitnami, etc.) come with a lot of extras - sentinel, multiple replicas, complex configurations. For a single-instance cache/session store, a plain StatefulSet is cleaner and easier to understand.

StatefulSet vs Deployment

StatefulSet gives us:

  • Stable pod name (redis-0 instead of redis-7f8b9c-xyz)
  • Stable network identity (redis-0.redis.data.svc.cluster.local)
  • Ordered startup/shutdown
  • Persistent volume that survives pod restarts

For a single Redis instance, this is exactly what's needed.

The Setup

Single Redis 8.4 instance with:

  • Password authentication
  • AOF persistence (append-only file)
  • Prometheus metrics via redis_exporter sidecar
# k8s/redis.yaml
apiVersion: v1
kind: Secret
metadata:
  name: redis
  namespace: data
type: Opaque
stringData:
  password: "<your-password>"
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: redis
  namespace: data
spec:
  serviceName: redis
  replicas: 1
  selector:
    matchLabels:
      app: redis
  template:
    metadata:
      labels:
        app: redis
    spec:
      containers:
        - name: redis
          image: redis:8.4-alpine
          args:
            - redis-server
            - --requirepass
            - $(REDIS_PASSWORD)
            - --appendonly
            - "yes"
          env:
            - name: REDIS_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: redis
                  key: password
          ports:
            - containerPort: 6379
          volumeMounts:
            - name: data
              mountPath: /data
        - name: exporter
          image: oliver006/redis_exporter:v1.67.0
          env:
            - name: REDIS_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: redis
                  key: password
            - name: REDIS_ADDR
              value: "redis://localhost:6379"
          ports:
            - containerPort: 9121
              name: metrics
  volumeClaimTemplates:
    - metadata:
        name: data
      spec:
        accessModes: ["ReadWriteOnce"]
        storageClassName: local-path
        resources:
          requests:
            storage: 5Gi

Connecting from Apps

redis://:<password>@redis.data.svc.cluster.local:6379

Or with environment variables:

env:
  - name: REDIS_URL
    value: "redis.data.svc.cluster.local:6379"
  - name: REDIS_PASSWORD
    valueFrom:
      secretKeyRef:
        name: redis
        key: password

Metrics

The redis_exporter sidecar exposes metrics on port 9121. Key metrics:

  • redis_connected_clients - current connections
  • redis_memory_used_bytes - memory usage
  • redis_commands_processed_total - total commands (counter)

OTel collector scrapes these via kubernetes_sd_configs filtering on app=redis label.

Dashboard

HyperDX dashboard with three panels:

  • Connected Clients (gauge)
  • Memory Used (gauge)
  • Collector Health (up metric)

Note: redis_commands_processed_total is a counter - without rate aggregation it just shows cumulative totals, so I skip it in the dashboard.

Written by Afanasy Barbarov — Tech Lead with 15+ years shipping production systems in Rust, Go, and TypeScript. Facing a similar challenge? Reach out on LinkedIn. Support my work.

More articles

Previous post

NATS with JetStream on Kubernetes.

Read more

Next post

Gateway API and Ingress Setup.

Read more