Skip to main content

Deployment Guide

Complete guide for deploying CODITECT DMS to production on Google Cloud Platform.


Architecture Overview

                    ┌─────────────────┐
│ Cloud Load │
│ Balancer │
│ (HTTPS/SSL) │
└────────┬────────┘

┌────────▼────────┐
│ Cloud Armor │
│ (WAF/DDoS) │
└────────┬────────┘

┌──────────────┼──────────────┐
│ │ │
┌────────▼────┐ ┌──────▼─────┐ ┌─────▼──────┐
│ GKE Cluster │ │ GKE │ │ GKE │
│ API Pods │ │ Worker │ │ Frontend │
│ (3-20) │ │ Pods │ │ (Nginx) │
└──────┬───────┘ └─────┬──────┘ └────────────┘
│ │
└────────┬───────┘

┌────────────┼────────────┐
│ │ │
┌────▼────┐ ┌────▼────┐ ┌────▼────┐
│ Cloud │ │ Memory- │ │ Cloud │
│ SQL │ │ store │ │ Storage │
│ (PG15) │ │ (Redis) │ │ (GCS) │
└─────────┘ └─────────┘ └─────────┘

Prerequisites

Required Tools

# Install required CLI tools
brew install google-cloud-sdk kubectl helm

# Authenticate with GCP
gcloud auth login
gcloud auth application-default login

# Set project
gcloud config set project coditect-prod

GCP Services

Enable required APIs:

gcloud services enable \
container.googleapis.com \
sqladmin.googleapis.com \
redis.googleapis.com \
secretmanager.googleapis.com \
cloudarmor.googleapis.com \
monitoring.googleapis.com \
logging.googleapis.com

Infrastructure Setup

1. Create GKE Cluster

# Create cluster
gcloud container clusters create coditect-prod-cluster \
--zone=us-central1-a \
--machine-type=n2-standard-4 \
--num-nodes=3 \
--min-nodes=2 \
--max-nodes=10 \
--enable-autoscaling \
--enable-network-policy \
--enable-ip-alias \
--enable-shielded-nodes \
--workload-pool=coditect-prod.svc.id.goog

# Get credentials
gcloud container clusters get-credentials coditect-prod-cluster \
--zone=us-central1-a

2. Create Cloud SQL Instance

# Create PostgreSQL instance
gcloud sql instances create coditect-dms-db \
--database-version=POSTGRES_15 \
--tier=db-custom-4-16384 \
--region=us-central1 \
--availability-type=regional \
--storage-size=100GB \
--storage-auto-increase \
--backup-start-time=02:00 \
--enable-point-in-time-recovery

# Create database
gcloud sql databases create dms \
--instance=coditect-dms-db

# Create user
gcloud sql users create dms_user \
--instance=coditect-dms-db \
--password=$(openssl rand -base64 32)

# Enable pgvector extension
gcloud sql connect coditect-dms-db --user=postgres
# SQL> CREATE EXTENSION IF NOT EXISTS vector;

3. Create Memorystore Redis

# Create Redis instance
gcloud redis instances create coditect-dms-cache \
--size=2 \
--region=us-central1 \
--redis-version=redis_7_0 \
--tier=standard

4. Create Cloud Storage Bucket

# Create bucket for document storage
gsutil mb -l us-central1 gs://coditect-dms-documents

# Set lifecycle policy
gsutil lifecycle set lifecycle.json gs://coditect-dms-documents

Secrets Management

Create Secrets in Secret Manager

# Database URL
echo -n "postgresql://dms_user:PASSWORD@/dms?host=/cloudsql/coditect-prod:us-central1:coditect-dms-db" | \
gcloud secrets create dms-database-url --data-file=-

# JWT Secret
openssl rand -base64 64 | \
gcloud secrets create dms-jwt-secret --data-file=-

# OpenAI API Key
echo -n "sk-..." | \
gcloud secrets create dms-openai-key --data-file=-

# Stripe Secret Key
echo -n "sk_live_..." | \
gcloud secrets create dms-stripe-secret --data-file=-

Grant Access to GKE

# Create Kubernetes service account
kubectl create namespace coditect-dms
kubectl create serviceaccount dms-api -n coditect-dms

# Bind to GCP service account
gcloud iam service-accounts create dms-api-sa

gcloud iam service-accounts add-iam-policy-binding \
dms-api-sa@coditect-prod.iam.gserviceaccount.com \
--role roles/iam.workloadIdentityUser \
--member "serviceAccount:coditect-prod.svc.id.goog[coditect-dms/dms-api]"

# Grant secret access
gcloud secrets add-iam-policy-binding dms-database-url \
--role="roles/secretmanager.secretAccessor" \
--member="serviceAccount:dms-api-sa@coditect-prod.iam.gserviceaccount.com"

# Repeat for other secrets...

Kubernetes Deployment

1. Create Namespace and ConfigMap

# deploy/kubernetes/namespace.yaml
apiVersion: v1
kind: Namespace
metadata:
name: coditect-dms
labels:
name: coditect-dms
---
apiVersion: v1
kind: ConfigMap
metadata:
name: dms-config
namespace: coditect-dms
data:
APP_NAME: "CODITECT DMS"
APP_VERSION: "1.0.0"
ENVIRONMENT: "production"
LOG_LEVEL: "INFO"
CORS_ORIGINS: "https://dms.coditect.ai"
REDIS_URL: "redis://10.0.0.1:6379"

2. Deploy API

# deploy/kubernetes/api-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: coditect-dms-api
namespace: coditect-dms
spec:
replicas: 3
selector:
matchLabels:
app: dms-api
template:
metadata:
labels:
app: dms-api
spec:
serviceAccountName: dms-api
containers:
- name: api
image: gcr.io/coditect-prod/dms-api:1.0.0
ports:
- containerPort: 8000
envFrom:
- configMapRef:
name: dms-config
env:
- name: API_DATABASE_URL
valueFrom:
secretKeyRef:
name: dms-secrets
key: database-url
- name: API_JWT_SECRET
valueFrom:
secretKeyRef:
name: dms-secrets
key: jwt-secret
resources:
requests:
cpu: 500m
memory: 512Mi
limits:
cpu: 2000m
memory: 2Gi
livenessProbe:
httpGet:
path: /health/live
port: 8000
initialDelaySeconds: 10
periodSeconds: 10
readinessProbe:
httpGet:
path: /health/ready
port: 8000
initialDelaySeconds: 5
periodSeconds: 5
---
apiVersion: v1
kind: Service
metadata:
name: dms-api
namespace: coditect-dms
spec:
selector:
app: dms-api
ports:
- port: 80
targetPort: 8000
type: ClusterIP

3. Deploy HPA

# deploy/kubernetes/hpa.yaml
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: dms-api-hpa
namespace: coditect-dms
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: coditect-dms-api
minReplicas: 3
maxReplicas: 20
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: 80

4. Deploy Ingress

# deploy/kubernetes/ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: dms-ingress
namespace: coditect-dms
annotations:
kubernetes.io/ingress.class: "gce"
kubernetes.io/ingress.global-static-ip-name: "dms-api-ip"
networking.gke.io/managed-certificates: "dms-cert"
kubernetes.io/ingress.allow-http: "false"
spec:
rules:
- host: dms-api.coditect.ai
http:
paths:
- path: /*
pathType: ImplementationSpecific
backend:
service:
name: dms-api
port:
number: 80
---
apiVersion: networking.gke.io/v1
kind: ManagedCertificate
metadata:
name: dms-cert
namespace: coditect-dms
spec:
domains:
- dms-api.coditect.ai

5. Apply Manifests

# Apply all manifests
kubectl apply -f deploy/kubernetes/namespace.yaml
kubectl apply -f deploy/kubernetes/

Celery Workers

Deploy Workers

# deploy/kubernetes/workers.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: dms-worker
namespace: coditect-dms
spec:
replicas: 3
selector:
matchLabels:
app: dms-worker
template:
metadata:
labels:
app: dms-worker
spec:
serviceAccountName: dms-api
containers:
- name: worker
image: gcr.io/coditect-prod/dms-api:1.0.0
command: ["celery", "-A", "src.backend.tasks", "worker", "-l", "info"]
envFrom:
- configMapRef:
name: dms-config
env:
- name: CELERY_BROKER_URL
value: "redis://10.0.0.1:6379/0"
- name: CELERY_RESULT_BACKEND
value: "redis://10.0.0.1:6379/0"
resources:
requests:
cpu: 500m
memory: 1Gi
limits:
cpu: 2000m
memory: 4Gi

Monitoring Setup

Install Prometheus Stack

# Add Helm repo
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
helm repo update

# Install kube-prometheus-stack
helm install monitoring prometheus-community/kube-prometheus-stack \
--namespace monitoring \
--create-namespace \
--values deploy/kubernetes/monitoring-values.yaml

Apply ServiceMonitor

kubectl apply -f deploy/kubernetes/monitoring.yaml

Access Grafana

# Get admin password
kubectl get secret -n monitoring monitoring-grafana \
-o jsonpath="{.data.admin-password}" | base64 --decode

# Port forward
kubectl port-forward -n monitoring svc/monitoring-grafana 3000:80
# Open http://localhost:3000

Database Migrations

Run Migrations

# Connect to Cloud SQL via proxy
cloud_sql_proxy -instances=coditect-prod:us-central1:coditect-dms-db=tcp:5432 &

# Run migrations
DATABASE_URL="postgresql://dms_user:PASSWORD@localhost:5432/dms" \
alembic upgrade head

Rollback Migrations

# Rollback one step
alembic downgrade -1

# Rollback to specific revision
alembic downgrade <revision_id>

CI/CD Pipeline

GitHub Actions Workflow

# .github/workflows/deploy.yaml
name: Deploy to Production

on:
push:
branches: [main]
paths:
- 'src/**'
- 'deploy/**'

jobs:
build-and-deploy:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4

- name: Auth to GCP
uses: google-github-actions/auth@v2
with:
credentials_json: ${{ secrets.GCP_SA_KEY }}

- name: Setup gcloud
uses: google-github-actions/setup-gcloud@v2

- name: Configure Docker
run: gcloud auth configure-docker gcr.io

- name: Build and Push
run: |
docker build -t gcr.io/coditect-prod/dms-api:${{ github.sha }} .
docker push gcr.io/coditect-prod/dms-api:${{ github.sha }}

- name: Deploy to GKE
run: |
gcloud container clusters get-credentials coditect-prod-cluster \
--zone us-central1-a

kubectl set image deployment/coditect-dms-api \
api=gcr.io/coditect-prod/dms-api:${{ github.sha }} \
-n coditect-dms

kubectl rollout status deployment/coditect-dms-api \
-n coditect-dms --timeout=300s

Health Checks

Verify Deployment

# Check pods
kubectl get pods -n coditect-dms

# Check logs
kubectl logs -f deployment/coditect-dms-api -n coditect-dms

# Check health
curl https://dms-api.coditect.ai/health

# Check readiness
curl https://dms-api.coditect.ai/health/ready

Troubleshooting

# Describe pod
kubectl describe pod <pod-name> -n coditect-dms

# Check events
kubectl get events -n coditect-dms --sort-by='.lastTimestamp'

# Port forward for local testing
kubectl port-forward svc/dms-api 8000:80 -n coditect-dms
curl http://localhost:8000/health

Scaling

Manual Scaling

# Scale API pods
kubectl scale deployment coditect-dms-api --replicas=10 -n coditect-dms

# Scale workers
kubectl scale deployment dms-worker --replicas=5 -n coditect-dms

Adjust HPA

# Edit HPA
kubectl edit hpa dms-api-hpa -n coditect-dms

Security Hardening

Network Policies

# deploy/kubernetes/network-policy.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: dms-api-policy
namespace: coditect-dms
spec:
podSelector:
matchLabels:
app: dms-api
policyTypes:
- Ingress
- Egress
ingress:
- from:
- namespaceSelector:
matchLabels:
name: ingress-nginx
ports:
- protocol: TCP
port: 8000
egress:
- to:
- ipBlock:
cidr: 10.0.0.0/8 # Allow internal
- ports:
- protocol: TCP
port: 5432 # PostgreSQL
- protocol: TCP
port: 6379 # Redis
- protocol: TCP
port: 443 # External HTTPS

Cloud Armor Policy

# Create security policy
gcloud compute security-policies create dms-security-policy \
--description="DMS API Security Policy"

# Add rate limiting rule
gcloud compute security-policies rules create 1000 \
--security-policy=dms-security-policy \
--expression="true" \
--action=rate-based-ban \
--rate-limit-threshold-count=1000 \
--rate-limit-threshold-interval-sec=60 \
--ban-duration-sec=600

# Add SQL injection protection
gcloud compute security-policies rules create 2000 \
--security-policy=dms-security-policy \
--expression="evaluatePreconfiguredExpr('sqli-stable')" \
--action=deny-403

Backup and Recovery

Database Backups

Automated backups are enabled with 7-day retention. For additional backups:

# Manual backup
gcloud sql backups create \
--instance=coditect-dms-db \
--description="Pre-deployment backup"

# List backups
gcloud sql backups list --instance=coditect-dms-db

Disaster Recovery

See disaster-recovery-runbook.md for complete DR procedures.


Support