Deployment Runbook
How to deploy the CRM & Marketing Platform to Kubernetes.
Prerequisites
- kubectl configured for target cluster
- Access to Harbor registry
- Infisical secrets configured
Kubernetes Resources
Deployments
| Deployment | Purpose | Replicas |
|---|---|---|
crm-backend | API server | 2 |
crm-worker | Background jobs | 2 |
Services
| Service | Port | Type |
|---|---|---|
crm-backend | 80 (→3000) | ClusterIP |
Ingress
| Host | Path | Backend |
|---|---|---|
crm-api.digiwedge.dev | / | crm-backend:80 |
Deployment Steps
1. Build and Push Image
# Build image
docker build -t harbor.digiwedge.dev/crm/backend:$VERSION apps/crm/crm-backend
# Push to registry
docker push harbor.digiwedge.dev/crm/backend:$VERSION
2. Run Database Migrations
# Apply migration job
kubectl apply -f k8s/migrate-job.yaml
# Wait for completion
kubectl wait --for=condition=complete job/crm-migrate -n crm --timeout=120s
# Check migration logs
kubectl logs job/crm-migrate -n crm
3. Deploy Application
# Update image
kubectl set image deployment/crm-backend \
crm-backend=harbor.digiwedge.dev/crm/backend:$VERSION -n crm
kubectl set image deployment/crm-worker \
crm-worker=harbor.digiwedge.dev/crm/backend:$VERSION -n crm
# Watch rollout
kubectl rollout status deployment/crm-backend -n crm
kubectl rollout status deployment/crm-worker -n crm
4. Verify Deployment
# Check pods are running
kubectl get pods -n crm
# Check health endpoint
curl https://crm-api.digiwedge.dev/health
# Check logs
kubectl logs -l app=crm-backend -n crm --tail=100
Rollback Procedure
# Rollback to previous version
kubectl rollout undo deployment/crm-backend -n crm
kubectl rollout undo deployment/crm-worker -n crm
# Or rollback to specific revision
kubectl rollout undo deployment/crm-backend --to-revision=N -n crm
Secrets Configuration
Secrets are managed via Infisical and synced using InfisicalSecret CRD.
Backend Secrets (/crm/backend)
| Secret | Purpose |
|---|---|
CRM_DATABASE_URL | PostgreSQL connection (SCL DB with ?schema=crm) |
REDIS_URL | Redis for BullMQ queues and caching |
AUTH_JWKS_URL | IDP JWKS endpoint for JWT verification |
AUTH_ISS | Expected JWT issuer |
AUTH_AUD | Expected JWT audience |
Events Worker Secrets (/crm/events-worker)
| Secret | Purpose |
|---|---|
CRM_DATABASE_URL | PostgreSQL connection |
REDIS_URL | Redis for BullMQ queues |
Social Secrets (/crm/social) - Future
| Secret | Purpose |
|---|---|
FACEBOOK_APP_ID | Facebook Graph API |
FACEBOOK_APP_SECRET | Facebook Graph API |
TWITTER_CLIENT_ID | Twitter/X API |
TWITTER_CLIENT_SECRET | Twitter/X API |
Note: CRM uses IDP JWKS authentication (AUTH_JWKS_URL/AUTH_ISS/AUTH_AUD), NOT symmetric JWT_SECRET.
Health Checks
| Endpoint | Purpose |
|---|---|
/health | Liveness probe |
/health/ready | Readiness probe |
/metrics | Prometheus metrics |
Troubleshooting
Pods not starting
# Check events
kubectl describe pod <pod-name> -n crm
# Check logs
kubectl logs <pod-name> -n crm --previous
Database connection issues
# Verify secret exists
kubectl get secret crm-secrets -n crm -o yaml
# Test connection from pod
kubectl exec -it <pod-name> -n crm -- \
psql $CRM_DATABASE_URL -c "SELECT 1"
Migration failed
# Check migration job logs
kubectl logs job/crm-migrate -n crm
# Reset and retry
kubectl delete job/crm-migrate -n crm
kubectl apply -f k8s/migrate-job.yaml