Kubernetes Deployment
This guide covers deploying Terragnos Core on Kubernetes, including configuration, scaling, and operational considerations.
Prerequisites
- Kubernetes cluster (1.24+)
kubectlconfigured to access your cluster- Container registry access (for pulling Terragnos images)
- PostgreSQL database (in-cluster or external)
Basic Deployment
Namespace
Create a namespace for Terragnos Core:
apiVersion: v1
kind: Namespace
metadata:
name: terragnos-core
Secrets
Create secrets for sensitive configuration:
apiVersion: v1
kind: Secret
metadata:
name: terragnos-secrets
namespace: terragnos-core
type: Opaque
stringData:
DATABASE_URL: postgres://user:password@db:5432/terragnos
AUTH_JWT_SECRET: your-jwt-secret-minimum-32-characters
LICENSE_KEY: eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...
LICENSE_PUBLIC_KEY: |
-----BEGIN PUBLIC KEY-----
...
-----END PUBLIC KEY-----
ConfigMap
Create a ConfigMap for non-sensitive configuration:
apiVersion: v1
kind: ConfigMap
metadata:
name: terragnos-config
namespace: terragnos-core
data:
PORT: "3000"
NODE_ENV: "production"
LOG_LEVEL: "info"
AUTH_DEFAULT_TENANT: "default"
RATE_LIMIT_TTL: "60"
RATE_LIMIT_LIMIT: "120"
LAYER_CACHE_TTL_SECONDS: "3600"
API Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: terragnos-api
namespace: terragnos-core
spec:
replicas: 3
selector:
matchLabels:
app: terragnos-api
template:
metadata:
labels:
app: terragnos-api
spec:
containers:
- name: api
image: terragnos/core-api:latest
ports:
- containerPort: 3000
envFrom:
- secretRef:
name: terragnos-secrets
- configMapRef:
name: terragnos-config
resources:
requests:
memory: "512Mi"
cpu: "500m"
limits:
memory: "2Gi"
cpu: "2000m"
livenessProbe:
httpGet:
path: /v1/health/live
port: 3000
initialDelaySeconds: 30
periodSeconds: 10
readinessProbe:
httpGet:
path: /v1/health/ready
port: 3000
initialDelaySeconds: 10
periodSeconds: 5
Worker Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: terragnos-worker
namespace: terragnos-core
spec:
replicas: 2
selector:
matchLabels:
app: terragnos-worker
template:
metadata:
labels:
app: terragnos-worker
spec:
containers:
- name: worker
image: terragnos/core-worker:latest
envFrom:
- secretRef:
name: terragnos-secrets
- configMapRef:
name: terragnos-config
resources:
requests:
memory: "512Mi"
cpu: "500m"
limits:
memory: "2Gi"
cpu: "2000m"
Service
Expose the API service:
apiVersion: v1
kind: Service
metadata:
name: terragnos-api
namespace: terragnos-core
spec:
selector:
app: terragnos-api
ports:
- port: 80
targetPort: 3000
type: ClusterIP
Ingress
Expose the API externally:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: terragnos-api
namespace: terragnos-core
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
ingressClassName: nginx
tls:
- hosts:
- api.terragnos.example.com
secretName: terragnos-api-tls
rules:
- host: api.terragnos.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: terragnos-api
port:
number: 80
Database Setup
Option 1: External Database
Use an external managed database (recommended for production):
# Update DATABASE_URL in secrets to point to external database
DATABASE_URL: postgres://user:password@external-db.example.com:5432/terragnos
Option 2: In-Cluster Database
Deploy PostgreSQL with PostGIS in the cluster:
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: postgres
namespace: terragnos-core
spec:
serviceName: postgres
replicas: 1
selector:
matchLabels:
app: postgres
template:
metadata:
labels:
app: postgres
spec:
containers:
- name: postgres
image: postgis/postgis:16-3.4
env:
- name: POSTGRES_DB
value: terragnos
- name: POSTGRES_USER
value: terragnos
- name: POSTGRES_PASSWORD
valueFrom:
secretKeyRef:
name: postgres-secret
key: password
volumeMounts:
- name: postgres-data
mountPath: /var/lib/postgresql/data
volumeClaimTemplates:
- metadata:
name: postgres-data
spec:
accessModes: [ "ReadWriteOnce" ]
resources:
requests:
storage: 100Gi
Database Migrations
Run migrations using a Job:
apiVersion: batch/v1
kind: Job
metadata:
name: terragnos-migrations
namespace: terragnos-core
spec:
template:
spec:
containers:
- name: db-setup
image: terragnos/core-db-setup:latest
envFrom:
- secretRef:
name: terragnos-secrets
restartPolicy: Never
backoffLimit: 3
Scaling
Horizontal Pod Autoscaling
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: terragnos-api-hpa
namespace: terragnos-core
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: terragnos-api
minReplicas: 3
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: 80
Manual Scaling
kubectl scale deployment terragnos-api --replicas=5 -n terragnos-core
Networking
Service Mesh
Terragnos Core works with service meshes (Istio, Linkerd):
- mTLS: Enable mutual TLS for service-to-service communication
- Traffic management: Use service mesh for advanced routing
- Observability: Leverage mesh telemetry
Network Policies
Restrict network access:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: terragnos-api-policy
namespace: terragnos-core
spec:
podSelector:
matchLabels:
app: terragnos-api
policyTypes:
- Ingress
- Egress
ingress:
- from:
- namespaceSelector:
matchLabels:
name: ingress-nginx
ports:
- protocol: TCP
port: 3000
egress:
- to:
- podSelector:
matchLabels:
app: postgres
ports:
- protocol: TCP
port: 5432
Monitoring
ServiceMonitor (Prometheus)
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: terragnos-api
namespace: terragnos-core
spec:
selector:
matchLabels:
app: terragnos-api
endpoints:
- port: http
path: /metrics
interval: 15s
Best Practices
- Use StatefulSets for databases – Ensures stable network identities
- Set resource limits – Prevent resource exhaustion
- Use health checks – Configure liveness and readiness probes
- Enable autoscaling – Scale based on CPU/memory usage
- Use secrets management – Store sensitive data in Kubernetes secrets
- Enable TLS – Use TLS for all external traffic
- Monitor everything – Set up Prometheus and Grafana
- Backup regularly – Automate database backups
- Use namespaces – Isolate Terragnos Core in its own namespace
- Update regularly – Keep container images updated