New to KubeDB? Please start here.
Redis Alerting with Prometheus
This tutorial shows you how to configure Prometheus-based alerting for a KubeDB-managed Redis instance using the redis-alerts Helm chart.
Before You Begin
Ensure you have a Kubernetes cluster and that
kubectlis configured to communicate with it. If you do not already have a cluster, you can create one using kind.Install the KubeDB operator by following the steps here.
Deploy the database in the
alert-redisnamespace:$ kubectl create ns alert-redis namespace/alert-redis createdTo learn more about how Prometheus monitoring works with KubeDB, see the overview here.
Note: YAML files used in this tutorial are stored in docs/examples/redis folder in GitHub repository kubedb/docs.
Configuration
Step 1 (
kube-prometheus-stack) is required to follow this tutorial. Step 2 (Panopticon) is required for the Provisioner Group alerts below (KubeDBRedisPhase...) — skip it only if you just want the exporter-based Database Group alerts. If you have already completed the step(s) you need in another guide, skip ahead.
Step 1: Deploy kube-prometheus-stack
kube-prometheus-stack installs Prometheus, Prometheus Operator, Alertmanager, and Grafana together. This is the recommended way to get the full monitoring stack on Kubernetes.
Add the prometheus-community Helm repo and install:
$ helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
$ helm repo update
$ helm upgrade --install prometheus prometheus-community/kube-prometheus-stack \
--namespace monitoring --create-namespace \
--set grafana.image.tag=7.5.5
Wait for all pods to be ready:
$ kubectl get pods -n monitoring
NAME READY STATUS RESTARTS AGE
alertmanager-prometheus-kube-prometheus-alertmanager-0 2/2 Running 0 2m
prometheus-grafana-xxxx 3/3 Running 0 2m
prometheus-kube-prometheus-operator-xxxx 1/1 Running 0 2m
prometheus-kube-prometheus-prometheus-0 2/2 Running 0 2m
prometheus-kube-state-metrics-xxxx 1/1 Running 0 2m
Find the serviceMonitorSelector/ruleSelector labels that Prometheus uses to pick up ServiceMonitor/PrometheusRule objects — this is the release: prometheus label used throughout this tutorial.
$ kubectl get prometheus -n monitoring -o jsonpath='{.items[0].spec.ruleSelector}'
{"matchLabels":{"release":"prometheus"}}
$ kubectl get prometheus -n monitoring -o jsonpath='{.items[0].spec.serviceMonitorSelector}'
{"matchLabels":{"release":"prometheus"}}
Step 2: Install Panopticon (required for the Provisioner Group alerts)
Panopticon is the Appscode operator that exports the KubeDB operator’s own view of every resource — kubedb_com_redis_status_phase and related metrics. It’s what powers the Provisioner Group alerts below (KubeDBRedisPhaseNotReady/KubeDBRedisPhaseCritical). Skip this step if you only need the exporter-based Database Group alerts.
$ helm repo add appscode https://charts.appscode.com/stable/
$ helm repo update
$ helm upgrade --install panopticon appscode/panopticon \
--version v2026.4.30 \
--namespace kubeops --create-namespace \
--set monitoring.enabled=true \
--set monitoring.agent=prometheus.io/operator \
--set monitoring.serviceMonitor.labels.release=prometheus \
--set-file license=/path/to/kubedb-license.txt \
--wait --timeout 5m0s
Verify Panopticon is running:
$ kubectl get pods -n kubeops
NAME READY STATUS RESTARTS AGE
panopticon-xxxx 1/1 Running 0 1m
Overview
- KubeDB deploys Redis with a built-in
redis_exportersidecar that exposes metrics on port56790. - ServiceMonitor (named
{redis-name}-stats) is created automatically by KubeDB and tells Prometheus to scrape the exporter every 10 seconds. - PrometheusRule is created by the
redis-alertschart and contains all Redis alert definitions grouped by concern: database health, provisioner, ops-manager, and backups (Stash and KubeStash). - Prometheus Operator evaluates every rule expression every 30 seconds and fires matching alerts to AlertManager.
- AlertManager groups, inhibits, and silences alerts, then routes them to configured receivers (Slack, email, PagerDuty, webhook, etc.).
Deploy Redis with Monitoring Enabled
At first, let’s deploy a Redis database with monitoring enabled. Below is the Redis object we are going to create.
apiVersion: kubedb.com/v1
kind: Redis
metadata:
name: rd-alert-demo
namespace: alert-redis
spec:
version: "6.0.20"
deletionPolicy: WipeOut
storage:
storageClassName: "local-path"
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
monitor:
agent: prometheus.io/operator
prometheus:
serviceMonitor:
interval: 10s
labels:
release: prometheus
Here,
spec.monitor.agent: prometheus.io/operatortells KubeDB to create aServiceMonitorresource managed by the Prometheus operator.spec.monitor.prometheus.serviceMonitor.labels.release: prometheusadds therelease: prometheuslabel to the createdServiceMonitor, matching the PrometheusserviceMonitorSelectorso the target is discovered automatically.
Let’s create the Redis resource.
$ kubectl apply -f https://github.com/kubedb/docs/raw/v2026.7.10/docs/examples/redis/monitoring/rd-alert-demo.yaml
redis.kubedb.com/rd-alert-demo created
Now, wait for the database to go into Ready state.
$ kubectl get redis -n alert-redis rd-alert-demo
NAME VERSION STATUS AGE
rd-alert-demo 6.0.20 Ready 62m
KubeDB creates a dedicated stats service with the -stats suffix for monitoring.
$ kubectl get svc -n alert-redis --selector="app.kubernetes.io/instance=rd-alert-demo"
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
rd-alert-demo ClusterIP 10.43.236.232 <none> 6379/TCP 62m
rd-alert-demo-pods ClusterIP None <none> 6379/TCP,16379/TCP 62m
rd-alert-demo-stats ClusterIP 10.43.191.236 <none> 56790/TCP 62m
KubeDB also creates a ServiceMonitor that tells Prometheus where to scrape.
$ kubectl get servicemonitor -n alert-redis
NAME AGE
rd-alert-demo-stats 62m
Verify that the ServiceMonitor carries the release: prometheus label so Prometheus discovers it.
$ kubectl get servicemonitor -n alert-redis rd-alert-demo-stats \
-o jsonpath='{.metadata.labels.release}'
prometheus
Step 1 — Install redis-alerts
The redis-alerts chart creates a PrometheusRule resource containing all Redis alert definitions grouped by concern: database health, provisioner, ops-manager, and backups (Stash / KubeStash).
Why the Helm release name matters
The chart derives the PromQL job/instance scoping (and the PrometheusRule name) from the Helm release name, not from a values field — so the release name must match the Redis object’s name (rd-alert-demo) for the rules to be correctly scoped to this instance.
The chart’s default label is release: kube-prometheus-stack, so we must also override it at install time to match the Prometheus ruleSelector.
Install
$ helm upgrade -i rd-alert-demo oci://ghcr.io/appscode-charts/redis-alerts \
-n alert-redis \
--create-namespace \
--version=v2026.7.14 \
--set form.alert.labels.release=prometheus \
--set form.alert.appSuffix=rd-grafana-demo
| Flag | Value | Purpose |
|---|---|---|
rd-alert-demo (release name) | — | Scopes every PromQL expression to this instance (job="rd-alert-demo-stats") |
-n alert-redis | alert-redis | Installs the PrometheusRule in the same namespace as the database |
form.alert.labels.release | prometheus | Matches the Prometheus ruleSelector so the rules are loaded |
Verify the PrometheusRule is created
$ kubectl get prometheusrule -n alert-redis
NAME AGE
rd-alert-demo 60m
Confirm the release: prometheus label is present.
$ kubectl get prometheusrule -n alert-redis rd-alert-demo \
-o jsonpath='{.metadata.labels.release}'
prometheus
Confirm Prometheus loaded the rules
Port-forward the Prometheus UI and open the Status → Rule health page.
$ kubectl port-forward -n monitoring \
svc/prometheus-kube-prometheus-prometheus 9090:9090
Open http://localhost:9090/rules?search=redis.

The redis.database.alert-redis.rd-alert-demo.rules group (and the accompanying redis.kubeStash.alert-redis.rd-alert-demo.rules group) is visible with all rules showing OK, confirming that Prometheus has loaded and is evaluating the Redis alert definitions every 30 seconds.
Verify End-to-End
1. Check the exporter is running
The exporter sidecar inside the Redis pod serves metrics at :56790/metrics. A value of redis_up 1 confirms the exporter can reach Redis.
$ kubectl exec -n alert-redis rd-alert-demo-0 -c exporter -- \
wget -qO- localhost:56790/metrics | grep redis_up
# HELP redis_up Information about the Redis instance
# TYPE redis_up gauge
redis_up 1
# HELP redis_uptime_in_seconds uptime_in_seconds metric
# TYPE redis_uptime_in_seconds gauge
redis_uptime_in_seconds 2591
2. Check the Prometheus target is UP
Open http://localhost:9090/targets?search=rd-alert-demo-stats. Prometheus discovers more than 20 scrape pools on this cluster, so it will ask you to pick one from the dropdown — select serviceMonitor/alert-redis/rd-alert-demo-stats/0.

The target serviceMonitor/alert-redis/rd-alert-demo-stats/0 shows UP, confirming metrics are being scraped from rd-alert-demo-0 in the alert-redis namespace.
3. Confirm all Redis alerts are inactive
Open http://localhost:9090/alerts?search=redis to see the Redis alert groups.

All 7 rules in the redis.database group show INACTIVE (7), meaning the database is healthy and no thresholds are breached.
4. Check AlertManager
Port-forward AlertManager to view any currently firing alerts.
$ kubectl port-forward -n monitoring \
svc/prometheus-kube-prometheus-alertmanager 9093:9093
Open http://localhost:9093. With a healthy Redis instance, no alerts for rd-alert-demo will be listed here.

Simulating a Firing Alert
The previous section confirmed that all alerts are INACTIVE while the database is healthy. This section walks through deliberately triggering the RedisDown critical alert so you can observe the full alert lifecycle — from firing in Prometheus through to the AlertManager dashboard — and then resolve it.
Unlike some other database exporters, the Redis exporter runs as a separate sidecar container that keeps running fine even if the main redis container crashes and gets restarted by Kubernetes. Because RedisDown requires the outage to persist for for: 2m (not instant), and Kubernetes tends to restart a crashed container within a few seconds, a single redis-cli shutdown is not reliable — confirmed live: one isolated shutdown attempt produced zero pod restarts over what should have been a full window (the container came back before the next scrape landed), while a sustained loop reliably kept it down and fired the alert on the very next try. Don’t trust a one-shot kill for this alert; always use the loop below for the full duration.
1. Stop the Redis process repeatedly
Shut down the redis process inside the pod. This crashes the main container so the exporter sidecar can no longer reach it and reports redis_up 0 on the next scrape, while Kubernetes restarts the crashed container in the background.
$ kubectl exec -n alert-redis rd-alert-demo-0 -c redis -- redis-cli shutdown nosave
Because Kubernetes restarts the container quickly, repeat this command every second for at least two and a half minutes to keep Redis down continuously long enough for the for: 2m window on RedisDown to be satisfied — confirmed live at exactly this cadence:
$ end=$(( $(date +%s) + 150 ))
while [ $(date +%s) -lt $end ]; do
kubectl exec -n alert-redis rd-alert-demo-0 -c redis -- redis-cli shutdown nosave >/dev/null 2>&1
sleep 1
done
Run this in the background (or a separate terminal) and let it run for the full 150 seconds before moving to the next step — stopping early risks landing back in the same “restarted before the next scrape” gap described above.
2. Watch the alert fire in Prometheus
Open http://localhost:9090/alerts?search=redis.

RedisDown moves from INACTIVE to FIRING once the redis_up == 0 condition has held continuously for the configured for: 2m duration. RedisMissingMaster fires alongside it, since with no master node visible the cluster is also missing a master.
3. Check the AlertManager dashboard
Open http://localhost:9093/#/alerts?filter=%7Bapp_namespace%3D%22alert-redis%22%7D.
Note: like several other
*-alertscharts in this project (e.g. Cassandra), Redis’s operator-sourced alerts carryapp_namespacerather than a plainnamespacelabel — filtering onnamespace="alert-redis"silently returns nothing (no error, just an empty “No alert groups found” that looks identical to “healthy”) even while alerts are actively firing. Always filter/group onapp_namespacehere.

AlertManager shows RedisDown and RedisMissingMaster together (confirmed live — dropping to zero visible master nodes trips both at once), alongside KubeDBRedisPhaseNotReady (the KubeDB operator’s own view that the pod isn’t ready) and, if your cluster happens to have real disk pressure at the time, possibly DiskUsageHigh too — that one is unrelated to this simulation and reflects genuine node-disk usage, not a side effect of the kill loop. Each alert card displays:
- Severity:
critical(warningforDiskUsageHigh) - pod:
rd-alert-demo-0in thealert-redisnamespace - job:
rd-alert-demo-stats - Started: timestamp when the alert first fired
AlertManager routes these alerts to every receiver configured in your alertmanagerConfig (Slack, email, PagerDuty, webhook, etc.) based on your routing tree. If no receiver is configured, the alerts are visible here but silently dropped.
4. Restore Redis
Let the loop from step 1 finish (or stop it early) — the container’s own restart policy brings redis back up on its own; no manual pod deletion is needed.
$ kubectl get pod -n alert-redis rd-alert-demo-0
NAME READY STATUS RESTARTS AGE
rd-alert-demo-0 2/2 Running 17 2d16h
If it’s still cycling through CrashLoopBackOff a while after the loop has stopped, Kubernetes’ exponential backoff is just catching up — wait a bit longer before concluding something’s wrong. Once redis_up returns to 1 continuously, Prometheus marks the alert INACTIVE again and AlertManager sends a resolved notification to all receivers.
Alert Reference
All alerts are scoped to the rd-alert-demo instance in the alert-redis namespace via the PromQL label filters job="rd-alert-demo-stats" and namespace="alert-redis".
Database Group
Fired based on live metrics from the Redis exporter.
| Alert | Severity | For | What It Means |
|---|---|---|---|
RedisDown | critical | 2m | Exporter cannot reach Redis — instance is down or crashed. |
RedisMissingMaster | critical | 2m | Redis cluster has fewer nodes marked as master than expected. |
RedisTooManyMasters | critical | 2m | Redis cluster has more nodes marked as master than expected — possible split-brain. |
RedisDisconnectedSlaves | warning | 2m | Redis is not replicating for all slaves — review the replication status. |
RedisTooManyConnections | warning | 2m | More than 80% of maxclients are in use — client pool nearing exhaustion. |
DiskUsageHigh | warning | 5m | Persistent volume usage is between 80% and 95% — plan for capacity. |
DiskAlmostFull | critical | 5m | Persistent volume usage has exceeded 95% — the volume is nearly full. |
Provisioner Group
Monitors the KubeDB operator’s view of the Redis resource phase.
| Alert | Severity | For | What It Means |
|---|---|---|---|
KubeDBRedisPhaseNotReady | critical | 1m | KubeDB marked the Redis resource NotReady — operator cannot reach the database. |
KubeDBRedisPhaseCritical | warning | 15m | The instance is in a degraded/critical phase. |
OpsManager Group
Tracks RedisOpsRequest lifecycle during upgrades, scaling, and reconfiguration.
| Alert | Severity | For | What It Means |
|---|---|---|---|
KubeDBRedisOpsRequestOnProgress | info | instant | A RedisOpsRequest is currently in progress. |
KubeDBRedisOpsRequestStatusProgressingToLong | critical | 30m | A RedisOpsRequest has been in progress for 30+ minutes — likely stuck. |
KubeDBRedisOpsRequestFailed | critical | instant | A RedisOpsRequest failed — check the RedisOpsRequest object for the error. |
Stash Group
Tracks Stash-driven backup/restore health for this instance. (You do not need to configure backups to see these rules; they are included in the PrometheusRule regardless.)
| Alert | Severity | For | What It Means |
|---|---|---|---|
RedisStashBackupSessionFailed | critical | instant | A Stash backup session failed. |
RedisStashRestoreSessionFailed | critical | instant | A Stash restore session failed. |
RedisStashNoBackupSessionForTooLong | warning | instant | No successful backup session for more than 18000s (5 hours). |
RedisStashRepositoryCorrupted | critical | 5m | The Stash backup repository integrity check failed — repository is corrupted. |
RedisStashRepositoryStorageRunningLow | warning | 5m | Backup repository storage size has exceeded 10GB. |
RedisStashBackupSessionPeriodTooLong | warning | instant | A backup session took more than 1800s (30 minutes) to complete. |
RedisStashRestoreSessionPeriodTooLong | warning | instant | A restore session took more than 1800s (30 minutes) to complete. |
KubeStash Group
Tracks KubeStash-driven backup/restore health for this instance. Same semantics as the Stash group above, sourced from KubeStash metrics instead.
| Alert | Severity | For | What It Means |
|---|---|---|---|
RedisKubeStashBackupSessionFailed | critical | instant | A KubeStash backup session failed. |
RedisKubeStashRestoreSessionFailed | critical | instant | A KubeStash restore session failed. |
RedisKubeStashNoBackupSessionForTooLong | warning | instant | No successful backup session for more than 18000s (5 hours). |
RedisKubeStashRepositoryCorrupted | critical | 5m | The KubeStash backup repository integrity check failed — repository is corrupted. |
RedisKubeStashRepositoryStorageRunningLow | warning | 5m | Backup repository storage size has exceeded 10GB. |
RedisKubeStashBackupSessionPeriodTooLong | warning | instant | A backup session took more than 1800s (30 minutes) to complete. |
RedisKubeStashRestoreSessionPeriodTooLong | warning | instant | A restore session took more than 1800s (30 minutes) to complete. |
Customising Alerts
To override thresholds or disable specific alert groups, create a custom values file and upgrade the chart.
# custom-alerts.yaml
form:
alert:
labels:
release: prometheus
groups:
database:
enabled: warning
rules:
redisTooManyConnections:
enabled: true
duration: "5m"
val: 90 # fire at 90% of maxclients instead of the default 80%
severity: warning
opsManager:
enabled: "none" # disable all ops-manager alerts
$ helm upgrade rd-alert-demo oci://ghcr.io/appscode-charts/redis-alerts \
-n alert-redis \
--version=v2026.7.14 \
-f custom-alerts.yaml
Cleaning up
To remove all resources created in this tutorial, run the following commands.
# Remove the redis-alerts release
$ helm uninstall rd-alert-demo -n alert-redis
# Remove the Redis instance
$ kubectl delete redis -n alert-redis rd-alert-demo
# Delete namespace
$ kubectl delete ns alert-redis
# Uninstall monitoring stack (optional — skip if other tutorials on this cluster still need them)
$ helm uninstall panopticon -n kubeops
$ helm uninstall prometheus -n monitoring
Next Steps
- Monitor your Redis database with KubeDB using builtin Prometheus.
- Monitor your Redis database with KubeDB using Prometheus operator.
- Use private Docker registry to deploy Redis with KubeDB.
- Want to hack on KubeDB? Check our contribution guidelines.
































