Architecture overview
Why this architecture
Zone redundancy at every layer
A single AZ failure must not cause an outage. This requires: a zone-redundant load balancer, NGINX Ingress replicas across zones, application pods spread across zones viatopologySpreadConstraints, a zone-redundant PostgreSQL Flexible Server, and an Azure Cache for Redis Standard C1 (which includes a replica in a separate fault domain). The AKS control plane is zone-redundant by default when you set --zones 1 2 3 on the node pools.
Spot instances for the safety worker only
The safety worker is the only component suitable for spot instances. It is stateless, processes jobs from a queue, and handlesSIGTERM gracefully. The proxy, API, and web services are latency-sensitive and must run on regular-priority nodes to avoid the 30-second eviction notice.
GitOps, not imperative kubectl
All cluster state is declared in a Helm chart checked into adeploy/ directory. The CI pipeline runs helm upgrade --install on every merge to main. There is no “apply some YAML files” step in production — that creates configuration drift. The Helm chart is the single source of truth.
Node pool design
Namespace design
Three namespaces keep platform, data, and monitoring concerns cleanly separated. RBAC policies are applied per namespace so the monitoring namespace cannot write to platform secrets.In the reference architecture, PostgreSQL and Redis run as fully managed Azure services (PostgreSQL Flexible Server and Azure Cache for Redis), not in-cluster. The
cognisafe-data namespace is only relevant if you choose to run in-cluster databases for cost or latency reasons — this is not recommended for production.High availability configuration
Proxy (2+ replicas)
API (2+ replicas)
Safety worker (3 replicas minimum, HPA up to 20)
PostgreSQL Flexible Server (zone-redundant)
Azure Cache for Redis (Standard C1 with replica)
Secret management
All secrets live in Azure Key Vault and are injected into pods at runtime via the Secrets Store CSI driver. Secrets are never stored in etcd, never in manifests, and never in environment files committed to source control. Key rotation happens in Key Vault; the CSI driver picks up new values on the next pod restart without a redeployment.Certificate management
cert-manager issues and renews a wildcard TLS certificate for*.cognisafe.yourco.com using DNS-01 challenge against Azure DNS. This avoids exposing each individual subdomain for HTTP-01 validation.
Ingress rules
Deployment pipeline
The deployment pipeline runs on GitHub Actions. The pipeline builds, tests, pushes images to ACR, and performs a Helm upgrade. The Alembic migration runs as a Kubernetes Job before the new API pods are promoted, not as an init container in production (init containers on every replica are acceptable in staging but create race conditions at scale).Observability
Azure Monitor + Container Insights
Container Insights is enabled at cluster creation. It provides per-node and per-pod CPU, memory, network, and disk metrics in Azure Monitor, plus log forwarding to a Log Analytics workspace. Navigate to AKS → Monitoring → Insights in the Azure Portal.kube-prometheus-stack
Key alerts
Custom Cognisafe Prometheus metrics
Expose these metrics from the API service by adding a/metrics endpoint (FastAPI + prometheus-fastapi-instrumentator):
ServiceMonitor so Prometheus scrapes the API pods:
Backup and restore
Daily pg_dump to Azure Blob Storage
Tested restore procedure
1
List available backups
2
Download the target dump
3
Restore to a recovery PostgreSQL instance
4
Verify row counts match expectation
5
Promote the recovery instance
Update the
POSTGRES_URL secret in Key Vault to point at the recovery server. Restart all pods to pick up the new connection string.Disaster recovery
Failover procedure (full region loss)
1
Promote PostgreSQL geo-replica
2
Deploy AKS cluster in secondary region
Run the same Terraform/Bicep that provisions the primary cluster, targeting the secondary region (e.g.,
northeurope).3
Update Key Vault secrets
Update
cognisafe-postgres-url and cognisafe-redis-url in the secondary region’s Key Vault to point at the promoted replicas.4
Deploy application via Helm
5
Reroute DNS
Update Azure DNS or Traffic Manager to point
*.cognisafe.yourco.com at the secondary region’s load balancer IP.Cost estimate
All prices are approximate UK South list pricing as of mid-2026. Actual costs depend on reserved instance discounts, egress, and storage.Security hardening checklist
- Network Policy enabled (
--network-policy azure) — deny all ingress/egress by default, allow only required pod-to-pod paths - Private endpoint for PostgreSQL Flexible Server — no public network access
- Private endpoint for Azure Cache for Redis — TLS 1.2 minimum, no non-SSL port
- Azure Key Vault firewall — allow only AKS subnet CIDR and deployment pipeline IPs
- ACR network rules — allow only AKS kubelet subnet
- Pod Security Standards — set
pod-security.kubernetes.io/enforce: restrictedoncognisafe-systemnamespace - Container images built on
distrolessbase, non-root UID, read-only root filesystem - Dependabot or Renovate enabled on the repository for automated dependency updates
- Microsoft Defender for Containers enabled on the AKS cluster
- Audit logging enabled on the AKS control plane, forwarded to Log Analytics

