Skip to content
AI-200 Learn

Attach persistent storage to an app

Persistent storage on AKS for AI-200: PVs, PVCs, built-in CSI storage classes, Azure Disk vs Azure Files access modes, reclaim policy and mounting.

What this covers

Container filesystems are ephemeral: anything written inside a container disappears when the Pod restarts or moves to another node. AI services often need durable data such as cached model artifacts, embeddings, or conversation state. Kubernetes solves this with PersistentVolumes (PVs) and PersistentVolumeClaims (PVCs); on AKS, CSI drivers create the Azure Disk, Azure Files or Blob resource behind the claim automatically. This page covers choosing a storage class, writing the claim, mounting it, and the access-mode mistakes the exam likes to test.

Exam weight: Develop containerized solutions on Azure (20–25%)

Skills measured

  • "Deploy and manage applications to Azure Kubernetes Service (AKS) by using manifest files"

Key concepts

PV, PVC and StorageClass

  • A PersistentVolumeClaim is the app's request: size, access mode and storageClassName.
  • A StorageClass describes how to provision: CSI driver, SKU, reclaim policy, binding mode, expansion.
  • A PersistentVolume is the actual piece of storage. With dynamic provisioning, the CSI driver creates it (and the Azure resource) when the claim is made; the claim then shows Bound.

Access modes

ModeShortMeaning
ReadWriteOnceRWORead-write by Pods on one node
ReadOnlyManyROXRead-only from many nodes
ReadWriteManyRWXRead-write from many nodes
ReadWriteOncePodRWOPRead-write by exactly one Pod

Azure Disk is block storage attached to one VM, so it supports RWO only. Azure Files (SMB or NFS) mounts on many nodes at once, so it supports RWX.

Built-in AKS storage classes

Storage classBacking storageAccess modeUse case
default / managed-csiAzure Disk, Standard SSDRWOCost-efficient single-Pod state, small databases
managed-csi-premiumAzure Disk, Premium SSDRWOLow-latency, I/O-heavy single-Pod workloads
azurefile-csiAzure Files, StandardRWXShared config, logs, content across Pods
azurefile-csi-premiumAzure Files, PremiumRWXShared access needing low latency

The class named default is the cluster default (Azure Disk, Standard SSD), so a PVC without storageClassName gets an Azure Disk. Built-in classes use reclaimPolicy: Delete (deleting the PVC deletes the Azure disk or share) and allow volume expansion. Disk classes use WaitForFirstConsumer, so the disk is created in the zone where the Pod lands. Blob classes (azureblob-fuse-premium, azureblob-nfs-premium) suit large unstructured datasets.

Azure Container Storage

Beyond CSI drivers, Azure Container Storage is a managed, container-native storage service using NVMe-oF for fast attach and detach, which shortens Pod failover for I/O-intensive stateful workloads. Choose it for performance-critical stateful apps; choose CSI classes for general-purpose needs.

How it works

Diagram source: flowchart LR PVC[PVC data-pvc 10Gi RWO] --> SC[StorageClass managed-csi] SC -->|Azure Disk CSI driver| D[Azure managed disk] D --> PV[PersistentVolume] PV -->|Bound| PVC PVC -->|volumes.persistentVolumeClaim| POD[Pod /app/data]

The claim:

YAML
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: data-pvc
spec:
  accessModes:
  - ReadWriteOnce
  resources:
    requests:
      storage: 10Gi
  storageClassName: default

Mounting it in a Deployment:

YAML
apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-api
spec:
  replicas: 1                 # RWO disk: keep to one Pod (see Exam traps)
  strategy:
    type: Recreate            # release the disk before the new Pod starts
  selector:
    matchLabels:
      app: web-api
  template:
    metadata:
      labels:
        app: web-api
    spec:
      volumes:
      - name: data-volume
        persistentVolumeClaim:
          claimName: data-pvc
      containers:
      - name: api
        image: myregistry.azurecr.io/web-api:v1
        volumeMounts:
        - name: data-volume
          mountPath: /app/data

The Learn unit's example uses replicas: 2 with this RWO claim. That works only while both Pods land on the same node; a Pod scheduled elsewhere fails with a Multi-Attach error. For several replicas, use azurefile-csi (RWX) or a StatefulSet with volumeClaimTemplates so each replica gets its own disk.

Hands-on

Azure portal

  1. Open the cluster > Kubernetes resources > Storage to see storage classes, PVCs and PVs.
  2. Select Create > Apply a YAML, paste pvc.yaml, and select Add.
  3. Apply the Deployment in Workloads.
  4. Return to Storage > Persistent volume claims and confirm the status is Bound.

Azure CLI

Azure CLI / Bash
kubectl get storageclass
kubectl apply -f pvc.yaml
kubectl apply -f deployment.yaml
kubectl describe pvc data-pvc            # Status: Bound, Volume: pvc-...
kubectl describe pod -l app=web-api      # Volumes / mount events
kubectl get pv

# Test persistence: write, delete the Pod, read again
POD=$(kubectl get pod -l app=web-api -o jsonpath='{.items[0].metadata.name}')
kubectl exec $POD -- sh -c 'echo hello > /app/data/test.txt'
kubectl delete pod $POD
kubectl wait --for=condition=Ready pod -l app=web-api --timeout=120s
POD=$(kubectl get pod -l app=web-api -o jsonpath='{.items[0].metadata.name}')
kubectl exec $POD -- cat /app/data/test.txt

# Grow the volume (class must allow expansion)
kubectl patch pvc data-pvc -p '{"spec":{"resources":{"requests":{"storage":"20Gi"}}}}'

Python

Python
# pip install kubernetes
from kubernetes import client, config

config.load_kube_config()
v1 = client.CoreV1Api()

pvc = client.V1PersistentVolumeClaim(
    metadata=client.V1ObjectMeta(name="shared-pvc"),
    spec=client.V1PersistentVolumeClaimSpec(
        access_modes=["ReadWriteMany"],
        storage_class_name="azurefile-csi",
        resources=client.V1VolumeResourceRequirements(requests={"storage": "100Gi"}),
    ),
)
v1.create_namespaced_persistent_volume_claim("default", pvc)
print(v1.read_namespaced_persistent_volume_claim("shared-pvc", "default").status.phase)

Exam traps

RequirementChoose
One Pod, low latency, database-style I/Omanaged-csi-premium (Azure Disk, RWO)
Many Pods on different nodes share filesazurefile-csi (Azure Files, RWX)
Each replica needs its own diskStatefulSet + volumeClaimTemplates
Huge unstructured datasetsAzure Blob CSI classes
Fastest failover for stateful workloadsAzure Container Storage
Keep the disk after the PVC is deletedCustom StorageClass with reclaimPolicy: Retain

Quick review

  • Container filesystems are ephemeral; PVCs survive Pod restarts and rescheduling.
  • PVC = request; StorageClass = how; PV = the actual volume.
  • default/managed-csi = Standard SSD disk; -premium = Premium SSD.
  • Azure Disk → RWO; Azure Files → RWX.
  • Built-in classes reclaim with Delete and allow expansion.
  • kubectl describe pvc should show Bound.
  • Mount via volumes[].persistentVolumeClaim.claimName + volumeMounts[].mountPath.

Practice

Practice: AKS manifest questions

Official references