Skip to content

Kubernetes Deployment Guide

This guide explains how to deploy Cesivi Server to a Kubernetes cluster using raw Kubernetes manifests.

For Helm chart deployment (recommended), see HELM_CHART_GUIDE.md

Table of Contents

Prerequisites

Required

  • Kubernetes cluster (v1.24+)
  • Local: minikube, kind, Docker Desktop
  • Cloud: AKS, EKS, GKE
  • kubectl (v1.24+) configured to access your cluster
  • Container runtime supporting OCI images
  • Storage provider with PersistentVolume support
  • nginx-ingress controller for ingress support
  • cert-manager for automatic TLS certificate management
  • Prometheus Operator for metrics collection
  • Jaeger for distributed tracing

Verify Prerequisites

# Check Kubernetes version
kubectl version --short

# Check cluster access
kubectl cluster-info

# Check available storage classes
kubectl get storageclass

# Check if nginx-ingress is installed
kubectl get pods -n ingress-nginx

# Check if cert-manager is installed
kubectl get pods -n cert-manager

Quick Start

1. Deploy All Resources

# Clone repository
git clone https://github.com/your-org/cesivi.git
cd cesivi

# Deploy everything
kubectl apply -f k8s/

# Wait for deployment to complete
kubectl wait --for=condition=available --timeout=300s \
  deployment/cesivi -n cesivi

2. Verify Deployment

# Check pod status
kubectl get pods -n cesivi

# Check all resources
kubectl get all -n cesivi

3. Access the Application

# Port-forward for local access
kubectl port-forward -n cesivi svc/cesivi 8080:80

# Open browser
open http://localhost:8080

# Or use ingress (if configured)
# https://cesivi.example.com

Architecture Overview

Deployment Architecture

┌─────────────────────────────────────────────────────────┐
│ Kubernetes Cluster                                      │
├─────────────────────────────────────────────────────────┤
│                                                          │
│  ┌──────────────────────────────────────────────────┐  │
│  │ Ingress Controller (nginx-ingress)               │  │
│  │ - TLS termination                                │  │
│  │ - Load balancing                                 │  │
│  └────────────────┬─────────────────────────────────┘  │
│                   │                                      │
│  ┌────────────────▼─────────────────────────────────┐  │
│  │ Service: cesivi (ClusterIP)             │  │
│  └────────────────┬─────────────────────────────────┘  │
│                   │                                      │
│     ┌─────────────┴──────────────┬──────────────┐      │
│     │                            │              │      │
│  ┌──▼───┐  ┌────────┐  ┌────────▼┐  ┌─────────▼┐     │
│  │ SPM  │  │  SPM   │  │   SPM   │  │   SPM    │     │
│  │ Pod1 │  │  Pod2  │  │   Pod3  │  │   ...    │     │
│  └──┬───┘  └────┬───┘  └────┬────┘  └─────┬────┘     │
│     │           │           │             │          │
│     └───────────┴───────────┴─────────────┘          │
│                   │                                      │
│  ┌────────────────▼─────────────────────────────────┐  │
│  │ Redis StatefulSet                                │  │
│  │ - Session state                                  │  │
│  │ - Cache                                          │  │
│  └──────────────────────────────────────────────────┘  │
│                                                          │
│  ┌──────────────────────────────────────────────────┐  │
│  │ PostgreSQL StatefulSet                           │  │
│  │ - Persistent storage                             │  │
│  └──────────────────────────────────────────────────┘  │
│                                                          │
└─────────────────────────────────────────────────────────┘

Component Overview

Component Type Replicas Purpose
Cesivi Server Deployment 3+ Main application
Redis StatefulSet 1 Session state & cache
PostgreSQL StatefulSet 1 Data persistence
Service ClusterIP 1 Internal load balancing
Ingress Ingress 1 External access & TLS
HPA HorizontalPodAutoscaler 1 Auto-scaling
PDB PodDisruptionBudget 1 High availability

Deployment Steps

Step 1: Create Namespace

kubectl apply -f k8s/namespace.yaml

Verify:

kubectl get namespace cesivi

Step 2: Configure Secrets

IMPORTANT: Update passwords before deploying!

Edit k8s/secret.yaml and replace default passwords:

stringData:
  REDIS_CONNECTION: "redis:6379,abortConnect=false"
  SQL_CONNECTION: "Server=sqlserver;Database=Cesivi;User Id=sa;Password=YOUR_SECURE_PASSWORD;TrustServerCertificate=True"

Apply:

kubectl apply -f k8s/secret.yaml

Verify:

kubectl get secret spm-secrets -n cesivi

Alternative: Create secret via kubectl

kubectl create secret generic spm-secrets \
  --from-literal=REDIS_CONNECTION="redis:6379,abortConnect=false" \
  --from-literal=SQL_CONNECTION="Server=sqlserver;Database=Cesivi;User Id=sa;Password=YourStrong@Passw0rd;TrustServerCertificate=True" \
  -n cesivi

Step 3: Create Configuration

kubectl apply -f k8s/configmap.yaml

Verify:

kubectl get configmap cesivi-config -n cesivi
kubectl describe configmap cesivi-config -n cesivi

Step 4: Deploy Redis

kubectl apply -f k8s/redis-deployment.yaml
kubectl apply -f k8s/redis-service.yaml

Wait for Redis to be ready:

kubectl wait --for=condition=ready pod \
  -l app.kubernetes.io/name=redis \
  -n cesivi \
  --timeout=300s

Verify:

kubectl get pods -n cesivi -l app.kubernetes.io/name=redis
kubectl get svc -n cesivi -l app.kubernetes.io/name=redis

Step 5: Deploy SQL Server (Optional)

For production, use external managed database instead!

# Update secret with SQL Server SA password
kubectl create secret generic spm-secrets \
  --from-literal=SQL_SA_PASSWORD="YourStrong@Passw0rd" \
  --dry-run=client -o yaml | kubectl apply -f -

# Deploy SQL Server
kubectl apply -f k8s/sqlserver-deployment.yaml

Wait for SQL Server to be ready:

kubectl wait --for=condition=ready pod \
  -l app.kubernetes.io/name=sqlserver \
  -n cesivi \
  --timeout=600s  # SQL Server takes longer to start

Step 6: Deploy Cesivi Server

kubectl apply -f k8s/deployment.yaml
kubectl apply -f k8s/service.yaml

Wait for deployment:

kubectl wait --for=condition=available \
  deployment/cesivi \
  -n cesivi \
  --timeout=300s

Verify:

kubectl get deployments -n cesivi
kubectl get pods -n cesivi
kubectl get svc -n cesivi

Step 7: Configure Ingress

Edit k8s/ingress.yaml to set your hostname:

spec:
  tls:
  - hosts:
    - your-domain.com  # Change this
    secretName: cesivi-tls
  rules:
  - host: your-domain.com  # Change this

Apply:

kubectl apply -f k8s/ingress.yaml

Verify:

kubectl get ingress -n cesivi
kubectl describe ingress cesivi -n cesivi

Step 8: Enable Auto-Scaling

kubectl apply -f k8s/hpa.yaml
kubectl apply -f k8s/pdb.yaml

Verify:

kubectl get hpa -n cesivi
kubectl get pdb -n cesivi

Configuration

Application Configuration

Configuration is managed via ConfigMap (k8s/configmap.yaml).

Key Settings

{
  "Cesivi": {
    "BaseUrl": "http://cesivi:5000",
    "EnableSwagger": false,
    "EnableHealthChecks": true,
    "EnableMetrics": true,
    "EnableTracing": true
  },
  "Storage": {
    "Provider": "SqlServer",  // or PostgreSQL
    "EnableCaching": true,
    "CacheExpiry": "00:05:00"
  },
  "DistributedState": {
    "Provider": "Redis",
    "KeyPrefix": "spm:",
    "SessionExpiry": "08:00:00"
  }
}

Update Configuration

  1. Edit k8s/configmap.yaml
  2. Apply changes:
    kubectl apply -f k8s/configmap.yaml
    
  3. Restart pods to pick up changes:
    kubectl rollout restart deployment/cesivi -n cesivi
    

Secrets Management

Update Secrets

# Update Redis connection
kubectl create secret generic spm-secrets \
  --from-literal=REDIS_CONNECTION="redis:6379,password=newpassword" \
  --dry-run=client -o yaml | kubectl apply -n cesivi -f -

# Restart deployment
kubectl rollout restart deployment/cesivi -n cesivi

Best Practices

For production, use proper secret management: - Azure: Azure Key Vault with CSI driver - AWS: AWS Secrets Manager with external-secrets operator - GCP: Google Secret Manager - Universal: HashiCorp Vault, Sealed Secrets

Resource Limits

Edit k8s/deployment.yaml to adjust resources:

resources:
  requests:
    cpu: 500m      # Increase for production
    memory: 1Gi    # Increase for production
  limits:
    cpu: 2000m
    memory: 4Gi

Apply:

kubectl apply -f k8s/deployment.yaml

Ingress Configuration

Change Hostname

Edit k8s/ingress.yaml:

spec:
  rules:
  - host: sharepoint.your-company.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: cesivi
            port:
              number: 80

Enable TLS with Let's Encrypt

Ensure cert-manager is installed, then update k8s/ingress.yaml:

metadata:
  annotations:
    cert-manager.io/cluster-issuer: "letsencrypt-prod"
spec:
  tls:
  - hosts:
    - sharepoint.your-company.com
    secretName: cesivi-tls

cert-manager will automatically provision a TLS certificate.

Custom TLS Certificate

# Create TLS secret
kubectl create secret tls cesivi-tls \
  --cert=path/to/tls.crt \
  --key=path/to/tls.key \
  -n cesivi

Monitoring

Health Checks

# Port-forward
kubectl port-forward -n cesivi svc/cesivi 8080:80

# Check health endpoints
curl http://localhost:8080/health          # Overall health
curl http://localhost:8080/health/ready    # Readiness
curl http://localhost:8080/health/live     # Liveness

Prometheus Metrics

# Access metrics endpoint
curl http://localhost:8080/metrics

ServiceMonitor (for Prometheus Operator)

Create servicemonitor.yaml:

apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
  name: cesivi
  namespace: cesivi
spec:
  selector:
    matchLabels:
      app.kubernetes.io/name: cesivi
  endpoints:
  - port: metrics
    path: /metrics
    interval: 30s

Apply:

kubectl apply -f servicemonitor.yaml

Logs

# All pods
kubectl logs -n cesivi -l app.kubernetes.io/name=cesivi --tail=100 -f

# Specific pod
kubectl logs -n cesivi <pod-name> -f

# Previous container (if crashed)
kubectl logs -n cesivi <pod-name> --previous

Events

# Recent events
kubectl get events -n cesivi --sort-by='.lastTimestamp'

# Watch events
kubectl get events -n cesivi --watch

Scaling

Manual Scaling

# Scale to 5 replicas
kubectl scale deployment cesivi --replicas=5 -n cesivi

# Verify
kubectl get pods -n cesivi

Auto-Scaling (HPA)

HPA is configured in k8s/hpa.yaml:

spec:
  minReplicas: 3
  maxReplicas: 10
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 70

Monitor HPA:

# Watch HPA status
kubectl get hpa -n cesivi --watch

# Describe HPA
kubectl describe hpa cesivi -n cesivi

Adjust Auto-Scaling

Edit k8s/hpa.yaml:

spec:
  minReplicas: 5        # Minimum pods
  maxReplicas: 20       # Maximum pods
  targetCPUUtilizationPercentage: 60  # Scale when CPU > 60%

Apply:

kubectl apply -f k8s/hpa.yaml

Troubleshooting

Pods Not Starting

Symptom: Pods in Pending, CrashLoopBackOff, or ImagePullBackOff state.

Diagnosis:

kubectl describe pod <pod-name> -n cesivi
kubectl logs <pod-name> -n cesivi

Common Issues:

  1. Image Pull Error:
  2. Check image name in deployment.yaml
  3. Verify image exists and is accessible
  4. Check imagePullSecrets if using private registry

  5. Insufficient Resources:

  6. Check node resources: kubectl describe nodes
  7. Reduce resource requests or add more nodes

  8. Failed Health Checks:

  9. Check health check endpoints: /health/ready, /health/live
  10. Increase initialDelaySeconds in probes

Database Connection Issues

Symptom: Pods running but app errors about database connection.

Diagnosis:

# Check if database pod is running
kubectl get pods -n cesivi | grep -E '(postgres|sqlserver)'

# Test connection from SPM pod
kubectl exec -it <spm-pod-name> -n cesivi -- /bin/sh
# Inside pod:
nc -zv sqlserver 1433
# or
nc -zv postgresql 5432

Solutions:

  1. Database not ready:
  2. Wait for database pod: kubectl wait --for=condition=ready pod ...

  3. Wrong connection string:

  4. Check secret: kubectl get secret spm-secrets -n cesivi -o yaml
  5. Verify hostname, port, credentials

  6. Network policy blocking:

  7. Check network policies: kubectl get networkpolicies -n cesivi

Redis Connection Issues

Symptom: Session state not working across pods.

Diagnosis:

# Check Redis pod
kubectl get pods -n cesivi -l app.kubernetes.io/name=redis

# Test connection
kubectl exec -it <spm-pod-name> -n cesivi -- /bin/sh
nc -zv redis 6379

# Check Redis logs
kubectl logs -n cesivi -l app.kubernetes.io/name=redis

Ingress Not Working

Symptom: Cannot access app via ingress hostname.

Diagnosis:

# Check ingress status
kubectl get ingress -n cesivi
kubectl describe ingress cesivi -n cesivi

# Check ingress controller
kubectl get pods -n ingress-nginx
kubectl logs -n ingress-nginx <controller-pod>

Solutions:

  1. DNS not configured:
  2. Add DNS A record pointing to ingress external IP
  3. Or add to /etc/hosts for testing

  4. TLS certificate issues:

  5. Check cert-manager logs
  6. Verify certificate: kubectl get certificate -n cesivi
  7. Check certificate status: kubectl describe certificate cesivi-tls -n cesivi

Performance Issues

Symptom: Slow response times, high CPU/memory usage.

Diagnosis:

# Check resource usage
kubectl top pods -n cesivi
kubectl top nodes

# Check HPA status
kubectl get hpa -n cesivi

# Check metrics
kubectl port-forward -n cesivi svc/cesivi 8080:80
curl http://localhost:8080/metrics | grep -E '(request_duration|memory|cpu)'

Solutions:

  1. Increase resources:
  2. Edit deployment.yaml resource limits
  3. Add more replicas

  4. Enable caching:

  5. Verify Redis is working
  6. Check cache hit ratio in metrics

  7. Database slow:

  8. Check database resource usage
  9. Add indexes, optimize queries

Production Recommendations

1. Use External Managed Services

DO NOT use in-cluster databases for production!

Use managed services instead:

  • Azure:
  • Azure Database for PostgreSQL
  • Azure Cache for Redis
  • Azure SQL Database

  • AWS:

  • RDS for PostgreSQL
  • ElastiCache for Redis
  • RDS for SQL Server

  • GCP:

  • Cloud SQL for PostgreSQL
  • Memorystore for Redis
  • Cloud SQL for SQL Server

Update k8s/secret.yaml with external connection strings.

2. Persistent Storage

Use high-performance storage classes:

# In PVC or StatefulSet
storageClassName: "premium-ssd"  # Azure
# or
storageClassName: "gp3"          # AWS
# or
storageClassName: "pd-ssd"       # GCP

3. High Availability

# Increase replicas
replicas: 5

# Update HPA
minReplicas: 3
maxReplicas: 20

# Update PDB
minAvailable: 3

4. Resource Limits

resources:
  requests:
    cpu: 1000m
    memory: 2Gi
  limits:
    cpu: 4000m
    memory: 8Gi

5. Pod Anti-Affinity

Add to deployment.yaml:

spec:
  template:
    spec:
      affinity:
        podAntiAffinity:
          preferredDuringSchedulingIgnoredDuringExecution:
          - weight: 100
            podAffinityTerm:
              labelSelector:
                matchExpressions:
                - key: app.kubernetes.io/name
                  operator: In
                  values:
                  - cesivi
              topologyKey: kubernetes.io/hostname

This ensures pods run on different nodes for HA.

6. Network Policies

Restrict network traffic:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: cesivi-network-policy
  namespace: cesivi
spec:
  podSelector:
    matchLabels:
      app.kubernetes.io/name: cesivi
  policyTypes:
  - Ingress
  - Egress
  ingress:
  - from:
    - namespaceSelector:
        matchLabels:
          name: ingress-nginx
    ports:
    - protocol: TCP
      port: 5000
  egress:
  - to:
    - podSelector:
        matchLabels:
          app.kubernetes.io/name: redis
    ports:
    - protocol: TCP
      port: 6379
  - to:
    - podSelector:
        matchLabels:
          app.kubernetes.io/name: postgresql
    ports:
    - protocol: TCP
      port: 5432

7. Monitoring & Alerting

  • Enable Prometheus ServiceMonitor
  • Configure alerts for:
  • Pod restarts
  • High CPU/memory usage
  • Failed health checks
  • Slow response times

8. Backup & Disaster Recovery

# Backup database (PostgreSQL example)
kubectl exec -n cesivi postgresql-0 -- \
  pg_dump -U sharepoint_mock Cesivi > backup.sql

# Backup Redis (if needed)
kubectl exec -n cesivi redis-0 -- \
  redis-cli BGSAVE

# Backup entire namespace (using Velero)
velero backup create cesivi-backup \
  --include-namespaces cesivi

Advanced Topics

Multi-Tenant Deployment

Deploy multiple isolated instances:

# Tenant 1
kubectl create namespace cesivi-tenant1
kubectl apply -f k8s/ -n cesivi-tenant1

# Tenant 2
kubectl create namespace cesivi-tenant2
kubectl apply -f k8s/ -n cesivi-tenant2

Use different ingress hostnames for each tenant.

GitOps with ArgoCD

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: cesivi
  namespace: argocd
spec:
  project: default
  source:
    repoURL: https://github.com/your-org/cesivi
    targetRevision: main
    path: k8s
  destination:
    server: https://kubernetes.default.svc
    namespace: cesivi
  syncPolicy:
    automated:
      prune: true
      selfHeal: true

Service Mesh (Istio)

Add Istio sidecar injection:

metadata:
  labels:
    istio-injection: enabled

Configure VirtualService and DestinationRule for advanced traffic management.

Blue/Green Deployment

# Deploy green version
kubectl apply -f k8s-green/

# Test green version
kubectl port-forward -n cesivi-green svc/cesivi 9090:80

# Switch traffic (update ingress)
kubectl patch ingress cesivi -n cesivi \
  --type=json -p='[{"op": "replace", "path": "/spec/rules/0/http/paths/0/backend/service/name", "value":"cesivi-green"}]'

# Cleanup blue version
kubectl delete -f k8s/

Canary Deployment

Use Flagger or Argo Rollouts for automated canary deployments.

Next Steps

Support