Operations Deployment Kubernetes - osama1998H/Moca GitHub Wiki
Kubernetes Deployment
Deploy Moca on Kubernetes for cloud-native, horizontally scalable workloads. The moca generate k8s command produces all required manifests.
Prerequisites
- Kubernetes 1.28+
kubectlconfigured against your target cluster- Moca CLI installed locally
- Container images available (pre-built from
ghcr.ioor locally built)
Step 1: Generate Manifests
Run the generator from your project root:
moca generate k8s
This produces a k8s/ directory with the following manifests:
| Manifest | Purpose |
|---|---|
namespace.yaml |
Dedicated namespace for Moca resources |
configmap.yaml |
Non-secret configuration (domain, feature flags) |
secret.yaml |
Database password, Redis password, Meilisearch API key, secret key |
deployment-server.yaml |
moca-server Deployment + Service |
deployment-worker.yaml |
moca-worker Deployment |
deployment-scheduler.yaml |
moca-scheduler Deployment (single replica) |
deployment-outbox.yaml |
moca-outbox Deployment (single replica) |
Step 2: Configure Secrets
The generated secret.yaml uses placeholder values. Replace them with your base64-encoded secrets before applying:
echo -n "your-db-password" | base64
echo -n "your-redis-password" | base64
echo -n "your-meili-api-key" | base64
echo -n "your-secret-key" | base64
For production, prefer an external secrets manager instead of storing secrets in-cluster:
- External Secrets Operator — sync from AWS Secrets Manager, Vault, GCP Secret Manager
- Sealed Secrets — encrypt secrets that are safe to commit to Git
Step 3: Apply Manifests
Apply the manifests in order:
kubectl apply -f k8s/namespace.yaml
kubectl apply -f k8s/configmap.yaml
kubectl apply -f k8s/secret.yaml
kubectl apply -f k8s/deployment-server.yaml
kubectl apply -f k8s/deployment-worker.yaml
kubectl apply -f k8s/deployment-scheduler.yaml
kubectl apply -f k8s/deployment-outbox.yaml
Step 4: Verify
Check that all pods are running:
kubectl get pods -n moca
Inspect server logs:
kubectl logs -n moca -l app=moca-server --tail=50
Ingress Configuration
The generator produces a basic Ingress. For TLS with cert-manager, annotate the Ingress resource:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: moca-ingress
namespace: moca
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
tls:
- hosts:
- mysite.example.com
secretName: moca-tls
rules:
- host: mysite.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: moca-server
port:
number: 8000
HPA Tuning
Horizontal Pod Autoscaler configuration for CPU and memory-based scaling:
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: moca-server-hpa
namespace: moca
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: moca-server
minReplicas: 2
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: 80
Recommended scaling bounds per process:
| Process | Min Replicas | Max Replicas | Notes |
|---|---|---|---|
| moca-server | 2 | 10 | Scale on CPU + memory |
| moca-worker | 1 | 5 | Scale on queue depth (KEDA recommended) |
| moca-scheduler | 1 | 1 | Leader election enforces single active instance |
| moca-outbox | 1 | 1 | Single instance per site |
Multi-Tenant Considerations
- Use a dedicated namespace per environment (e.g.,
moca-staging,moca-production). - PostgreSQL schema-per-tenant isolation is enforced at the application level — all tenants share the same database pods.
- For high tenant counts (1 000+), use Meilisearch tenant tokens instead of per-tenant indexes to reduce index overhead. See ADR-006.
Database
For production, run PostgreSQL outside the cluster (managed services recommended):
- AWS RDS for PostgreSQL / Aurora PostgreSQL
- Google Cloud SQL for PostgreSQL
- Azure Database for PostgreSQL
Running stateful workloads inside Kubernetes adds operational complexity (volume management, failover, backups) that managed services handle automatically. Store the connection string in the Kubernetes Secret generated by moca generate k8s.