Deploy the Credence Backend to a Kubernetes cluster.
- Kubernetes cluster (1.24+)
kubectlconfigured for your cluster- Container image pushed to a registry (default:
ghcr.io/credenceorg/credence-backend:latest)
# 1. Apply all manifests at once via Kustomize
kubectl apply -k k8s/
# 2. Check rollout status
kubectl rollout status deployment/credence-backend -n credence
# 3. Verify pods are running
kubectl get pods -n credence| File | Kind | Description |
|---|---|---|
k8s/namespace.yaml |
Namespace | credence namespace for all resources |
k8s/configmap.yaml |
ConfigMap | Non-secret config (PORT, NODE_ENV, DATABASE_URL, REDIS_URL) |
k8s/secret.yaml |
Secret | Placeholder for sensitive values (passwords, API keys) |
k8s/deployment.yaml |
Deployment | 2-replica deployment with resource limits and health probes |
k8s/service.yaml |
Service | ClusterIP service exposing port 80 → container port 3000 |
k8s/kustomization.yaml |
Kustomization | Applies all resources in the correct order |
Edit k8s/configmap.yaml or override at apply time:
| Key | Default | Description |
|---|---|---|
PORT |
3000 |
Express server port |
NODE_ENV |
production |
Node environment |
DATABASE_URL |
postgresql://credence:CHANGEME@postgres:5432/credence |
PostgreSQL connection string |
REDIS_URL |
redis://redis:6379 |
Redis connection string |
LOG_LEVEL |
info |
Application log level |
SHUTDOWN_GRACE_PERIOD_MS |
30000 |
Time in milliseconds to wait for graceful shutdown before forcing exit |
RATE_LIMIT_ENABLED |
true |
Enable or disable rate limiting |
RATE_LIMIT_WINDOW_SEC |
60 |
Fixed-window size in seconds |
RATE_LIMIT_MAX_FREE |
100 |
Max requests per window for Free tier |
RATE_LIMIT_MAX_PRO |
1000 |
Max requests per window for Pro tier |
RATE_LIMIT_MAX_ENTERPRISE |
10000 |
Max requests per window for Enterprise tier |
RATE_LIMIT_FAIL_OPEN |
false |
Fail-open behavior on Redis failure |
Do not commit real secrets. Create them manually:
kubectl create secret generic credence-backend-secret \
--from-literal=DATABASE_PASSWORD=<real-password> \
--from-literal=API_KEY=<real-api-key> \
-n credenceOr use a secrets manager (HashiCorp Vault, AWS Secrets Manager, etc.).
The deployment uses the existing health endpoints:
| Probe | Endpoint | Purpose |
|---|---|---|
| Liveness | GET /api/health/live |
Restart pod if process hangs |
| Readiness | GET /api/health/ready |
Remove from Service if dependencies are down or during shutdown |
| Startup | GET /api/health/live |
Allow time for container startup |
The application now handles SIGTERM and SIGINT by:
- stopping the HTTP server from accepting new requests
- marking readiness false so Kubernetes stops routing traffic
- stopping listeners and workers
- waiting up to
SHUTDOWN_GRACE_PERIOD_MSbefore force exiting
Make sure terminationGracePeriodSeconds in k8s/deployment.yaml exceeds SHUTDOWN_GRACE_PERIOD_MS so pods can shut down cleanly.
# Manual scaling
kubectl scale deployment/credence-backend --replicas=4 -n credence
# Or use a HorizontalPodAutoscaler
kubectl autoscale deployment/credence-backend \
--min=2 --max=10 --cpu-percent=70 -n credence| CPU | Memory | |
|---|---|---|
| Request | 100m | 128Mi |
| Limit | 500m | 512Mi |
Adjust in k8s/deployment.yaml based on observed usage.
The default Service type is ClusterIP (internal only). Options for external access:
# In k8s/service.yaml, change:
spec:
type: LoadBalancerapiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: credence-backend
namespace: credence
spec:
rules:
- host: api.credence.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: credence-backend
port:
name: httpkubectl set image deployment/credence-backend \
credence-backend=ghcr.io/credenceorg/credence-backend:v1.2.3 \
-n credenceFor the full cutover sequence — health-gate thresholds, how to tell a stalled rollout from a healthy one, and how/when to trigger a rollback — see docs/deployment-cutover.md.
kubectl delete -k k8s/