Skip to content

Commit ee8dc28

Browse files
committed
fix(helm): bundle Redis in secret-manager modes unless the URL is supplied
Suppressing Redis whenever a secret mode was active left those deployments with no Redis at all — REDIS_URL is optional there and both shipped examples omit it. The chart now steps aside only on a detectable signal: an explicit app.env.REDIS_URL, an ESO remoteRefs.app.REDIS_URL mapping, or the new redis.provideUrl=false opt-out for a pre-created Secret it cannot read.
1 parent ebb846f commit ee8dc28

7 files changed

Lines changed: 78 additions & 45 deletions

File tree

apps/docs/content/docs/en/platform/self-hosting/redis.mdx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,12 @@ app:
5858
REDIS_URL: "rediss://:<password>@my-cache.internal:6380"
5959
```
6060
61-
`app.env.REDIS_URL` takes over whenever `redis.enabled` is false. Setting it there is enough — the chart writes every `app.env` key into one Secret that **both** the app and realtime Deployments consume via `envFrom`. Supply it through your secret store rather than plain values; it contains a password, and `externalSecrets.remoteRefs.app.REDIS_URL` is supported.
61+
`app.env.REDIS_URL` takes over whenever it is set, and the chart skips the bundled instance so you do not get a stray pod.
62+
63+
If the URL lives in a secret store rather than in values:
64+
65+
- **External Secrets** — map `externalSecrets.remoteRefs.app.REDIS_URL`. The chart detects the mapping and steps aside automatically.
66+
- **Pre-created Secret** (`app.secrets.existingSecret`) — set `redis.provideUrl: false`. The chart cannot read your Secret, so without this it would inject a computed `REDIS_URL` that takes precedence over `envFrom` and shadows your value.
6267

6368
The bundled Redis is deliberately non-persistent (`--save ""`, `--appendonly no`) with a 512 MB cap: Sim stores coordination state and short-lived keys in it, so a restart costs in-flight live updates rather than committed data.
6469

helm/sim/README.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -473,17 +473,17 @@ Two changes alter behavior on an existing release. Neither requires action, but
473473

474474
* **Free-tier plan limits are no longer preset.** `app.envDefaults` previously shipped `RATE_LIMIT_FREE_SYNC`, `RATE_LIMIT_FREE_ASYNC`, `EXECUTION_TIMEOUT_FREE`, `EXECUTION_TIMEOUT_ASYNC_FREE`, `FREE_TABLES_LIMIT: 3`, and `FREE_TABLE_ROWS_LIMIT: 1000`. With billing disabled the application treats these as **opt-in** — unset means unlimited — so presetting them imposed hosted-plan caps on self-hosted deployments and diverged from Docker Compose, which presets nothing. They are now commented out. **On upgrade, these limits stop being enforced.** To keep them, set the keys explicitly under `app.env`. An explicitly set value has always taken precedence and is unaffected.
475475

476-
* **Redis is now bundled** (`redis.enabled: true`), matching the Docker Compose stack. Redis backs pub/sub and the Socket.IO adapter, and multi-replica deployments silently drop cross-pod events without it. The chart only manages Redis when it can be sure you are not supplying it yourself, so no upgrade reroutes an existing instance:
476+
* **Redis is now bundled** (`redis.enabled: true`), matching the Docker Compose stack. Redis backs pub/sub and the Socket.IO adapter, and multi-replica deployments silently drop cross-pod events without it. The chart steps aside whenever it can tell you are supplying `REDIS_URL` yourself, so no upgrade reroutes an existing instance:
477477

478478
| Your configuration | Bundled Redis | `REDIS_URL` |
479479
|---|---|---|
480480
| Default install | Deployed | Points at the bundled instance |
481481
| `app.env.REDIS_URL` set | Not deployed | Your value |
482-
| `app.secrets.existingSecret.enabled` | Not deployed | Whatever your Secret contains — the chart injects nothing |
483-
| `externalSecrets.enabled` | Not deployed | Whatever ESO syncs — the chart injects nothing |
482+
| `externalSecrets.remoteRefs.app.REDIS_URL` mapped | Not deployed | Synced by ESO — detected automatically |
483+
| `redis.provideUrl: false` | Not deployed | Whatever your pre-created Secret contains |
484484
| `redis.enabled: false` | Not deployed | Unset unless you provide it |
485485

486-
The two secret-manager rows matter: those modes carry `REDIS_URL` out-of-band where the chart cannot read it, and a chart-computed `env` entry would take precedence over `envFrom` and silently shadow it. Rendering is therefore byte-identical to 1.4.0 in both modes. To use the bundled Redis while running a secret manager, set `app.env.REDIS_URL` to the in-cluster address (`redis://<release>-redis:6379`) explicitly — it is not a secret.
486+
**If you use `app.secrets.existingSecret` and that Secret already contains `REDIS_URL`, set `redis.provideUrl: false`.** The chart cannot read a pre-created Secret, so it would otherwise inject a computed `REDIS_URL` as a container `env` entry, which takes precedence over `envFrom` and would shadow your value. External Secrets needs no such flag — mapping `remoteRefs.app.REDIS_URL` is detected on its own.
487487

488488
## Upgrading to 1.2.0
489489

helm/sim/examples/values-existing-secret.yaml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,3 +69,7 @@ postgresql:
6969
# kubectl create secret generic sim-postgresql-secret \
7070
# --namespace sim \
7171
# --from-literal=POSTGRES_PASSWORD="$(openssl rand -base64 16 | tr -d '/+=')"
72+
73+
# Redis: the chart bundles one by default and wires REDIS_URL to it. If the
74+
# Secret referenced above already contains REDIS_URL, set redis.provideUrl=false
75+
# so the chart does not shadow it.

helm/sim/examples/values-external-secrets.yaml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,3 +124,7 @@ postgresql:
124124
# kubernetes:
125125
# mountPath: "kubernetes"
126126
# role: "external-secrets"
127+
128+
# Redis: the chart bundles one by default and wires REDIS_URL to it. To use a
129+
# managed Redis instead, map externalSecrets.remoteRefs.app.REDIS_URL — the
130+
# chart detects that and steps aside.

helm/sim/templates/_helpers.tpl

Lines changed: 30 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -465,33 +465,44 @@ PII (Presidio) service URL
465465
{{- end }}
466466

467467
{{/*
468-
Whether the chart owns Redis for this release.
469-
470-
False when the operator is supplying REDIS_URL out-of-band — either explicitly in
471-
app.env, or through a pre-created Secret / External Secrets, where the chart
472-
cannot see the value. In those modes emitting a computed REDIS_URL as a container
473-
`env` would shadow the operator's value (env beats envFrom), silently rerouting a
474-
managed Redis to an empty in-cluster one on upgrade. Deploying an unused Redis pod
475-
alongside it would be wrong too, so both are skipped.
468+
Whether the operator is supplying REDIS_URL themselves.
469+
470+
Three detectable signals:
471+
- app.env.REDIS_URL set explicitly
472+
- externalSecrets.remoteRefs.app.REDIS_URL mapped (ESO syncs it into the Secret)
473+
- redis.provideUrl=false, the opt-out for a pre-created Secret that already
474+
contains REDIS_URL, which the chart cannot read at render time
475+
476+
When any holds, the chart neither deploys Redis nor emits a computed REDIS_URL —
477+
a container `env` entry beats `envFrom`, so emitting one would silently shadow
478+
the operator's value and reroute a managed Redis to an empty in-cluster instance.
479+
*/}}
480+
{{- define "sim.redisUrlSuppliedByOperator" -}}
481+
{{- $esoRef := "" -}}
482+
{{- if .Values.externalSecrets.enabled -}}
483+
{{- $esoRef = dig "remoteRefs" "app" "REDIS_URL" "" .Values.externalSecrets -}}
484+
{{- end -}}
485+
{{- if or (.Values.app.env.REDIS_URL | default "") $esoRef (not .Values.redis.provideUrl) -}}
486+
true
487+
{{- end -}}
488+
{{- end }}
476489

477-
To use the bundled Redis while running a secret manager, set
478-
app.env.REDIS_URL to the in-cluster address explicitly — it is not a secret.
490+
{{/*
491+
Whether the chart owns Redis for this release: enabled, and the operator is not
492+
supplying a URL themselves. Secret-manager modes alone do NOT suppress it —
493+
doing so left those deployments with no Redis at all, since REDIS_URL is optional
494+
and the shipped examples omit it.
479495
*/}}
480496
{{- define "sim.chartManagesRedis" -}}
481-
{{- $externalUrl := .Values.app.env.REDIS_URL | default "" -}}
482-
{{- $secretMode := or
483-
(and .Values.app.secrets .Values.app.secrets.existingSecret .Values.app.secrets.existingSecret.enabled)
484-
.Values.externalSecrets.enabled -}}
485-
{{- if and .Values.redis.enabled (not $externalUrl) (not $secretMode) -}}
497+
{{- if and .Values.redis.enabled (not (include "sim.redisUrlSuppliedByOperator" .)) -}}
486498
true
487499
{{- end -}}
488500
{{- end }}
489501

490502
{{/*
491-
Redis URL used as a chart-computed container env. Only emitted when the chart
492-
owns Redis (see sim.chartManagesRedis) or when app.env.REDIS_URL is set
493-
explicitly. Empty otherwise, so a Secret-supplied value flows through envFrom
494-
untouched.
503+
Redis URL emitted as a chart-computed container env. Only set when the chart owns
504+
Redis, or when app.env.REDIS_URL is given explicitly. Empty otherwise, so a
505+
Secret- or ESO-supplied value flows through envFrom untouched.
495506
*/}}
496507
{{- define "sim.redisUrl" -}}
497508
{{- $external := .Values.app.env.REDIS_URL | default "" -}}

helm/sim/tests/redis_test.yaml

Lines changed: 22 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -114,35 +114,49 @@ tests:
114114
name: FREE_TABLES_LIMIT
115115
value: "3"
116116

117-
# Secret-manager modes carry REDIS_URL out-of-band, where the chart cannot see
118-
# it. Emitting a computed REDIS_URL as inline `env` would beat `envFrom` and
119-
# silently reroute a managed Redis to an empty in-cluster one on upgrade.
120-
- it: does not inject REDIS_URL in existingSecret mode
117+
# A secret mode alone must NOT suppress Redis — REDIS_URL is optional there and
118+
# the shipped examples omit it, so suppressing would leave no Redis at all.
119+
- it: still bundles Redis in existingSecret mode when no URL is supplied
120+
template: deployment-redis.yaml
121+
set:
122+
app.secrets.existingSecret.enabled: true
123+
app.secrets.existingSecret.name: my-app-secrets
124+
asserts:
125+
- hasDocuments:
126+
count: 2
127+
128+
# ...but the operator can opt out when their pre-created Secret already has it,
129+
# which the chart cannot read at render time.
130+
- it: honours redis.provideUrl=false for a Secret that already carries REDIS_URL
121131
template: deployment-app.yaml
122132
set:
123133
app.secrets.existingSecret.enabled: true
124134
app.secrets.existingSecret.name: my-app-secrets
135+
redis.provideUrl: false
125136
asserts:
126137
- notContains:
127138
path: spec.template.spec.containers[0].env
128139
content:
129140
name: REDIS_URL
130141
value: "redis://t-sim-redis:6379"
131142

132-
- it: does not bundle Redis in existingSecret mode
143+
- it: deploys no Redis when provideUrl is false
133144
template: deployment-redis.yaml
134145
set:
135146
app.secrets.existingSecret.enabled: true
136147
app.secrets.existingSecret.name: my-app-secrets
148+
redis.provideUrl: false
137149
asserts:
138150
- hasDocuments:
139151
count: 0
140152

141-
- it: does not inject REDIS_URL in External Secrets mode
153+
# ESO exposes a detectable signal, so no manual opt-out is needed there.
154+
- it: detects an ESO-mapped REDIS_URL and steps aside
142155
template: deployment-app.yaml
143156
set:
144157
externalSecrets.enabled: true
145158
externalSecrets.secretStoreRef.name: my-store
159+
externalSecrets.remoteRefs.app.REDIS_URL: sim/app/redis-url
146160
externalSecrets.remoteRefs.app.BETTER_AUTH_SECRET: sim/app/better-auth-secret
147161
externalSecrets.remoteRefs.app.ENCRYPTION_KEY: sim/app/encryption-key
148162
externalSecrets.remoteRefs.app.INTERNAL_API_SECRET: sim/app/internal-api-secret
@@ -155,7 +169,7 @@ tests:
155169
name: REDIS_URL
156170
value: "redis://t-sim-redis:6379"
157171

158-
- it: does not bundle Redis in External Secrets mode
172+
- it: still bundles Redis under ESO when REDIS_URL is not mapped
159173
template: deployment-redis.yaml
160174
set:
161175
externalSecrets.enabled: true
@@ -167,16 +181,4 @@ tests:
167181
externalSecrets.remoteRefs.postgresql.password: sim/postgresql/password
168182
asserts:
169183
- hasDocuments:
170-
count: 0
171-
172-
- it: realtime also gets no computed REDIS_URL in existingSecret mode
173-
template: deployment-realtime.yaml
174-
set:
175-
app.secrets.existingSecret.enabled: true
176-
app.secrets.existingSecret.name: my-app-secrets
177-
asserts:
178-
- notContains:
179-
path: spec.template.spec.containers[0].env
180-
content:
181-
name: REDIS_URL
182-
value: "redis://t-sim-redis:6379"
184+
count: 2

helm/sim/values.yaml

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ app:
106106
# Optional: API Key Encryption (RECOMMENDED for production)
107107
# Generate with: openssl rand -hex 32 (produces the required 64-hex-char / 32-byte value).
108108
API_ENCRYPTION_KEY: "" # OPTIONAL - encrypts API keys at rest; if unset, keys are stored in plain text
109-
REDIS_URL: "" # OPTIONAL - external Redis connection string. Takes precedence over the bundled Redis (see the `redis:` section) and suppresses it. May also come from a pre-created Secret or External Secrets; in those modes the chart injects no REDIS_URL and deploys no bundled Redis, so your value is used as-is.
109+
REDIS_URL: "" # OPTIONAL - external Redis connection string. Takes precedence over the bundled Redis (see the `redis:` section) and suppresses it. If it instead comes from a pre-created Secret, set redis.provideUrl=false; if from External Secrets, map externalSecrets.remoteRefs.app.REDIS_URL and the chart detects it.
110110

111111
# Email & Communication
112112
# Configure one provider — the mailer auto-detects in priority order:
@@ -564,6 +564,13 @@ realtime:
564564
redis:
565565
enabled: true
566566

567+
# Inject REDIS_URL pointing at the bundled instance. Set false when you run
568+
# `app.secrets.existingSecret` and that Secret already contains REDIS_URL —
569+
# the chart cannot read a pre-created Secret, and a computed env entry would
570+
# take precedence over it. Not needed for External Secrets: mapping
571+
# externalSecrets.remoteRefs.app.REDIS_URL is detected automatically.
572+
provideUrl: true
573+
567574
image:
568575
repository: redis
569576
tag: "7-alpine"

0 commit comments

Comments
 (0)