Introduction
Migrating an application to Azure Kubernetes Service (AKS) is a project that, with good preparation, can run without downtime. With poor preparation — it might cost you several sleepless nights. In this article we’ll cover what you need to check, plan and prepare before moving the first line of code to the cloud.
Step 1 — Audit the Existing Application
Is the application container-ready?
✓ Application is stateless?
✓ Configuration comes from environment variables?
✓ Logs go to stdout/stderr?
✓ Application handles SIGTERM for graceful shutdown?
✓ Health check endpoint exists (/health or /ready)?
Choosing a migration strategy (6R model)
| Strategy | When to use | Effort |
|---|---|---|
| Rehost (lift & shift) | VM → Azure VM, no changes | Low |
| Replatform | Minimal changes, e.g. DB → Azure SQL | Medium |
| Refactor | Rewrite to microservices / containers | High |
Step 2 — Plan the AKS Architecture
Internet → Azure Load Balancer → Ingress Controller (nginx)
→ AKS Cluster [Node 1: app-pod, Node 2: app-pod]
→ Azure SQL DB + Azure Blob Storage
Node pools
az aks nodepool add \
--cluster-name my-aks \
--resource-group my-rg \
--name apppool \
--node-count 2 \
--node-vm-size Standard_D2s_v3 \
--mode User
Step 3 — Prepare Infrastructure (Terraform)
resource "azurerm_kubernetes_cluster" "main" {
name = "myapp-aks"
location = azurerm_resource_group.main.location
resource_group_name = azurerm_resource_group.main.name
dns_prefix = "myapp"
kubernetes_version = "1.29"
default_node_pool {
name = "system"
node_count = 2
vm_size = "Standard_D2s_v3"
enable_auto_scaling = true
min_count = 2
max_count = 5
}
identity {
type = "SystemAssigned"
}
network_profile {
network_plugin = "azure"
load_balancer_sku = "standard"
}
}
terraform init && terraform plan -out=tfplan && terraform apply tfplan
az aks get-credentials --resource-group myapp-rg --name myapp-aks
Step 4 — Kubernetes Manifests
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp
namespace: production
spec:
replicas: 2
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
template:
spec:
containers:
- name: myapp
image: myregistry.azurecr.io/myapp:v1.0.0
resources:
requests:
memory: "128Mi"
cpu: "100m"
limits:
memory: "256Mi"
cpu: "500m"
livenessProbe:
httpGet:
path: /health
port: 8000
readinessProbe:
httpGet:
path: /ready
port: 8000
Step 5 — Database Migration Strategy
Phase 1: Launch new database (Azure SQL) in parallel with the old one
Phase 2: Synchronise data (replication or ETL)
Phase 3: Switch application to new database
Phase 4: Monitor for 24-48h
Phase 5: Shut down old database
# PostgreSQL → Azure Database for PostgreSQL
pg_dump -h old-server -U user dbname | \
psql "host=new-server.postgres.database.azure.com user=admin dbname=mydb sslmode=require"
Step 6 — Pre-Go-Live Checklist
INFRASTRUCTURE
✓ AKS cluster with min. 2 nodes (HA)
✓ Node autoscaling configured
✓ Monitoring (Azure Monitor / Grafana) active
✓ Alerts on CPU/memory/pod restarts
APPLICATION
✓ Health checks work (/health, /ready)
✓ Resource requests/limits set
✓ Secrets in Azure Key Vault (not in yaml)
✓ NetworkPolicy configured
DNS AND SSL
✓ Ingress Controller installed
✓ Cert-manager with Let's Encrypt configured
✓ DNS switched (TTL lowered to 60s)
Common Pitfalls
Image Pull Secrets — AKS needs permissions to a private registry:
az aks update --name myapp-aks --resource-group myapp-rg --attach-acr myregistry
Resource Limits — without requests and limits, one pod can starve an entire node.
Summary
A successful AKS migration is a matter of planning, not luck. Key principles: adapt the application first, use Terraform for infrastructure, take care of the database and test disaster recovery before you need it.