Skip to content

Commit 958f7d3

Browse files
chore(infra): retire self-hosted MinIO — DO Spaces is canonical (supersedes #4) (#16)
DO Spaces (nyc3.digitaloceanspaces.com, bucket instant-shared) has been the active object-store backend in production since 2026-05-11. The self-hosted MinIO Deployment in instant-data is no longer in the request path for /storage/new — verified via live cluster: OBJECT_STORE_BACKEND=shared-key (alias → do-spaces) OBJECT_STORE_ENDPOINT=nyc3.digitaloceanspaces.com OBJECT_STORE_BUCKET=instant-shared This commit retires the local MinIO manifests and replaces every MINIO_* env injection on production k8s deployments with OBJECT_STORE_* sourced from instant-secrets / instant-infra-secrets. Supersedes PR #4 (2026-05-11), which had drifted from current master after the broad manifest reconciliation work landed. Manifests deleted: - k8s/data/minio.yaml (Deployment + PVC + ClusterIP + NodePort) - k8s/data/minio-bucket-init.yaml (one-shot Job creating instant-shared) - k8s/data/minio-secret.yaml (local-dev MinIO root creds) Env-var injection migrated MINIO_* → OBJECT_STORE_* in: - k8s/app.yaml (instant-api) — removed MINIO_ROOT_USER/PASSWORD optional refs; OBJECT_STORE_* keys already wired via prior storage-abstraction work. - k8s/worker/deployment.yaml (instant-worker) — storage_bytes scanner now reads OBJECT_STORE_* from instant-infra-secrets. - k8s/provisioner/deployment.yaml (instant-provisioner) — storage_bytes scanner block migrated. Also removes the dangling reference to a 'minio-secrets' Secret in the instant-infra namespace that was never defined in-tree (the in-repo Secret lived in instant-data). - k8s/configmap.yaml — removed MINIO_ENDPOINT / MINIO_BUCKET_NAME. - k8s/secrets.yaml (template) — removed MINIO_ROOT_USER/PASSWORD template keys; added OBJECT_STORE_* template keys for DO Spaces. Docs: - k8s/APPLY-CHECKLIST.md — new 'MinIO retirement' section with the post-merge operator cleanup commands (kubectl delete deploy/minio pvc/minio-data svc/{minio,minio-external} job/minio-bucket-init secret/minio-secrets in instant-data). Per CLAUDE.md rule 15 (infra has no auto-apply), the operator runs this manually after merge. Verification: - kubectl apply --dry-run=server -f k8s/{app,configmap,secrets, provisioner/deployment,worker/deployment}.yaml — all clean (no schema errors; pre-existing E2E_TEST_TOKEN hides-previous warning is unrelated to this change). - Live confirmation prod is on DO Spaces: instant-secrets has OBJECT_STORE_BACKEND=shared-key (alias to do-spaces), OBJECT_STORE_ENDPOINT=nyc3.digitaloceanspaces.com. Coverage block: Symptom: Self-hosted MinIO still deployed in instant-data while prod traffic is on DO Spaces Enumeration: rg -n -i 'minio' k8s/ --type yaml Sites found: 8 (3 manifest files + 5 env-injection blocks across app/configmap/worker/provisioner/secrets) Sites touched: 8 (3 deleted + 5 migrated to OBJECT_STORE_*) Coverage test: kubectl apply --dry-run=server clean across all mutated manifests (no resolveError on missing minio- secrets, no env-var redefinition warnings beyond the pre-existing E2E_TEST_TOKEN one) Live verified: Operator runs APPLY-CHECKLIST.md 'MinIO retirement' section commands post-merge; prod request path verified pre-PR via OBJECT_STORE_BACKEND env on live instant-secrets (DO Spaces, nyc3, instant-shared). Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 07277f4 commit 958f7d3

9 files changed

Lines changed: 163 additions & 233 deletions

File tree

k8s/APPLY-CHECKLIST.md

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,57 @@ of silently regressing.
170170

171171
---
172172

173+
## MinIO retirement (2026-05-20)
174+
175+
The self-hosted MinIO Deployment in `instant-data` was retired in
176+
`chore/retire-self-hosted-minio-2026-05-20` (supersedes the stale PR #4
177+
from 2026-05-11). DO Spaces (`nyc3.digitaloceanspaces.com`, bucket
178+
`instant-shared`) is the canonical production object-store backend, selected
179+
by `OBJECT_STORE_BACKEND=do-spaces` in `instant-secrets` (and mirrored to
180+
`instant-infra-secrets` for worker + provisioner storage_bytes scanners).
181+
182+
After this PR merges, run the following on the prod cluster (and on any
183+
local Rancher Desktop clusters that still have the legacy MinIO workload
184+
deployed):
185+
186+
```bash
187+
# 1. Confirm context (do NOT run against the wrong cluster)
188+
kubectl config current-context
189+
190+
# 2. Inventory what's actually there before deleting anything
191+
kubectl get deploy,pvc,svc,job,secret -n instant-data -l app=minio
192+
kubectl get secret -n instant-data minio-secrets 2>/dev/null || echo "no minio-secrets"
193+
194+
# 3. Remove the MinIO workload + storage + services + bootstrap Job + Secret
195+
kubectl delete -n instant-data deploy/minio --ignore-not-found
196+
kubectl delete -n instant-data pvc/minio-data --ignore-not-found
197+
kubectl delete -n instant-data svc/minio svc/minio-external --ignore-not-found
198+
kubectl delete -n instant-data job/minio-bucket-init --ignore-not-found
199+
kubectl delete -n instant-data secret/minio-secrets --ignore-not-found
200+
201+
# 4. Verify nothing left
202+
kubectl get pods -n instant-data | grep -i minio # should print nothing
203+
204+
# 5. (Optional) If the legacy `s3.instanode.dev` Ingress still points at
205+
# the minio Service, delete or repoint it to DO Spaces. The Ingress
206+
# object was untracked in this repo — confirm what's live:
207+
kubectl get ingress -A | grep -i minio
208+
209+
# 6. Sanity-check the storage hot path is unaffected
210+
curl -sS https://api.instanode.dev/healthz | jq .
211+
# /storage/new responses should reference *.digitaloceanspaces.com,
212+
# not minio.instant-data.svc.cluster.local.
213+
```
214+
215+
Rollback: revert the merge commit on master, re-apply the deleted
216+
manifests from history (`git show <revert-sha>~1 -- k8s/data/minio*.yaml |
217+
kubectl apply -f -`), and flip `OBJECT_STORE_BACKEND` back to `minio` in
218+
`instant-secrets`. Storage data isn't lost in either direction — the PVC
219+
was on local-path in Rancher Desktop only; DO Spaces holds the real
220+
production object bytes.
221+
222+
---
223+
173224
## Related files
174225

175226
- `README.md` — secrets clobber warning (the same class of bug, but for

k8s/app.yaml

Lines changed: 7 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -194,18 +194,9 @@ spec:
194194
name: instant-secrets
195195
key: R2_BUCKET_NAME
196196
optional: true
197-
- name: MINIO_ROOT_USER
198-
valueFrom:
199-
secretKeyRef:
200-
name: instant-secrets
201-
key: MINIO_ROOT_USER
202-
optional: true
203-
- name: MINIO_ROOT_PASSWORD
204-
valueFrom:
205-
secretKeyRef:
206-
name: instant-secrets
207-
key: MINIO_ROOT_PASSWORD
208-
optional: true
197+
# MINIO_ROOT_USER/MINIO_ROOT_PASSWORD env refs retired 2026-05-20
198+
# (chore/retire-self-hosted-minio-2026-05-20). The api reads
199+
# OBJECT_STORE_* below for the canonical DO Spaces backend.
209200
# ── Razorpay annual plan IDs (codified 2026-05-20) ────────────────
210201
# Live since the annual-pricing toggle shipped. Required for any
211202
# *_yearly plan checkout to succeed. NOT optional in prod, but
@@ -262,8 +253,10 @@ spec:
262253
optional: true
263254
# ── Object-store backend (storage abstraction, 2026-05-20) ────────
264255
# OBJECT_STORE_BACKEND selects the impl: do-spaces (prod today),
265-
# r2, s3, or minio. The rest are backend-specific. See
266-
# common/storageprovider/factory.go.
256+
# r2, or s3. The rest are backend-specific. See
257+
# common/storageprovider/factory.go. The self-hosted MinIO backend
258+
# was retired 2026-05-20 — DO Spaces (`nyc3.digitaloceanspaces.com`,
259+
# bucket `instant-shared`) is the canonical production backend.
267260
- name: OBJECT_STORE_BACKEND
268261
valueFrom:
269262
secretKeyRef:

k8s/configmap.yaml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,9 @@ data:
3636
COMPUTE_PROVIDER: "k8s"
3737
STACK_EXPOSE_VIA: "nodeport"
3838
KUBE_NAMESPACE_APPS: "instant-apps"
39-
MINIO_ENDPOINT: "minio.instant-data.svc.cluster.local:9000"
40-
MINIO_BUCKET_NAME: "instant-shared"
39+
# MINIO_ENDPOINT / MINIO_BUCKET_NAME retired 2026-05-20 (self-hosted MinIO
40+
# retirement). Object storage now lives behind OBJECT_STORE_* in
41+
# instant-secrets (DO Spaces, nyc3, bucket instant-shared).
4142
# Deploy / stack ingress wiring. DEPLOY_DOMAIN is the wildcard zone the
4243
# api builds per-deploy hostnames under (<id>.deployment.instanode.dev);
4344
# without it the code falls back to the hardcoded default "instant.dev".

k8s/data/minio-bucket-init.yaml

Lines changed: 0 additions & 46 deletions
This file was deleted.

k8s/data/minio-secret.yaml

Lines changed: 0 additions & 16 deletions
This file was deleted.

k8s/data/minio.yaml

Lines changed: 0 additions & 124 deletions
This file was deleted.

k8s/provisioner/deployment.yaml

Lines changed: 45 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -201,21 +201,55 @@ spec:
201201
value: "1"
202202
- name: K8S_MONGO_STORAGE_GI
203203
value: "1"
204-
# ── MinIO storage bytes queries ───────────────────────────────────
205-
- name: MINIO_ENDPOINT
206-
value: "minio.instant-data.svc.cluster.local:9000"
207-
- name: MINIO_BUCKET_NAME
208-
value: "instant-shared"
209-
- name: MINIO_ROOT_USER
204+
# ── Object-storage bytes queries ──────────────────────────────────
205+
# Migrated 2026-05-20 from MINIO_* to OBJECT_STORE_* as part of
206+
# chore/retire-self-hosted-minio-2026-05-20 (supersedes PR #4).
207+
# Self-hosted MinIO retired; DO Spaces is the canonical backend.
208+
# Also removes a previously dangling reference to a `minio-secrets`
209+
# Secret in the instant-infra namespace that was never defined in
210+
# the tree (the in-repo Secret lived in instant-data).
211+
- name: OBJECT_STORE_BACKEND
210212
valueFrom:
211213
secretKeyRef:
212-
name: minio-secrets
213-
key: MINIO_ROOT_USER
214-
- name: MINIO_ROOT_PASSWORD
214+
name: instant-infra-secrets
215+
key: OBJECT_STORE_BACKEND
216+
optional: true
217+
- name: OBJECT_STORE_ENDPOINT
218+
valueFrom:
219+
secretKeyRef:
220+
name: instant-infra-secrets
221+
key: OBJECT_STORE_ENDPOINT
222+
optional: true
223+
- name: OBJECT_STORE_REGION
224+
valueFrom:
225+
secretKeyRef:
226+
name: instant-infra-secrets
227+
key: OBJECT_STORE_REGION
228+
optional: true
229+
- name: OBJECT_STORE_ACCESS_KEY
230+
valueFrom:
231+
secretKeyRef:
232+
name: instant-infra-secrets
233+
key: OBJECT_STORE_ACCESS_KEY
234+
optional: true
235+
- name: OBJECT_STORE_SECRET_KEY
236+
valueFrom:
237+
secretKeyRef:
238+
name: instant-infra-secrets
239+
key: OBJECT_STORE_SECRET_KEY
240+
optional: true
241+
- name: OBJECT_STORE_BUCKET
215242
valueFrom:
216243
secretKeyRef:
217-
name: minio-secrets
218-
key: MINIO_ROOT_PASSWORD
244+
name: instant-infra-secrets
245+
key: OBJECT_STORE_BUCKET
246+
optional: true
247+
- name: OBJECT_STORE_SECURE
248+
valueFrom:
249+
secretKeyRef:
250+
name: instant-infra-secrets
251+
key: OBJECT_STORE_SECURE
252+
optional: true
219253
# ── OTLP headers (NR license key) — CODIFIED INTENT ───────────────
220254
# The live deployment has this as an inline `value:` literal (NR
221255
# license key embedded). Codified intent is to pull from

k8s/secrets.yaml

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -51,11 +51,18 @@ stringData:
5151
R2_API_TOKEN: "CHANGE_ME"
5252
R2_ENDPOINT: "CHANGE_ME"
5353
R2_BUCKET_NAME: "CHANGE_ME"
54-
# MinIO credentials (same values as in infra/k8s/data/minio-secret.yaml).
55-
# Used only by the legacy self-hosted MinIO Deployment, which was retired
56-
# 2026-05-20 in favour of DigitalOcean Spaces. Operators MUST replace.
57-
MINIO_ROOT_USER: "CHANGE_ME"
58-
MINIO_ROOT_PASSWORD: "CHANGE_ME"
54+
# Object-storage backend (canonical 2026-05-20 onward — self-hosted MinIO retired).
55+
# OBJECT_STORE_BACKEND selects the impl: do-spaces (prod), r2, or s3.
56+
# The remaining keys are backend-specific credentials. See
57+
# common/storageprovider/factory.go.
58+
OBJECT_STORE_BACKEND: "do-spaces"
59+
OBJECT_STORE_ENDPOINT: "CHANGE_ME"
60+
OBJECT_STORE_PUBLIC_URL: "CHANGE_ME"
61+
OBJECT_STORE_REGION: "CHANGE_ME"
62+
OBJECT_STORE_ACCESS_KEY: "CHANGE_ME"
63+
OBJECT_STORE_SECRET_KEY: "CHANGE_ME"
64+
OBJECT_STORE_BUCKET: "instant-shared"
65+
OBJECT_STORE_SECURE: "true"
5966
# Comma-separated list of admin user emails (case-insensitive). Empty
6067
# / unset → admin endpoints reject every caller (closed-by-default).
6168
# Read by api/internal/middleware/admin.go on every request, no app

0 commit comments

Comments
 (0)