Skip to content

Production Deployment

This guide covers deploying KubeOrch in a production environment.

  • Docker and Docker Compose v2+
  • A domain name (optional but recommended)
  • TLS certificate (Let’s Encrypt or similar)
  • MongoDB 6.0+ instance (or use the bundled container)
Section titled “Option 1: Docker Compose (Recommended for Small Teams)”
Terminal window
cat > .env <<EOF
# Core Backend
GIN_MODE=release
PORT=8080
MONGO_URI=mongodb://mongo:27017/kubeorch
JWT_SECRET=$(openssl rand -hex 32)
ENCRYPTION_KEY=$(openssl rand -hex 16)
TOKEN_TTL=24h
# Frontend
NEXT_PUBLIC_API_URL=https://your-domain.com/api
# MongoDB
MONGO_INITDB_DATABASE=kubeorch
EOF
docker-compose.production.yml
services:
core:
image: ghcr.io/kubeorch/core:latest
restart: unless-stopped
env_file: .env
ports:
- "8080:8080"
depends_on:
mongo:
condition: service_healthy
healthcheck:
test: ["CMD", "wget", "--spider", "-q", "http://localhost:8080/health"]
interval: 30s
timeout: 5s
retries: 3
ui:
image: ghcr.io/kubeorch/ui:latest
restart: unless-stopped
environment:
- NEXT_PUBLIC_API_URL=https://your-domain.com/api
ports:
- "3000:3000"
depends_on:
- core
mongo:
image: mongo:7
restart: unless-stopped
volumes:
- mongo_data:/data/db
healthcheck:
test: ["CMD", "mongosh", "--eval", "db.adminCommand('ping')"]
interval: 10s
timeout: 5s
retries: 5
volumes:
mongo_data:
Terminal window
docker compose -f docker-compose.production.yml up -d
Terminal window
# Check all services are running
docker compose -f docker-compose.production.yml ps
# Check core health
curl http://localhost:8080/health
Terminal window
kubectl create namespace kubeorch
Terminal window
kubectl create secret generic kubeorch-secrets \
--namespace kubeorch \
--from-literal=jwt-secret=$(openssl rand -hex 32) \
--from-literal=encryption-key=$(openssl rand -hex 16) \
--from-literal=mongo-uri=mongodb://mongo:27017/kubeorch
mongo.yaml
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: mongo
namespace: kubeorch
spec:
serviceName: mongo
replicas: 1
selector:
matchLabels:
app: mongo
template:
metadata:
labels:
app: mongo
spec:
containers:
- name: mongo
image: mongo:7
ports:
- containerPort: 27017
volumeMounts:
- name: data
mountPath: /data/db
volumeClaimTemplates:
- metadata:
name: data
spec:
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 10Gi
---
apiVersion: v1
kind: Service
metadata:
name: mongo
namespace: kubeorch
spec:
selector:
app: mongo
ports:
- port: 27017
core.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: core
namespace: kubeorch
spec:
replicas: 1
selector:
matchLabels:
app: core
template:
metadata:
labels:
app: core
spec:
containers:
- name: core
image: ghcr.io/kubeorch/core:latest
ports:
- containerPort: 8080
env:
- name: GIN_MODE
value: release
- name: PORT
value: "8080"
- name: MONGO_URI
valueFrom:
secretKeyRef:
name: kubeorch-secrets
key: mongo-uri
- name: JWT_SECRET
valueFrom:
secretKeyRef:
name: kubeorch-secrets
key: jwt-secret
- name: ENCRYPTION_KEY
valueFrom:
secretKeyRef:
name: kubeorch-secrets
key: encryption-key
livenessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 10
periodSeconds: 30
readinessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 5
periodSeconds: 10
---
apiVersion: v1
kind: Service
metadata:
name: core
namespace: kubeorch
spec:
selector:
app: core
ports:
- port: 8080
ui.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: ui
namespace: kubeorch
spec:
replicas: 1
selector:
matchLabels:
app: ui
template:
metadata:
labels:
app: ui
spec:
containers:
- name: ui
image: ghcr.io/kubeorch/ui:latest
ports:
- containerPort: 3000
env:
- name: NEXT_PUBLIC_API_URL
value: https://your-domain.com/api
---
apiVersion: v1
kind: Service
metadata:
name: ui
namespace: kubeorch
spec:
selector:
app: ui
ports:
- port: 3000
ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: kubeorch
namespace: kubeorch
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
tls:
- hosts:
- your-domain.com
secretName: kubeorch-tls
rules:
- host: your-domain.com
http:
paths:
- path: /v1
pathType: Prefix
backend:
service:
name: core
port:
number: 8080
- path: /
pathType: Prefix
backend:
service:
name: ui
port:
number: 3000
Terminal window
kubectl apply -f mongo.yaml
kubectl apply -f core.yaml
kubectl apply -f ui.yaml
kubectl apply -f ingress.yaml

Add an nginx service to your compose file:

nginx:
image: nginx:alpine
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
- ./certs:/etc/nginx/certs:ro
depends_on:
- core
- ui

Use cert-manager for automatic TLS:

Terminal window
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/latest/download/cert-manager.yaml

Then create a ClusterIssuer for Let’s Encrypt and reference it in the Ingress annotation as shown above.

Terminal window
# Docker Compose
docker compose exec mongo mongodump --out /data/backup
docker compose cp mongo:/data/backup ./backup-$(date +%Y%m%d)
# Kubernetes
kubectl exec -n kubeorch mongo-0 -- mongodump --out /data/backup
kubectl cp kubeorch/mongo-0:/data/backup ./backup-$(date +%Y%m%d)
Terminal window
# Docker Compose
docker compose cp ./backup mongo:/data/backup
docker compose exec mongo mongorestore /data/backup
# Kubernetes
kubectl cp ./backup kubeorch/mongo-0:/data/backup
kubectl exec -n kubeorch mongo-0 -- mongorestore /data/backup

For production, schedule regular backups using a CronJob:

apiVersion: batch/v1
kind: CronJob
metadata:
name: mongo-backup
namespace: kubeorch
spec:
schedule: "0 2 * * *" # Daily at 2 AM
jobTemplate:
spec:
template:
spec:
containers:
- name: backup
image: mongo:7
command:
- mongodump
- --uri=mongodb://mongo:27017/kubeorch
- --out=/backup/$(date +\%Y\%m\%d)
volumeMounts:
- name: backup
mountPath: /backup
volumes:
- name: backup
persistentVolumeClaim:
claimName: backup-pvc
restartPolicy: OnFailure

See the Configuration page for all available environment variables.