3.1 Deploy & Manage Apps on AKS with Manifests
Key Takeaways
- AKS applications are declared as Kubernetes objects in YAML manifests—Deployments for Pods, Services for stable networking, and Ingress for HTTP(S) routing
- kubectl apply -f creates or updates resources declaratively; always target the correct namespace with -n or metadata.namespace
- Namespaces isolate workloads, RBAC, quotas, and DNS names (svc.namespace.svc.cluster.local) inside one AKS cluster
- Liveness probes restart unhealthy containers; readiness probes remove Pods from Service endpoints until they can serve traffic
- Ingress controllers (often NGINX or Application Gateway for Containers) translate Ingress rules into load balancer and path routing configuration
Deploy & Manage Apps on AKS with Manifests
Quick Answer: On AKS you describe desired state in YAML manifests—typically a Deployment (Pods + ReplicaSet), a Service (stable ClusterIP/LoadBalancer), and often an Ingress (HTTP path/host routing). Apply with
kubectl apply -f, scope objects to a namespace, and use liveness/readiness probes so Kubernetes restarts failed containers and withholds traffic until Pods are ready.
Azure Kubernetes Service (AKS) runs standard Kubernetes. For AI-200, you must know how to declare containerized apps as manifests, apply them to a cluster, and manage rollouts, networking, and health checks without relying on the Azure portal alone.
Why Manifests Matter on AKS
A manifest is a YAML (or JSON) document with apiVersion, kind, metadata, and spec. Kubernetes reconciles the live cluster toward that desired state. This declarative model is exam-critical: you do not SSH into nodes to start processes—you submit objects and let controllers create Pods, endpoints, and routes.
Typical production app set:
- Deployment — manages identical Pod replicas and rolling updates
- Service — stable virtual IP and DNS name in front of Pods
- Ingress (optional) — L7 HTTP(S) routing from outside the cluster to Services
ConfigMaps and Secrets often accompany these for non-secret and secret configuration, but Deployments, Services, and Ingress are the core trio for "deploy apps with manifests."
Deployment Manifest Essentials
A Deployment creates a ReplicaSet that keeps replicas Pods matching a Pod template. Key fields you must recognize:
| Field | Purpose |
|---|---|
spec.replicas | Desired number of Pods |
spec.selector.matchLabels | Labels the ReplicaSet uses to own Pods |
spec.template.metadata.labels | Must match the selector |
spec.template.spec.containers[].image | Container image (often from ACR) |
spec.template.spec.containers[].ports | Container port the app listens on |
spec.strategy | RollingUpdate (default) vs Recreate |
Example shape (abbreviated):
apiVersion: apps/v1
kind: Deployment
metadata:
name: inference-api
namespace: ml-apps
spec:
replicas: 3
selector:
matchLabels:
app: inference-api
template:
metadata:
labels:
app: inference-api
spec:
containers:
- name: api
image: myacr.azurecr.io/inference:1.4.0
ports:
- containerPort: 8080
Selector/template label mismatch is a classic failure: the Deployment never adopts Pods, so kubectl get pods may show nothing while the Deployment reports unavailable replicas.
Image Pulls and ACR
AKS commonly pulls from Azure Container Registry. Ensure the kubelet identity (managed identity / ACR integration) can pull the image. Manifest-side mistakes—wrong tag, private registry without credentials—surface as ImagePullBackOff or ErrImagePull on the Pod.
Services: Stable Networking for Pods
Pods are ephemeral; their IPs change. A Service selects Pods by label and provides a stable ClusterIP (default), NodePort, or LoadBalancer.
| Service type | Typical use on AKS |
|---|---|
ClusterIP | Internal microservice-to-microservice traffic |
LoadBalancer | Azure Load Balancer front door for TCP/UDP (or HTTP without Ingress) |
NodePort | Expose on each node port (less common as primary public pattern) |
Service YAML highlights:
spec.selectormust match Pod labels from the Deployment templatespec.ports[].portis the Service port clients usespec.ports[].targetPortis the container port
Cluster DNS resolves service-name.namespace.svc.cluster.local. Cross-namespace calls must include the namespace segment or they fail DNS lookup.
Ingress: HTTP(S) Routing
Ingress is not a load balancer by itself—an Ingress controller watches Ingress objects and programs routing. On AKS you may use NGINX Ingress, Application Gateway Ingress Controller (AGIC), or Application Gateway for Containers. The manifest declares hosts, paths, and backend Services:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: inference-ingress
namespace: ml-apps
annotations:
kubernetes.ingress.kubernetes.io/rewrite-target: /
spec:
ingressClassName: nginx
rules:
- host: api.contoso.com
http:
paths:
- path: /predict
pathType: Prefix
backend:
service:
name: inference-api
port:
number: 80
Exam focus: wrong service.name/port, missing Ingress class, or TLS secret misconfiguration causes 404/502 or certificate errors—even when Pods are healthy.
Applying Manifests with kubectl
Declarative apply is the standard workflow:
kubectl apply -f deployment.yaml
kubectl apply -f service.yaml
kubectl apply -f ingress.yaml
# or a directory:
kubectl apply -f ./manifests/
Useful management commands:
| Command | What it does |
|---|---|
kubectl get deploy,svc,ingress -n ml-apps | List core objects |
kubectl describe deploy inference-api -n ml-apps | Events, replicas, conditions |
kubectl rollout status deploy/inference-api -n ml-apps | Wait for rolling update |
kubectl rollout undo deploy/inference-api -n ml-apps | Roll back previous revision |
kubectl delete -f ./manifests/ | Remove resources declared in files |
kubectl apply merges changes; deleting a field from YAML may not remove the live field unless you use server-side apply/prune patterns—know that apply is declarative create-or-update, not a full replace of every unspecified field in older client-side apply habits.
Connect to AKS with az aks get-credentials --resource-group <rg> --name <cluster> so kubectl talks to the correct API server context.
Namespaces: Isolation and Scope
Namespaces partition cluster objects (except cluster-scoped kinds like Nodes and PersistentVolumes). Benefits:
- Separate teams/environments (
dev,staging,prod) - Scope RBAC RoleBindings
- Apply ResourceQuotas and LimitRanges
- Avoid name collisions (
deploy/apican exist in two namespaces)
Create and use:
kubectl create namespace ml-apps
kubectl apply -f deployment.yaml -n ml-apps
Or set metadata.namespace inside each manifest. Forgetting -n applies to default, which is a frequent ops mistake on multi-namespace clusters.
DNS reminder: a Service named redis in namespace cache is reached as redis.cache.svc.cluster.local from other namespaces.
Probes: Liveness and Readiness
Health probes keep Deployments reliable under failure:
| Probe | Effect when it fails |
|---|---|
| Liveness | kubelet restarts the container |
| Readiness | Pod is removed from Service endpoints (no new traffic) |
| Startup (optional) | Delays liveness/readiness until slow apps finish starting |
Probe mechanisms: HTTP GET, TCP socket, or exec command. Configure initialDelaySeconds, periodSeconds, timeoutSeconds, failureThreshold carefully—overly aggressive liveness probes restart healthy-but-slow apps during cold start (common with large ML model containers).
Readiness is what protects users during rolling updates: new Pods join the Service only after they pass readiness. Without readiness, traffic can hit containers that are still loading models.
Example container probe snippet:
readinessProbe:
httpGet:
path: /health/ready
port: 8080
initialDelaySeconds: 5
periodSeconds: 10
livenessProbe:
httpGet:
path: /health/live
port: 8080
initialDelaySeconds: 30
periodSeconds: 20
End-to-End Deploy Mental Model
- Build/push image to ACR
- Write Deployment + Service (+ Ingress) manifests with matching labels and ports
- Create namespace;
kubectl apply -f - Confirm Pods
Runningand Ready; Service has Endpoints; Ingress gets an ADDRESS - Tune probes and replica count; use rollout undo if a bad image ships
Mastering manifests means you can reproduce the same app environment repeatedly—exactly what AKS and the AI-200 skills measure.
A Deployment's Pods are Running, but the ClusterIP Service has no Endpoints and clients receive connection failures. The Service selector is app=inference. What is the most likely cause?
You need external HTTPS clients to reach path /predict on host api.contoso.com, which should forward to an internal ClusterIP Service. Which Kubernetes object primarily expresses that HTTP routing rule on AKS?
During a rolling update of a model-serving container that takes 90 seconds to load weights, users briefly get 5xx errors from Pods that are not ready. Which change best prevents traffic until the app can serve?