Kubernetes
The Shift Platform uses Kustomize for Kubernetes manifest management, with a base layer and per-environment overlays.
Kustomize Structure
k8s/
|-- kind-config.yml # Kind cluster config (port mapping, ingress-ready)
|-- base/ # Shared across all environments
| |-- kustomization.yml
| |-- namespace.yml # shift-platform namespace
| |-- configmap.yml # Base config (PORT, SHIFT_STORAGE, etc.)
| |-- deployment.yml # Gateway deployment (2 replicas, resource limits)
| |-- service.yml # ClusterIP 80 -> 3000
| |-- ingress.yml # Host-based routing
| +-- convex/
| |-- deployment.yml # Self-hosted Convex (port 3210, /version readiness)
| +-- service.yml # ClusterIP 3210
+-- overlays/
|-- dev/ # Local development (kind)
| |-- kustomization.yml
| |-- configmap-patch.yml # NODE_ENV=development, LOG_LEVEL=debug
| |-- deployment-patch.yml # 1 replica, lower resources
| +-- ingress-patch.yml # host: shift.lvh.me
|-- staging/ # Staging (staging.the-shift.dev)
| +-- ...
+-- prod/ # Production (app.the-shift.dev)
+-- ...
Base Resources
Namespace
All platform resources live in the shift-platform namespace (or shift-platform-staging for staging).
ConfigMap
The base ConfigMap sets default configuration values:
| Key | Default |
|---|---|
PORT | 3000 |
SHIFT_STORAGE | convex |
NODE_ENV | production |
Overlays patch environment-specific values (e.g., LOG_LEVEL=debug in dev).
Deployment
The gateway deployment runs the shift-platform image with:
- 2 replicas (base, overridden per environment)
- Resource requests and limits
- Readiness probe on
/healthz - Environment variables from the ConfigMap and Secrets
Service
A ClusterIP service maps port 80 to the gateway's port 3000.
Ingress
Host-based routing directs traffic to the gateway service. Each overlay sets the appropriate hostname and ingress class.
Convex Backend
A self-hosted Convex instance runs alongside the gateway:
- Single replica deployment on port 3210
- Readiness probe on
/version - ClusterIP service exposing port 3210
- The gateway connects to it via the in-cluster URL:
http://convex-backend.shift-platform.svc.cluster.local:3210
Secrets
Sensitive values are stored in a Kubernetes secret (shift-platform-secrets) and injected as environment variables:
| Key | Description |
|---|---|
GOOGLE_CLIENT_ID | Google OAuth client ID |
GOOGLE_CLIENT_SECRET | Google OAuth client secret |
GOOGLE_CLI_CLIENT_ID | Google OAuth client ID (CLI) |
GOOGLE_CLI_CLIENT_SECRET | Google OAuth client secret (CLI) |
SESSION_SECRET | HMAC key for session cookies |
SHIFT_API_KEY | API key for scripts and agents |
In local dev, secrets are injected from Doppler. In staging and production, they are managed via the CI/CD pipeline.
Applying Manifests
# Dev overlay (kind)
kubectl apply -k k8s/overlays/dev/
# Staging overlay
kubectl apply -k k8s/overlays/staging/
# Production overlay
kubectl apply -k k8s/overlays/prod/