Back to Blog
4 min read

Deployment Strategies for Azure Kubernetes Service

Azure Kubernetes Service (AKS) has become the go-to platform for container orchestration on Azure. As organizations scale their container deployments, choosing the right deployment strategy becomes critical. Let me walk through the common patterns.

Prerequisites

# Create an AKS cluster
az aks create \
    --resource-group rg-aks \
    --name aks-cluster \
    --node-count 3 \
    --enable-addons monitoring \
    --generate-ssh-keys

# Get credentials
az aks get-credentials --resource-group rg-aks --name aks-cluster

Rolling Update (Default)

The default strategy replaces pods gradually:

# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp
spec:
  replicas: 4
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 1
  selector:
    matchLabels:
      app: myapp
  template:
    metadata:
      labels:
        app: myapp
    spec:
      containers:
        - name: myapp
          image: myregistry.azurecr.io/myapp:v1
          ports:
            - containerPort: 80
          readinessProbe:
            httpGet:
              path: /health
              port: 80
            initialDelaySeconds: 5
            periodSeconds: 10
          livenessProbe:
            httpGet:
              path: /health
              port: 80
            initialDelaySeconds: 15
            periodSeconds: 20

Deploy and update:

# Initial deployment
kubectl apply -f deployment.yaml

# Update the image
kubectl set image deployment/myapp myapp=myregistry.azurecr.io/myapp:v2

# Watch the rollout
kubectl rollout status deployment/myapp

# Rollback if needed
kubectl rollout undo deployment/myapp

Blue-Green Deployment

Run two identical environments and switch traffic:

# blue-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp-blue
spec:
  replicas: 3
  selector:
    matchLabels:
      app: myapp
      version: blue
  template:
    metadata:
      labels:
        app: myapp
        version: blue
    spec:
      containers:
        - name: myapp
          image: myregistry.azurecr.io/myapp:v1
          ports:
            - containerPort: 80
---
# green-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp-green
spec:
  replicas: 3
  selector:
    matchLabels:
      app: myapp
      version: green
  template:
    metadata:
      labels:
        app: myapp
        version: green
    spec:
      containers:
        - name: myapp
          image: myregistry.azurecr.io/myapp:v2
          ports:
            - containerPort: 80
---
# service.yaml
apiVersion: v1
kind: Service
metadata:
  name: myapp
spec:
  selector:
    app: myapp
    version: blue  # Switch to green when ready
  ports:
    - port: 80
      targetPort: 80

Switch traffic:

# Deploy green version
kubectl apply -f green-deployment.yaml

# Test green deployment (via port-forward or internal service)
kubectl port-forward deployment/myapp-green 8080:80

# Switch traffic to green
kubectl patch service myapp -p '{"spec":{"selector":{"version":"green"}}}'

# Clean up blue deployment
kubectl delete deployment myapp-blue

Canary Deployment

Route a percentage of traffic to the new version:

# stable-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp-stable
spec:
  replicas: 9
  selector:
    matchLabels:
      app: myapp
      track: stable
  template:
    metadata:
      labels:
        app: myapp
        track: stable
    spec:
      containers:
        - name: myapp
          image: myregistry.azurecr.io/myapp:v1
---
# canary-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp-canary
spec:
  replicas: 1  # 10% of total (1 out of 10)
  selector:
    matchLabels:
      app: myapp
      track: canary
  template:
    metadata:
      labels:
        app: myapp
        track: canary
    spec:
      containers:
        - name: myapp
          image: myregistry.azurecr.io/myapp:v2
---
# service.yaml
apiVersion: v1
kind: Service
metadata:
  name: myapp
spec:
  selector:
    app: myapp  # Matches both stable and canary
  ports:
    - port: 80
      targetPort: 80

Gradually shift traffic:

# Scale canary up, stable down
kubectl scale deployment myapp-canary --replicas=3
kubectl scale deployment myapp-stable --replicas=7

# Continue until fully migrated
kubectl scale deployment myapp-canary --replicas=10
kubectl scale deployment myapp-stable --replicas=0

Using Helm for Deployments

# Create a Helm chart
helm create myapp

# Install
helm install myapp ./myapp --set image.tag=v1

# Upgrade
helm upgrade myapp ./myapp --set image.tag=v2

# Rollback
helm rollback myapp 1

Health Checks Are Critical

Always configure proper probes:

readinessProbe:
  httpGet:
    path: /ready
    port: 80
  initialDelaySeconds: 5
  periodSeconds: 5
  failureThreshold: 3

livenessProbe:
  httpGet:
    path: /health
    port: 80
  initialDelaySeconds: 30
  periodSeconds: 10
  failureThreshold: 3

startupProbe:
  httpGet:
    path: /health
    port: 80
  failureThreshold: 30
  periodSeconds: 10

Monitoring Deployments

# Watch deployment progress
kubectl get deployments -w

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

# View pod logs
kubectl logs -f deployment/myapp

Choosing the right deployment strategy depends on your risk tolerance and application requirements. Start with rolling updates and evolve to more sophisticated strategies as needed.

Michael John Peña

Michael John Peña

Senior Data Engineer based in Sydney. Writing about data, cloud, and technology.