Table of Contents

Kubernetes Deployment Guide
Production Scalability with Kubernetes


Overview

SWIRL can be deployed on Kubernetes for production scalability. The platform is containerized and ready for cloud-native deployments across on-premises and cloud environments (AWS, Azure, GCP). The swirl-infra/ directory in the repository contains example manifests for rapid deployment.

Kubernetes deployments provide:

  • Auto-scaling based on CPU and memory usage
  • High availability with multiple pod replicas
  • Service discovery for inter-pod communication
  • Rolling updates with zero downtime
  • Persistent volumes for databases and uploads
  • Health monitoring with liveness and readiness probes

Prerequisites

Before deploying SWIRL on Kubernetes, ensure you have:

  • Kubernetes cluster version 1.27 or higher
  • kubectl configured to access your cluster
  • PostgreSQL database (managed service or in-cluster)
  • Redis instance (managed service or in-cluster)
  • Container registry access to SWIRL Enterprise images
  • TLS certificates (for production ingress via cert-manager and Let's Encrypt)
  • Sufficient cluster resources: Minimum 16 CPU and 32 GB RAM
  • Persistent volumes provisioner available in cluster
  • Ingress controller installed (nginx-ingress or cloud provider default)

SWIRL Enterprise License Required
The Kubernetes deployment uses SWIRL Enterprise container images. You must have a valid SWIRL license and container registry credentials.

Architecture

The SWIRL Kubernetes architecture consists of the following pods and services:

SWIRL Application Pod

The primary Django application container with integrated Celery workers:

  • Runs Django web server on port 8000
  • Includes 5 Celery worker processes for async task execution
  • Uses PostgreSQL for data persistence
  • Uses Redis for message broker and caching
  • Resource allocation: 8 CPU cores, 10 GB memory (production minimum)

Redis Pod

Message broker and caching layer:

  • Port: 6379
  • Use: Celery task queue, session storage, caching
  • Resource allocation: 2 CPU cores, 4 GB memory

Tika Pod

Document text extraction service:

  • Port: 9998
  • Image: apache/tika:latest
  • Use: OCR and text extraction from PDF, Office documents, and images
  • Resource allocation: 4 CPU cores, 8 GB memory

Topic Text Matcher Pod

Passage detection and semantic matching for RAG:

  • Port: 7029
  • Image: swirlai/swirl-integrations:topic-text-matcher
  • Use: Identifies relevant passages in document collections for RAG workflows
  • Resource allocation: 8 CPU cores, 10 GB memory

PostgreSQL

Relational database for SWIRL metadata:

  • Deployment: External managed service (recommended for production) or in-cluster StatefulSet
  • Port: 5432
  • Databases required: Create swirl database before deployment
  • Backups: Essential for production workloads

Configuration

SWIRL Kubernetes deployments use a ConfigMap to manage environment variables. Key configuration settings:

Host and Protocol

ALLOWED_HOSTS: "*.example.com,swirl.example.com"
PROTOCOL: "https"  # Always use https in production
DEBUG: "False"
SECRET_KEY: "<generate-strong-secret>"

Database Configuration

SQL_ENGINE: "django.db.backends.postgresql"
SQL_DATABASE: "swirl"
SQL_USER: "swirl"
SQL_PASSWORD: "<secure-password>"  # Store in Secret, not ConfigMap
SQL_HOST: "postgres.default.svc.cluster.local"
SQL_PORT: "5432"

Celery and Messaging

CELERY_BROKER_URL: "redis://redis:6379/0"
CELERY_RESULT_BACKEND: "redis://redis:6379/1"

External Services

TIKA_SERVER_ENDPOINT: "http://tika:9998"
SWIRL_TEXT_SUMMARIZATION_URL: "http://topic-text-matcher:7029"

SWIRL Features

SWIRL_LICENSE: "<your-enterprise-license>"
SWIRL_EXPLAIN: "True"

Store sensitive data (passwords, tokens) in Kubernetes Secrets:

kubectl create secret generic swirl-secrets \
  --from-literal=sql_password=<password> \
  --from-literal=secret_key=<generated-key> \
  -n swirl

Deployment Steps

1. Create Namespace

kubectl create namespace swirl

2. Store Secrets

kubectl create secret generic swirl-secrets \
  --from-literal=sql_password=<your-password> \
  --from-literal=secret_key=<your-secret-key> \
  -n swirl

kubectl create secret docker-registry swirl-registry \
  --docker-server=<registry-url> \
  --docker-username=<username> \
  --docker-password=<password> \
  -n swirl

3. Apply Manifests

Deploy Redis, PostgreSQL (if in-cluster), Tika, and Topic Text Matcher services:

kubectl apply -f redis-deployment.yaml -n swirl
kubectl apply -f tika-deployment.yaml -n swirl
kubectl apply -f topic-text-matcher-deployment.yaml -n swirl

If using an in-cluster PostgreSQL:

kubectl apply -f postgres-deployment.yaml -n swirl

4. Apply SWIRL Deployment

kubectl apply -f swirl-deployment.yaml -n swirl

5. Verify Pods Are Running

kubectl get pods -n swirl
kubectl logs -f deployment/swirl -n swirl

6. Run Database Migrations

SWIRL includes an init container that automatically runs migrations on startup:

kubectl logs -f deployment/swirl -n swirl | grep -i "migration\|completed"

Or manually run migrations:

kubectl exec -it deployment/swirl -n swirl -- python manage.py migrate

7. Verify Health

kubectl logs -f deployment/swirl -n swirl | grep -i "health\|ready"

Ingress and TLS

Install cert-manager

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

Create ClusterIssuer for Let's Encrypt

apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt-prod
spec:
  acme:
    server: https://acme-v02.api.letsencrypt.org/directory
    email: admin@example.com
    privateKeySecretRef:
      name: letsencrypt-prod
    solvers:
    - http01:
        ingress:
          class: nginx

Apply the issuer:

kubectl apply -f cluster-issuer.yaml

Create Ingress with TLS

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: swirl-ingress
  namespace: swirl
  annotations:
    cert-manager.io/cluster-issuer: "letsencrypt-prod"
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  ingressClassName: nginx
  tls:
  - hosts:
    - swirl.example.com
    secretName: swirl-tls
  rules:
  - host: swirl.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: swirl
            port:
              number: 8000

Apply the ingress:

kubectl apply -f swirl-ingress.yaml -n swirl

Verify TLS certificate:

kubectl get certificate -n swirl
kubectl describe certificate swirl-tls -n swirl

Scaling

Horizontal Pod Autoscaling

Create an HorizontalPodAutoscaler to scale SWIRL replicas based on resource usage:

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: swirl-hpa
  namespace: swirl
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: swirl
  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

Apply the HPA:

kubectl apply -f swirl-hpa.yaml -n swirl

Monitor HPA status:

kubectl get hpa -n swirl -w

Resource Limits and Requests

Each SWIRL pod requires:

resources:
  requests:
    cpu: "4"
    memory: "6Gi"
  limits:
    cpu: "8"
    memory: "10Gi"

Tika pod requires:

resources:
  requests:
    cpu: "2"
    memory: "4Gi"
  limits:
    cpu: "4"
    memory: "8Gi"

Topic Text Matcher pod requires:

resources:
  requests:
    cpu: "4"
    memory: "6Gi"
  limits:
    cpu: "8"
    memory: "10Gi"

Node Autoscaling

Enable Cluster Autoscaler on your cloud provider:

AWS (EKS):

# Enable autoscaling on your node group
aws eks update-nodegroup-config \
  --cluster-name <cluster-name> \
  --nodegroup-name <nodegroup-name> \
  --scaling-config minSize=3,maxSize=20,desiredSize=5

Azure (AKS):

# Enable autoscaling on node pool
az aks nodepool update \
  --cluster-name <cluster-name> \
  --name <nodepool-name> \
  --enable-cluster-autoscaler \
  --min-count 3 \
  --max-count 20

GCP (GKE):

# Update node pool with autoscaling
gcloud container node-pools update <nodepool-name> \
  --cluster <cluster-name> \
  --enable-autoscaling \
  --min-nodes 3 \
  --max-nodes 20

Health Checks

SWIRL includes health check endpoints for Kubernetes probes.

Readiness Probe

readinessProbe:
  httpGet:
    path: /health/celery/
    port: 8000
  initialDelaySeconds: 30
  periodSeconds: 10
  timeoutSeconds: 5
  failureThreshold: 3

Liveness Probe

livenessProbe:
  httpGet:
    path: /health/celery/
    port: 8000
  initialDelaySeconds: 60
  periodSeconds: 30
  timeoutSeconds: 5
  failureThreshold: 3

Check probe status:

kubectl describe pod <pod-name> -n swirl | grep -A 10 "Readiness\|Liveness"

Supporting Services

Apache Tika

Tika is required for document text extraction and OCR.

Deployment manifest snippet:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: tika
  namespace: swirl
spec:
  replicas: 1
  selector:
    matchLabels:
      app: tika
  template:
    metadata:
      labels:
        app: tika
    spec:
      containers:
      - name: tika
        image: apache/tika:latest
        ports:
        - containerPort: 9998
        resources:
          requests:
            cpu: "2"
            memory: "4Gi"
          limits:
            cpu: "4"
            memory: "8Gi"
        livenessProbe:
          httpGet:
            path: /tika
            port: 9998
          initialDelaySeconds: 30
          periodSeconds: 30

Topic Text Matcher

Topic Text Matcher provides semantic passage detection for RAG workflows.

Deployment manifest snippet:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: topic-text-matcher
  namespace: swirl
spec:
  replicas: 1
  selector:
    matchLabels:
      app: topic-text-matcher
  template:
    metadata:
      labels:
        app: topic-text-matcher
    spec:
      containers:
      - name: topic-text-matcher
        image: swirlai/swirl-integrations:topic-text-matcher
        ports:
        - containerPort: 7029
        resources:
          requests:
            cpu: "4"
            memory: "6Gi"
          limits:
            cpu: "8"
            memory: "10Gi"
        env:
        - name: PORT
          value: "7029"
        livenessProbe:
          httpGet:
            path: /health
            port: 7029
          initialDelaySeconds: 60
          periodSeconds: 30

Azure-Specific Notes

AKS Node Pool Configuration

For Azure Kubernetes Service (AKS), create appropriately sized node pools:

# Create a node pool for SWIRL workloads
az aks nodepool add \
  --cluster-name <cluster-name> \
  --name swirl-pool \
  --vm-set-type VirtualMachineScaleSets \
  --node-vm-size Standard_D8s_v3 \
  --node-count 3 \
  --enable-cluster-autoscaler \
  --min-count 3 \
  --max-count 20 \
  --resource-group <resource-group>

Azure File Share for Uploads

Configure Azure File Share for persistent uploads storage:

apiVersion: v1
kind: PersistentVolume
metadata:
  name: swirl-uploads-pv
  namespace: swirl
spec:
  capacity:
    storage: 500Gi
  accessModes:
    - ReadWriteMany
  azureFile:
    secretName: azure-storage-secret
    shareName: swirl-uploads
    readOnly: false
  storageClassName: azurefile

---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: swirl-uploads-pvc
  namespace: swirl
spec:
  accessModes:
    - ReadWriteMany
  storageClassName: azurefile
  resources:
    requests:
      storage: 500Gi

Create the storage secret:

kubectl create secret generic azure-storage-secret \
  --from-literal=azurestorageaccountname=<account-name> \
  --from-literal=azurestorageaccountkey=<account-key> \
  -n swirl

Mount the share in the SWIRL deployment:

volumes:
- name: uploads
  azureFile:
    secretName: azure-storage-secret
    shareName: swirl-uploads
    readOnly: false

Monitoring and Logging

View Logs

# View SWIRL application logs
kubectl logs -f deployment/swirl -n swirl

# View Redis logs
kubectl logs -f deployment/redis -n swirl

# View Tika logs
kubectl logs -f deployment/tika -n swirl

# View Topic Text Matcher logs
kubectl logs -f deployment/topic-text-matcher -n swirl

Check Pod Status

# List all SWIRL pods
kubectl get pods -n swirl -o wide

# Describe a specific pod for events and status
kubectl describe pod <pod-name> -n swirl

# Watch pod status changes
kubectl get pods -n swirl -w

Access SWIRL

Once the ingress is active with TLS certificates issued:

# Check ingress status
kubectl get ingress -n swirl

# Get the external IP or hostname
kubectl get ingress swirl-ingress -n swirl -o wide

Visit: https://swirl.example.com

Troubleshooting

Pod Not Starting

# Check pod events
kubectl describe pod <pod-name> -n swirl

# Check logs
kubectl logs <pod-name> -n swirl

# Check resource availability
kubectl describe nodes

Database Connection Issues

# Verify PostgreSQL is accessible
kubectl run -it --rm debug --image=postgres:15 --restart=Never -- \
  psql -h postgres.default.svc.cluster.local -U swirl -d swirl

# Test from within SWIRL pod
kubectl exec -it deployment/swirl -n swirl -- \
  python manage.py dbshell

Redis Connection Issues

# Test Redis connectivity
kubectl run -it --rm debug --image=redis:latest --restart=Never -- \
  redis-cli -h redis:6379 ping

# Check Redis info
kubectl exec -it deployment/redis -n swirl -- \
  redis-cli info

Celery Workers Not Processing Tasks

# Check Celery worker status
kubectl exec -it deployment/swirl -n swirl -- \
  celery -A swirl_server inspect active

# View Celery logs
kubectl logs -f deployment/swirl -n swirl | grep -i celery

For additional support, refer to the SWIRL documentation or contact your SWIRL Enterprise support team.