Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions redis/RELEASES.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
# Release Notes - Version 3.4.1

## What's New

- **Grafana Dashboard**: Added optional `GrafanaDashboard` CRD provisioned via the [Grafana Operator](https://grafana.github.io/grafana-operator/). Enable with `grafana.dashboard.enabled: true` (disabled by default). When enabled, a pre-built Redis dashboard is automatically created in your Grafana instance with CPU and memory panels always included, and Connected Clients, Redis Memory Used, Commands/sec, and Cache Hit Rate panels added when `redis.exporter.enabled: true`. Compatible with both Helm and ArgoCD deployments. Configure the target folder, datasource name, and Grafana CR selector via `grafana.folder`, `grafana.datasource`, and `grafana.instanceSelector`.


# Release Notes - Version 3.4.0

## What's New
Expand Down
17 changes: 17 additions & 0 deletions redis/versions/3.4.1/Chart.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
apiVersion: v2
name: redis
description: A master-replica Redis configuration with Redis Sentinel
type: application
version: 3.4.1
appVersion: "7.4"

annotations:
created: "2026-05-25"
lastModified: "2026-06-03"
category: "cache"
createsGvc: false

dependencies:
- name: cpln-common
version: 1.0.0
repository: "oci://ghcr.io/controlplane-com/templates"
288 changes: 288 additions & 0 deletions redis/versions/3.4.1/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,288 @@
## Redis Sentinel

Creates a Redis Sentinel cluster on Control Plane with automatic leader election, failover, and an optional backup configuration.

### Configuration

**Redis and Sentinel** — set replicas, resources, and timeouts for each. Sentinel replicas must be an odd number for quorum:
```yaml
redis:
replicas: 2
resources:
minCpu: 80m
minMemory: 128Mi
cpu: 200m
memory: 256Mi

sentinel:
replicas: 3
quorumAutoCalculation: true # calculates as (replicas/2)+1
```

**Authentication** — enable one method. Apply the same config under both `redis.auth` and `sentinel.auth`:
```yaml
redis:
auth:
password:
enabled: true
value: your-password
# fromSecret:
# enabled: true
# name: my-redis-secret
# passwordKey: password
```

**Persistence** — disabled by default. Enable to attach a persistent volume to Redis:
```yaml
redis:
persistence:
enabled: true
volumes:
data:
initialCapacity: 10
performanceClass: general-purpose-ssd # or high-throughput-ssd (min 1000 GiB)
fileSystemType: ext4
```

When persistence is enabled, lifecycle hooks are automatically added to clean up orphaned temp RDB and AOF rewrite files on every container start and stop. These files are left behind when a pod is terminated mid-sync and can fill the volume over time if not removed.

**Probe tuning for large datasets** — the startup probe window is derived from the readiness probe:
```
startup window = initialDelaySeconds + (30 × periodSeconds)
```
The default (`10 + 30×5 = 160s`) is sufficient for small datasets. With persistence enabled and a large dataset, replicas must load their local AOF before syncing — which can take 60–120s or more — leaving little time for the actual RDB transfer. Increase `periodSeconds` to extend the window:
```yaml
redis:
probes:
readiness:
initialDelaySeconds: 35 # clears the AOF load window
periodSeconds: 20 # startup window = 35 + (30×20) = 635s (~10 min)
```

**Metrics exporter** — disabled by default. When enabled, a `redis_exporter` sidecar is added to each Redis pod. Control Plane scrapes `:9121/metrics` automatically every 30 seconds and makes the metrics available in the console:
```yaml
redis:
exporter:
enabled: true
```
Use `dropMetrics` to filter high-cardinality series before they are stored (regex patterns matched against metric names):
```yaml
redis:
exporter:
dropMetrics:
- "redis_commands_latencies_usec_bucket"
- "redis_latency_percentiles_usec"
```

**Grafana Dashboard** — opt-in, k8s clusters only. When enabled, a `GrafanaDashboard` CRD is provisioned via the [Grafana Operator](https://grafana.github.io/grafana-operator/) and automatically appears in your Grafana instance:

```yaml
grafana:
dashboard:
enabled: true
folder: Redis # Grafana folder the dashboard is placed in
datasource: metrics # name of the Prometheus datasource in your Grafana instance
instanceSelector:
matchLabels:
dashboards: grafana # must match the label on your Grafana CR
```

On Control Plane's managed platform where no Grafana Operator is present, leave this disabled — the `GrafanaDashboard` CRD will have nothing to reconcile it.

**Prerequisites:**

1. **Grafana Operator installed** in your Kubernetes cluster. The operator must be configured with your Grafana instance URL and a Grafana service account API token (not a Control Plane token):

```bash
kubectl create secret generic grafana-admin-credentials \
--from-literal=GF_SECURITY_ADMIN_USER=admin \
--from-literal=GF_SECURITY_ADMIN_PASSWORD=<grafana-api-token> \
-n grafana-operator
```

2. **A Grafana CR** with a label matching `grafana.instanceSelector.matchLabels`. For example:
```yaml
apiVersion: grafana.integreatly.org/v1beta1
kind: Grafana
metadata:
name: grafana
labels:
dashboards: grafana
spec:
external:
url: https://your-org.grafana.cpln.io
adminPassword:
name: grafana-admin-credentials
key: GF_SECURITY_ADMIN_PASSWORD
```

**Included panels:**
- CPU Usage (`cpu_used`) — always included
- Memory Usage (`mem_used`) — always included
- Connected Clients, Redis Memory, Commands/sec, Cache Hit Rate — included when `redis.exporter.enabled: true`

The dashboard includes template variables for datasource, GVC, workload, and replica so you can filter by deployment without editing the dashboard.

**Firewall** — set the internal access scope for both Redis and Sentinel:
```yaml
firewall:
internal_inboundAllowType: same-gvc # same-gvc, same-org, or workload-list
```

### Public Access (External TCP)

Redis and Sentinel can be exposed over the internet via TCP using Control Plane's domain resource with per-replica port routing.

#### Prerequisites

1. **A domain you control** with DNS managed by your registrar (e.g. Cloudflare)
2. **Dedicated Load Balancer** enabled on your GVC — required for arbitrary TCP port routing. Enable this under your GVC settings in the Control Plane console.
3. **DNS records added before deploying** — Control Plane will reject the domain resource on first deploy if ownership has not been proven. Add the following records in your DNS provider for each address before running the deployment. **Disable proxying** (e.g. Cloudflare's orange cloud) — TCP traffic must pass through directly:

| Type | Name | Value |
|------|------|-------|
| TXT | `_cpln-<subdomain>` | your Control Plane org name or org ID (either is accepted) |
| CNAME | `<subdomain>` | `<gvc-alias>.cpln.app` |

Your GVC alias is visible in the Control Plane console under GVC settings. The TXT record proves domain ownership — without it, the first deploy will fail with an `Unable to apply domain` error.

#### Configuration

Enable `publicAccess` for Redis and/or Sentinel and set a subdomain you own:

```yaml
redis:
publicAccess:
enabled: true
address: redis.your-domain.com
firewall:
internal_inboundAllowType: same-gvc
external_inboundAllowCIDR: "0.0.0.0/0" # or restrict to specific CIDRs

sentinel:
publicAccess:
enabled: true
address: redis-sentinel.your-domain.com
firewall:
internal_inboundAllowType: same-gvc
external_inboundAllowCIDR: "0.0.0.0/0"
```

When enabled, a Control Plane `domain` resource is created for each address. Port mapping is one port per replica:
- **Redis**: ports `6380`, `6381`, ... (replica 0, 1, ...)
- **Sentinel**: ports `26380`, `26381`, `26382`, ... (replica 0, 1, 2, ...)

After DNS propagates, the domain status in Control Plane will show **Ready**. You can verify the full DNS chain resolves correctly with:

```bash
dig <subdomain>.your-domain.com CNAME # should return <gvc-alias>.cpln.app
dig <gvc-alias>.cpln.app # should return an IP address
```

#### Connecting Externally (Public Access Enabled)

```bash
# add -a <password> if auth is enabled

# Redis replica 0
redis-cli -h redis.your-domain.com -p 6380 ping

# Redis replica 1
redis-cli -h redis.your-domain.com -p 6381 ping

# Sentinel replica 0
redis-cli -h redis-sentinel.your-domain.com -p 26380 ping
```

### Connecting

Redis is accessible internally on port 6379:
```
RELEASE_NAME-redis.GVC_NAME.cpln.local:6379
```

Sentinel is accessible on port 26379:
```
RELEASE_NAME-sentinel.GVC_NAME.cpln.local:26379
```

To route writes to the current master:
```bash
MASTER_INFO=$(redis-cli -h RELEASE_NAME-sentinel.GVC_NAME.cpln.local -p 26379 SENTINEL get-master-addr-by-name mymaster)
MASTER_HOST=$(echo $MASTER_INFO | cut -d' ' -f1)
MASTER_PORT=$(echo $MASTER_INFO | cut -d' ' -f2)
redis-cli -h $MASTER_HOST -p $MASTER_PORT SET my-key "value"
```

### Backing Up

Set `backup.enabled` to `true`, configure your provider, and set your desired schedule. The backup image is compatible with all Redis versions.

```yaml
backup:
enabled: true
schedule: "0 2 * * *" # daily at 2am UTC
provider: aws # Options: aws or gcp
```

#### AWS S3

For the backup cron job to access an S3 bucket, complete the following in your AWS account first:

1. Create your bucket. Set `backup.aws.bucket` to its name and `backup.aws.region` to its region.

2. If you do not have a Cloud Account set up, refer to the docs to [Create a Cloud Account](https://docs.controlplane.com/guides/create-cloud-account). Set `backup.aws.cloudAccountName` to its name.

3. Create a new IAM policy with the following JSON (replace `YOUR_BUCKET_NAME`) and set `backup.aws.policyName` to match:

```json
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:GetObject",
"s3:PutObject",
"s3:DeleteObject",
"s3:ListBucket",
"s3:GetObjectVersion",
"s3:DeleteObjectVersion"
],
"Resource": [
"arn:aws:s3:::YOUR_BUCKET_NAME",
"arn:aws:s3:::YOUR_BUCKET_NAME/*"
]
}
]
}
```

#### GCS

For the backup cron job to access a GCS bucket, complete the following in your GCP account first:

1. Create your bucket. Set `backup.gcp.bucket` to its name.

2. If you do not have a Cloud Account set up, refer to the docs to [Create a Cloud Account](https://docs.controlplane.com/guides/create-cloud-account). Set `backup.gcp.cloudAccountName` to its name.

**Important**: You must add the `Storage Admin` role when creating your GCP service account.

### Restoring a Backup

Run the following command from a client with access to the bucket (replace `aws s3 cp` with `gsutil cp` for GCS):

```sh
aws s3 cp s3://BUCKET_NAME/PREFIX/BACKUP_FILE.rdb /tmp/dump.rdb
redis-cli \
-h RELEASE_NAME-redis.GVC_NAME.cpln.local \
-p 6379 \
--rdb /tmp/dump.rdb
```

### Supported External Services
- [Redis Documentation](https://redis.io/docs/)
- [Redis Sentinel Documentation](https://redis.io/docs/latest/operate/oss_and_stack/management/sentinel/)

### Release Notes
See [RELEASES.md](https://github.com/controlplane-com/templates/blob/main/redis/RELEASES.md)
Loading
Loading