Skip to content
CAMPUX Cloud Bootcamp Lab · Class 27d · AKS ← All labs
Hands-On Lab · Beginner
~20 min · Free control plane · Cloud Shell
AKS & kubectl · torn down
Class 27d · Storage

Delete the pod. The file stays.

Write a file through a disk-backed claim, delete its pod, and read the same file from a new pod. Then mount that claim from two pods on this one-node cluster. The result shows why ReadWriteOnce means one node, not one pod.

Fig. 1 · The claim outlives the pod
A PersistentVolumeClaim on Azure Disk outlives the pod that mounts it — a replacement pod reads back what the deleted pod wrote. PVC Azure Disk pod (v1) writes note.txt pod (v2) reads note.txt same disk, same file
Start

Run one step, then check it

Read the step before copying. Bash commands belong in Git Bash on Windows or Azure Cloud Shell set to Bash; PowerShell uses different syntax. A JSON, YAML, Bicep or application-code example belongs in the named file, not directly at the terminal prompt. Follow any shell-specific instructions below.

Keep the same terminal open so earlier variables remain available. Copy one complete command block without the terminal's $ prompt. A backslash continues a command onto the next line. If Bash shows a lone >, it is waiting for the rest of a quote, command or file block. Finish the complete block; if the paste was incomplete, press Ctrl+C and copy it again. Do not paste the next step into an unfinished command.

A line such as RG="training-group" stores a value without printing it. Output captured with $(...) is also stored; a blank screen alone does not prove failure. A sleep deliberately waits, and -o none suppresses normal output. Wait for your normal prompt, then run the step's checkpoint. After an error, stop and keep the exact command and message; later steps cannot repair a missing resource. Never share passwords, access tokens or secret values in a screenshot.

Why

Pods are disposable. Some of what they touch is not.

Delete a pod and its container's writable layer goes with it. An emptyDir survives a container restart inside the same pod but disappears when the pod is removed. To keep this lab's file across pod replacement, create a separate PersistentVolumeClaim (PVC) backed by an Azure Disk through the managed-csi StorageClass. You will write a file, delete the pod, and read it from a new one. Then two pods on this single node will mount the same claim: ReadWriteOnce limits read-write access to one node, not one pod.

Replace the pod. Keep the claim.

Before you begin — one-time setup

You need a free Azure account and the Azure CLI (az), signed in with az login. First time? The 15-minute Set up your machine page covers the account, the installs, and sign-in. Prefer zero installs? Run everything in Azure Cloud Shell (Bash) — az and kubectl are preinstalled and already signed in.

Cost & teardown

This lab uses the cluster from Your first AKS cluster if it still exists; otherwise Step 1 recreates it. The AKS control plane is on the Free tier, but the node, disk, and other Azure resources can incur charges. Disk billing depends on the provisioned tier and size, not simply the requested 1Gi. Deleting a pod does not delete the claim. The teardown removes the PVC and resource group; verify both the cluster group and its managed node group are gone.

Step 1

The cluster

If you still have the cluster from Your first AKS cluster, skip to get-credentials. Otherwise recreate it with the identical command.

# Windows/Git Bash: stop it mangling /subscriptions/... arguments (harmless on macOS/Linux)
export MSYS_NO_PATHCONV=1

RG="campux-lab-aks-rg"
az group create -n "$RG" -l eastus

# same command as the first-cluster lab: free control plane, one small node
# if Azure says this size "is not allowed in your subscription", the same error lists the sizes
# that are; pick a 2-vCPU one from that list (Standard_D2as_v4 worked for us in October 2026)
az aks create -n campux-aks -g "$RG" \
  --tier free \
  --node-count 1 \
  --node-vm-size Standard_D2as_v4 \
  --enable-managed-identity \
  --generate-ssh-keys

az aks get-credentials -n campux-aks -g "$RG"
kubectl get nodes
kubectl get storageclass
Checkpoint kubectl get storageclass lists managed-csi among the built-in classes. The default marker may be on another class; this lab names managed-csi explicitly. If the cluster was not created by this lab, verify the selected context with kubectl config current-context before creating anything.
Step 2

A PersistentVolumeClaim, backed by an Azure Disk

Request 1Gi through the built-in disk class, then mount the claim into a pod at /data. Azure may provision and bill a larger disk tier than the requested capacity.

kubectl create namespace storage-demo

cat > pvc.yaml <<'EOF'
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: demo-pvc
  namespace: storage-demo
spec:
  accessModes:
    - ReadWriteOnce
  storageClassName: managed-csi
  resources:
    requests:
      storage: 1Gi
EOF

kubectl apply -f pvc.yaml
kubectl get pvc demo-pvc -n storage-demo   # STATUS: Pending
Checkpoint The claim may show Pending until a pod uses it if the StorageClass has WaitForFirstConsumer binding. Check with kubectl get storageclass managed-csi -o yaml; a different binding mode may make it Bound sooner. Step 3 verifies the final binding.
Step 3

Write a file, then delete the pod

Run a pod that mounts the claim, write a file to it, confirm the claim is now Bound, then delete the pod outright.

This block includes a deliberate wait. Leave this terminal open until the normal prompt returns; a wait is not proof that access has propagated.

cat > pod-v1.yaml <<'EOF'
apiVersion: v1
kind: Pod
metadata:
  name: writer
  namespace: storage-demo
spec:
  containers:
  - name: app
    image: busybox:1.28
    command: ["sh", "-c", "echo 'the disk remembers this' > /data/note.txt && sleep 3600"]
    volumeMounts:
    - name: data
      mountPath: /data
  volumes:
  - name: data
    persistentVolumeClaim:
      claimName: demo-pvc
EOF

kubectl apply -f pod-v1.yaml
kubectl wait --for=condition=Ready pod/writer -n storage-demo --timeout=120s
kubectl get pvc demo-pvc -n storage-demo
kubectl exec writer -n storage-demo -- cat /data/note.txt
Checkpoint demo-pvc now reads STATUS: Bound, and cat prints the disk remembers this. Now delete the pod and confirm it is really gone before moving on.
kubectl delete pod writer -n storage-demo
kubectl get pod writer -n storage-demo   # -> Error from server (NotFound)
Step 4

The replacement reads it back

Start a new pod — different name, does not write anything — that mounts the same claim and reads the file the deleted pod left behind.

This block includes a deliberate wait. Leave this terminal open until the normal prompt returns; a wait is not proof that access has propagated.

cat > pod-v2.yaml <<'EOF'
apiVersion: v1
kind: Pod
metadata:
  name: reader
  namespace: storage-demo
spec:
  containers:
  - name: app
    image: busybox:1.28
    command: ["sh", "-c", "sleep 3600"]
    volumeMounts:
    - name: data
      mountPath: /data
  volumes:
  - name: data
    persistentVolumeClaim:
      claimName: demo-pvc
EOF

kubectl apply -f pod-v2.yaml
kubectl wait --for=condition=Ready pod/reader -n storage-demo --timeout=120s
kubectl exec reader -n storage-demo -- cat /data/note.txt
Checkpoint cat prints the disk remembers this — a pod that never wrote the file reads back exactly what a now-deleted pod wrote. The PVC, and the Azure Disk behind it, never went away; only the pod referencing it did.
What just happened

Deleting a pod also removes its container's writable layer, but it leaves this separate PVC in place. The claim remains bound to a PV backed by an Azure managed disk. A new pod that references claimName: demo-pvc can mount that disk and read the same bytes, provided the claim and backing resource still exist. Deleting the PVC is different; its reclaim policy governs what happens to the disk.

Step 5

ReadWriteOnce means one node, not one pod

With reader still running and holding the claim, try to schedule a second pod that mounts the same PVC.

This block includes a deliberate wait. Leave this terminal open until the normal prompt returns; a wait is not proof that access has propagated.

cat > pod-v3.yaml <<'EOF'
apiVersion: v1
kind: Pod
metadata:
  name: second-reader
  namespace: storage-demo
spec:
  containers:
  - name: app
    image: busybox:1.28
    command: ["sh", "-c", "sleep 3600"]
    volumeMounts:
    - name: data
      mountPath: /data
  volumes:
  - name: data
    persistentVolumeClaim:
      claimName: demo-pvc
EOF

kubectl apply -f pod-v3.yaml
kubectl get pod second-reader -n storage-demo -w   # Ctrl-C once it stops changing
Checkpoint Stop the watch with Ctrl-C, then run kubectl get pods reader second-reader -n storage-demo -o wide. On this one-node cluster both pods should show the same NODE, and second-reader can reach Running. Check the shared file with kubectl exec second-reader -n storage-demo -- cat /data/note.txt. That observable result demonstrates the easy-to-miss point: RWO is a one-node access mode, not a one-pod lock. This one-node lab cannot demonstrate a cross-node attach failure; it would require another node and a controlled placement test.
What just happened

Two pods on the same node can mount this RWO disk. Do not let both write to the same data files unless the application is designed for it. If a workload needs a shared filesystem across nodes, evaluate Azure Files with RWX. If it needs exactly one pod to mount a volume, RWO alone does not enforce that; evaluate ReadWriteOncePod where the driver supports it, plus the workload's own safety controls.

kubectl delete pod reader second-reader -n storage-demo
Down

Tear it down

Delete the pods first, then the PVC and namespace. The built-in class normally uses a Delete reclaim policy, but confirm the disk is gone. The final group deletion also removes the cluster used by the first-cluster lab; skip it if you deliberately want to retain that cluster and accept its ongoing charges.

kubectl delete pvc demo-pvc -n storage-demo
kubectl delete namespace storage-demo

az group delete -n campux-lab-aks-rg --yes --no-wait
az group exists -n campux-lab-aks-rg      # -> false once complete
Checkpoint Confirm in the portal that the managed disk backing demo-pvc is gone (search "Disks" in your resource group before it disappears with the group), and that both the cluster's resource group and its auto-managed node group (named like MC_campux-lab-aks-rg_campux-aks_eastus) are gone.
End

What you can now honestly claim

You created a PVC backed by Azure Disk, wrote a file, deleted its pod, and read the same file from a new pod. You also mounted the claim from two pods on the same node, showing that RWO is a node limit rather than a one-pod lock. This single-node exercise does not test what happens when a second node requests the disk.