Last updated: May 2026
Azure ContainersIntermediateAZ-104⏱ 12 min read

Deploy an Application to AKS

Deploying an application to AKS involves writing Kubernetes manifest files (YAML) that describe what you want — which image to run, how many replicas, how to expose it. Kubernetes then makes it happen and keeps it running. This page covers the complete deployment workflow from manifest to live application.

What you'll learn Writing a Deployment manifest · Writing a Service manifest · Exposing with LoadBalancer vs Ingress · Environment variables and Secrets · Health probes (liveness, readiness) · Rolling updates · Viewing logs and debugging · kubectl essential commands

Deployment Manifest

YAMLdeployment.yaml — 3 replicas of a Node.js app
apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp
  namespace: default
spec:
  replicas: 3                          # Run 3 identical pods
  selector:
    matchLabels:
      app: myapp
  template:
    metadata:
      labels:
        app: myapp
    spec:
      containers:
      - name: myapp
        image: myregistry.azurecr.io/myapp:v1
        ports:
        - containerPort: 3000
        resources:
          requests:
            cpu: "250m"                # 0.25 vCPU minimum
            memory: "256Mi"            # 256 MB minimum
          limits:
            cpu: "500m"                # 0.5 vCPU maximum
            memory: "512Mi"            # 512 MB maximum
        env:
        - name: NODE_ENV
          value: production

Service Manifest

YAMLservice.yaml — expose app with Azure Load Balancer
apiVersion: v1
kind: Service
metadata:
  name: myapp-service
spec:
  type: LoadBalancer          # Creates Azure Load Balancer with public IP
  selector:
    app: myapp                # Routes to pods with this label
  ports:
  - protocol: TCP
    port: 80                  # External port
    targetPort: 3000          # Container port

Applying Manifests

kubectlApply manifests and check status
# Apply deployment and service
kubectl apply -f deployment.yaml
kubectl apply -f service.yaml

# Or apply all YAMLs in a directory
kubectl apply -f ./k8s/

# Check deployment status
kubectl get deployments
kubectl get pods
kubectl get services

# Wait for external IP (may take 1-2 minutes)
kubectl get service myapp-service --watch

# Output when ready:
# NAME            TYPE           CLUSTER-IP   EXTERNAL-IP    PORT(S)
# myapp-service   LoadBalancer   10.0.1.5     20.1.2.3       80:30000/TCP

Secrets and ConfigMaps

YAMLSecret and ConfigMap — inject into pod
# Secret (base64 encoded values)
apiVersion: v1
kind: Secret
metadata:
  name: myapp-secrets
type: Opaque
stringData:                    # stringData auto-encodes to base64
  DATABASE_URL: "mongodb://user:pass@host/db"
  API_KEY: "mysecretkey"
---
# ConfigMap (plain text)
apiVersion: v1
kind: ConfigMap
metadata:
  name: myapp-config
data:
  NODE_ENV: "production"
  LOG_LEVEL: "info"
YAMLReference Secret and ConfigMap in Deployment
        env:
        - name: DATABASE_URL
          valueFrom:
            secretKeyRef:
              name: myapp-secrets
              key: DATABASE_URL
        - name: NODE_ENV
          valueFrom:
            configMapKeyRef:
              name: myapp-config
              key: NODE_ENV

Health Probes

YAMLLiveness and readiness probes
        livenessProbe:           # Is the container alive? Restart if fails.
          httpGet:
            path: /health
            port: 3000
          initialDelaySeconds: 10
          periodSeconds: 10

        readinessProbe:          # Is the container ready for traffic? Remove from LB if fails.
          httpGet:
            path: /ready
            port: 3000
          initialDelaySeconds: 5
          periodSeconds: 5
ProbeFails → ActionPurpose
LivenessContainer restartedDetect deadlocked/stuck containers
ReadinessRemoved from Service endpointsPrevent traffic before app is ready

Rolling Updates

kubectlUpdate image and roll back
# Update image to new version
kubectl set image deployment/myapp myapp=myregistry.azurecr.io/myapp:v2

# Watch rollout progress
kubectl rollout status deployment/myapp

# Check rollout history
kubectl rollout history deployment/myapp

# Rollback to previous version
kubectl rollout undo deployment/myapp

Viewing Logs and Debugging

kubectlDebugging commands
# View pod logs
kubectl logs myapp-pod-xyz

# Follow logs in real time
kubectl logs -f myapp-pod-xyz

# View logs for all pods with label
kubectl logs -l app=myapp

# Describe a pod (events, status, config)
kubectl describe pod myapp-pod-xyz

# Execute command inside pod
kubectl exec -it myapp-pod-xyz -- /bin/sh

# Get events (useful for troubleshooting)
kubectl get events --sort-by=.lastTimestamp
💡
AZ-104 Exam Tip Know that kubectl apply -f deploys manifests. Know the difference between liveness (restart) and readiness (remove from load balancer) probes. Know that rolling updates update pods one at a time. Know kubectl rollout undo rolls back to the previous version.
📝 Practice Questions
Click an option to check your answer.
Q1. What Service type creates an Azure Load Balancer with a public IP for an AKS application?
A — ClusterIP
B — NodePort
C — LoadBalancer
D — ExternalName
Q2. What happens when a liveness probe fails repeatedly on a container?
A — The container is removed from the load balancer
B — The container is restarted
C — The entire pod is deleted and a new one is created
D — The node is rebooted
Q3. How do you roll back a deployment to the previous version in Kubernetes?
A — kubectl rollout status deployment/myapp
B — kubectl rollout undo deployment/myapp
C — kubectl delete deployment/myapp
D — kubectl apply -f old-deployment.yaml
Q4. What should you use to store a database password that will be injected into pods as an environment variable?
A — ConfigMap
B — Secret
C — PersistentVolume
D — Namespace
Q5. What is the difference between a liveness probe and a readiness probe?
A — Liveness failure removes the pod from the load balancer; readiness failure restarts the container
B — Liveness failure restarts the container; readiness failure removes the pod from the load balancer
C — Liveness uses HTTP checks; readiness uses TCP checks
D — Liveness is configured at cluster level; readiness is configured at pod level
Comments
Disclaimer: RedKite Cloud is an independent educational resource and is not affiliated with Microsoft Corporation.