Overview

This guide walks you through deploying CaseBender on DigitalOcean using pre-built Docker images with Kubernetes (DOKS) and managed services.

Prerequisites

  1. DigitalOcean Account
  2. doctl CLI installed
  3. kubectl installed
  4. Docker installed

Step 1: Initial Setup

Install and Configure doctl

# Using Homebrew
brew install doctl

# Authenticate with API token

doctl auth init

# Configure Docker for Container Registry

doctl registry login

Step 2: Create Kubernetes Cluster

# Create DOKS cluster
doctl kubernetes cluster create casebender \
  --region nyc1 \
  --size s-2vcpu-4gb \
  --count 3 \
  --version latest

# Get kubeconfig
doctl kubernetes cluster kubeconfig save casebender

Step 3: Set Up Managed Services

Create Spaces for Object Storage

# Create Spaces bucket
doctl spaces create casebender-storage \
  --region nyc3

# Create Spaces access key
doctl spaces access-key create

# Note: Save the access key and secret key securely
# They will be needed for application configuration

Create Managed PostgreSQL

# Create database cluster
doctl databases create \
  --engine pg \
  --name casebender-db \
  --region nyc1 \
  --size db-s-2vcpu-4gb \
  --version 14 \
  --num-nodes 1

# Create database
doctl databases db create casebender-db casebender

# Get connection details
doctl databases connection casebender-db --format ConnectionString

Create Managed Redis

# Create Redis cluster
doctl databases create \
  --engine redis \
  --name casebender-redis \
  --region nyc1 \
  --size db-s-1vcpu-2gb \
  --version 7

# Get connection details
doctl databases connection casebender-redis --format ConnectionString

Step 4: Configure Container Registry

# Create container registry
doctl registry create casebender-registry

# Get registry endpoint
REGISTRY_ENDPOINT=$(doctl registry get-endpoint)

# Pull CaseBender images
docker pull casebender/casebender:latest
docker pull casebender/workflow-processor:latest
docker pull casebender/misp-processor:latest

# Tag images for registry
docker tag casebender/casebender:latest registry.digitalocean.com/casebender-registry/app:latest
docker tag casebender/workflow-processor:latest registry.digitalocean.com/casebender-registry/workflow-processor:latest
docker tag casebender/misp-processor:latest registry.digitalocean.com/casebender-registry/misp-processor:latest

# Push images
docker push registry.digitalocean.com/casebender-registry/app:latest
docker push registry.digitalocean.com/casebender-registry/workflow-processor:latest
docker push registry.digitalocean.com/casebender-registry/misp-processor:latest

# Add registry to Kubernetes cluster
doctl kubernetes cluster registry add casebender

Step 5: Deploy to Kubernetes

Create Namespace

kubectl create namespace casebender

Create Secrets

# Create secrets for database and Redis
kubectl create secret generic db-credentials \
  --namespace casebender \
  --from-literal=postgres-url="postgresql://doadmin:password@casebender-db-do-user-1234567-0.b.db.ondigitalocean.com:25060/casebender?sslmode=require" \
  --from-literal=redis-url="rediss://default:password@casebender-redis-do-user-1234567-0.b.db.ondigitalocean.com:25061"

# Create secrets for application
kubectl create secret generic app-secrets \
  --namespace casebender \
  --from-literal=auth-secret="your-auth-secret" \
  --from-literal=auth-salt="your-auth-salt"

Deploy Applications

Create deployment.yaml:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: casebender-app
  namespace: casebender
spec:
  replicas: 2
  selector:
    matchLabels:
      app: casebender-app
  template:
    metadata:
      labels:
        app: casebender-app
    spec:
      containers:
        - name: app
          image: registry.digitalocean.com/casebender-registry/app:latest
          ports:
            - containerPort: 3000
          env:
            - name: AUTH_SECRET
              valueFrom:
                secretKeyRef:
                  name: app-secrets
                  key: auth-secret
            - name: AUTH_SALT
              valueFrom:
                secretKeyRef:
                  name: app-secrets
                  key: auth-salt
            - name: POSTGRES_PRISMA_URL
              valueFrom:
                secretKeyRef:
                  name: db-credentials
                  key: postgres-url
            - name: REDIS_URL
              valueFrom:
                secretKeyRef:
                  name: db-credentials
                  key: redis-url
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: workflow-processor
  namespace: casebender
spec:
  replicas: 1
  selector:
    matchLabels:
      app: workflow-processor
  template:
    metadata:
      labels:
        app: workflow-processor
    spec:
      containers:
        - name: processor
          image: registry.digitalocean.com/casebender-registry/workflow-processor:latest
          env:
            - name: POSTGRES_PRISMA_URL
              valueFrom:
                secretKeyRef:
                  name: db-credentials
                  key: postgres-url
            - name: REDIS_URL
              valueFrom:
                secretKeyRef:
                  name: db-credentials
                  key: redis-url
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: misp-processor
  namespace: casebender
spec:
  replicas: 1
  selector:
    matchLabels:
      app: misp-processor
  template:
    metadata:
      labels:
        app: misp-processor
    spec:
      containers:
        - name: processor
          image: registry.digitalocean.com/casebender-registry/misp-processor:latest
          env:
            - name: POSTGRES_PRISMA_URL
              valueFrom:
                secretKeyRef:
                  name: db-credentials
                  key: postgres-url
            - name: REDIS_URL
              valueFrom:
                secretKeyRef:
                  name: db-credentials
                  key: redis-url

Apply the deployments:

kubectl apply -f deployment.yaml

Create Services

Create service.yaml:

apiVersion: v1
kind: Service
metadata:
  name: casebender-app
  namespace: casebender
spec:
  type: ClusterIP
  ports:
    - port: 80
      targetPort: 3000
  selector:
    app: casebender-app

Apply the service:

kubectl apply -f service.yaml

Step 7: Set Up Ingress

Install NGINX Ingress Controller

# Add Helm repository
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm repo update

# Install NGINX Ingress Controller
helm install nginx-ingress ingress-nginx/ingress-nginx \
  --namespace casebender \
  --set controller.publishService.enabled=true

Configure Ingress

Create ingress.yaml:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: casebender-ingress
  namespace: casebender
  annotations:
    kubernetes.io/ingress.class: nginx
    cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
  tls:
    - hosts:
        - your-domain.com
      secretName: casebender-tls
  rules:
    - host: your-domain.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: casebender-app
                port:
                  number: 80

Apply the ingress:

kubectl apply -f ingress.yaml

Step 8: Set Up SSL with cert-manager

# Install cert-manager
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.8.0/cert-manager.yaml

# Create ClusterIssuer
cat <<EOF | kubectl apply -f -
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt-prod
spec:
  acme:
    server: https://acme-v02.api.letsencrypt.org/directory
    email: your-email@domain.com
    privateKeySecretRef:
      name: letsencrypt-prod
    solvers:
    - http01:
        ingress:
          class: nginx
EOF

Monitoring and Maintenance

Set Up Monitoring

# Install metrics server
kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml

# Deploy Prometheus and Grafana
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
helm repo update

helm install prometheus prometheus-community/kube-prometheus-stack \
  --namespace monitoring \
  --create-namespace

Configure Horizontal Pod Autoscaling

Create hpa.yaml:

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: casebender-app-hpa
  namespace: casebender
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: casebender-app
  minReplicas: 2
  maxReplicas: 10
  metrics:
    - type: Resource
      resource:
        name: cpu
        target:
          type: Utilization
          averageUtilization: 80

Apply the HPA:

kubectl apply -f hpa.yaml

Backup and Disaster Recovery

Database Backups

DigitalOcean managed databases automatically handle backups. You can also:

# Create manual backup
doctl databases backup casebender-db

Configure Database Failover

# Enable automatic failover
doctl databases replica casebender-db create \
  --region sfo2

Security Best Practices

  1. Enable DigitalOcean Cloud Firewall
  2. Use private networking
  3. Implement network policies
  4. Regular security updates
  5. Enable audit logging

Cost Optimization

  1. Use appropriate node sizes
  2. Implement autoscaling
  3. Use block storage wisely
  4. Monitor resource usage
  5. Consider reserved droplets

Next Steps

  • Set up CI/CD pipeline
  • Configure monitoring alerts
  • Implement logging solution
  • Review security measures