towerops/k8s/secrets.example.yaml
Graham McIntire 9ffa49a8f2 fix(oban): use DynamicLifeline in prod; add /health/live + split k8s probes
Prod paired the Oban Pro Smart engine + unique workers with core
Oban.Plugins.Lifeline, whose rescue has no unique_violation handling. An
orphaned executing CheckExecutorWorker job rescued back to available collides
with its already-scheduled successor on oban_jobs_unique_index (23505),
crashing the plugin every 60s and leaving ~150 orphans stuck. Switch prod to
Oban.Pro.Plugins.DynamicLifeline, which repairs the conflict via
Smart.clear_uniq_violation. Dev keeps core Lifeline (Basic engine).

Add a shallow /health/live endpoint that does not touch db/redis. k8s liveness
and startup probes now target it so a transient dependency outage can't kill or
block boot of a healthy pod; readiness keeps the deep /health to gate the load
balancer. (deployment.yaml probe/replica change pushed separately, after the
image carrying /health/live is live.)

Also drop unused POSTGRES_* keys from the secrets example.
2026-05-20 12:07:29 -05:00

88 lines
2.5 KiB
YAML

# Unified template for every Kubernetes Secret the towerops Deployment
# references. Copy to k8s/secrets.yaml and fill in real values:
#
# cp k8s/secrets.example.yaml k8s/secrets.yaml
# # edit k8s/secrets.yaml — fill in real values
# kubectl apply -f k8s/secrets.yaml
# kubectl rollout restart deployment/towerops -n towerops
#
# k8s/secrets.yaml is gitignored — never commit real secrets. Real
# values live in 1Password.
#
# Secret-by-secret:
# * towerops-secrets — application secrets (REQUIRED)
# * towerops-db — Postgres connection (REQUIRED, envFrom)
# * towerops-aws — AWS credentials (REQUIRED, envFrom)
# * towerops-redis — Redis connection (REQUIRED, envFrom)
# * towerops-billing — Stripe (optional)
# * towerops-llm — DeepSeek API key for insight enrichment (optional)
# * gitlab-registry — Docker registry creds (image pull, separate workflow)
---
apiVersion: v1
kind: Secret
metadata:
name: towerops-secrets
namespace: towerops
type: Opaque
stringData:
# Generate with: openssl rand -base64 32
RELEASE_COOKIE: "CHANGE_ME_openssl_rand_-base64_32"
# Generate with: mix phx.gen.secret (or openssl rand -base64 64)
SECRET_KEY_BASE: "CHANGE_ME_mix_phx_gen_secret"
# Generate with: openssl rand -base64 32
# CRITICAL: losing this makes encrypted columns unrecoverable.
CLOAK_KEY: "CHANGE_ME_openssl_rand_-base64_32"
---
apiVersion: v1
kind: Secret
metadata:
name: towerops-db
namespace: towerops
type: Opaque
stringData:
# Full ecto:// URL — the only DB var the app reads (runtime.exs).
DATABASE_URL: "postgresql://towerops:CHANGE_ME@postgres-host:5432/towerops"
---
apiVersion: v1
kind: Secret
metadata:
name: towerops-aws
namespace: towerops
type: Opaque
stringData:
AWS_ACCESS_KEY_ID: "CHANGE_ME"
AWS_SECRET_ACCESS_KEY: "CHANGE_ME"
AWS_REGION: "us-east-1"
---
apiVersion: v1
kind: Secret
metadata:
name: towerops-redis
namespace: towerops
type: Opaque
stringData:
REDIS_HOST: "CHANGE_ME_redis_host"
REDIS_PORT: "6379"
REDIS_PASSWORD: "CHANGE_ME"
---
apiVersion: v1
kind: Secret
metadata:
name: towerops-billing
namespace: towerops
type: Opaque
stringData:
STRIPE_SECRET_KEY: "CHANGE_ME_sk_live_..."
STRIPE_WEBHOOK_SECRET: "CHANGE_ME_whsec_..."
STRIPE_PRICE_ID: "CHANGE_ME_price_..."
STRIPE_METER_ID: "CHANGE_ME_mtr_..."
---
apiVersion: v1
kind: Secret
metadata:
name: towerops-llm
namespace: towerops
type: Opaque
stringData:
DEEPSEEK_API_KEY: "CHANGE_ME_sk_..."
DEEPSEEK_MODEL: ""