DEV Community

iapilgrim
iapilgrim

Posted on

AKS RWX Shared Storage Demo

Using Azure Files with Kubernetes (Full Script + Troubleshooting)

If you're running workloads on Azure Kubernetes Service and need multiple pods to read and write the same directory, you need:

ReadWriteMany (RWX) storage

In this tutorial, we’ll:

  • Deploy shared storage using Azure Files
  • Mount it in multiple pods
  • Prove cross-pod writes
  • Cover real-world troubleshooting scenarios

Why RWX Matters

By default, many Kubernetes volumes are:

ReadWriteOnce (RWO)
Enter fullscreen mode Exit fullscreen mode

Meaning:

  • Mounted by only one node at a time.

RWX allows:

  • Multiple pods
  • Across different nodes
  • Simultaneous read/write access

Perfect for:

  • WordPress clusters
  • Shared uploads
  • ML distributed training
  • Batch processing
  • CI runners

Architecture Overview

Pods (2 replicas)
      ↓
PersistentVolumeClaim (RWX)
      ↓
azurefile-csi StorageClass
      ↓
Azure File Share
Enter fullscreen mode Exit fullscreen mode


Prerequisites

  • AKS cluster running
  • kubectl configured
  • Azure File CSI driver enabled (default in modern AKS)

Verify:

kubectl get csidrivers
Enter fullscreen mode Exit fullscreen mode

You should see:

file.csi.azure.com
Enter fullscreen mode Exit fullscreen mode

Also confirm storage class:

kubectl get sc
Enter fullscreen mode Exit fullscreen mode

You should see:

azurefile-csi
Enter fullscreen mode Exit fullscreen mode

Full End-to-End Script

Save as:

rwx-demo.sh
Enter fullscreen mode Exit fullscreen mode

#!/bin/bash

set -e

echo "========================================"
echo "AKS RWX Shared Storage Demo"
echo "========================================"

NAMESPACE="rwx-demo"

echo "1️⃣ Creating namespace..."
kubectl create namespace $NAMESPACE || true

echo "2️⃣ Creating RWX PVC (Azure Files)..."

cat <<EOF | kubectl apply -n $NAMESPACE -f -
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: rwx-demo-pvc
spec:
  accessModes:
    - ReadWriteMany
  storageClassName: azurefile-csi
  resources:
    requests:
      storage: 5Gi
EOF

echo "Waiting for PVC to bind..."

for i in {1..30}; do
  STATUS=$(kubectl get pvc rwx-demo-pvc -n $NAMESPACE -o jsonpath='{.status.phase}')
  if [ "$STATUS" = "Bound" ]; then
    echo "PVC is Bound ✅"
    break
  fi
  echo "Still waiting..."
  sleep 5
done

echo "3️⃣ Deploying 2 writer pods..."

cat <<EOF | kubectl apply -n $NAMESPACE -f -
apiVersion: apps/v1
kind: Deployment
metadata:
  name: rwx-writer
spec:
  replicas: 2
  selector:
    matchLabels:
      app: rwx-writer
  template:
    metadata:
      labels:
        app: rwx-writer
    spec:
      containers:
      - name: writer
        image: busybox
        command: ["/bin/sh", "-c"]
        args:
          - |
            while true; do
              echo "Written by \$(hostname) at \$(date)" >> /shared/output.txt
              sleep 5
            done
        volumeMounts:
        - mountPath: /shared
          name: shared-volume
      volumes:
      - name: shared-volume
        persistentVolumeClaim:
          claimName: rwx-demo-pvc
EOF

echo "Waiting for pods..."
kubectl rollout status deployment/rwx-writer -n $NAMESPACE

echo "4️⃣ Listing pods..."
kubectl get pods -o wide -n $NAMESPACE

echo "5️⃣ Showing shared file content..."
POD=$(kubectl get pod -n $NAMESPACE -l app=rwx-writer -o jsonpath='{.items[0].metadata.name}')
kubectl exec -n $NAMESPACE $POD -- sh -c "sleep 10 && cat /shared/output.txt"

echo ""
echo "========================================"
echo "✅ RWX demo completed successfully!"
echo "========================================"

echo "To clean up:"
echo "kubectl delete namespace $NAMESPACE"
Enter fullscreen mode Exit fullscreen mode

Run the Demo

chmod +x rwx-demo.sh
./rwx-demo.sh
Enter fullscreen mode Exit fullscreen mode

You should see output like:

Written by rwx-writer-xxxx at ...
Written by rwx-writer-yyyy at ...
Enter fullscreen mode Exit fullscreen mode

That proves:

  • Both pods
  • Writing to the same file
  • Across potentially different nodes
  • Backed by Azure Files
  • Using ReadWriteMany

Production Use Cases

Workload Shared Path
WordPress HA /wp-content/uploads
ML training /dataset, /checkpoints
Batch jobs /output
CI runners /workspace

Troubleshooting Guide

1️⃣ PVC Stuck in Pending

Run:

kubectl describe pvc rwx-demo-pvc -n rwx-demo
Enter fullscreen mode Exit fullscreen mode

Check the Events section.

Common causes:

StorageClass name mismatch

Check available classes:

kubectl get sc
Enter fullscreen mode Exit fullscreen mode

Update:

storageClassName: azurefile-csi
Enter fullscreen mode Exit fullscreen mode

2️⃣ Permission / Authorization Errors

If you see:

AuthorizationFailed
Enter fullscreen mode Exit fullscreen mode

AKS identity likely lacks permissions.

Find node resource group:

az aks show \
  --resource-group <rg> \
  --name <cluster> \
  --query nodeResourceGroup -o tsv
Enter fullscreen mode Exit fullscreen mode

Grant Contributor role to AKS identity.


3️⃣ CSI Driver Not Installed

Check:

kubectl get csidrivers
Enter fullscreen mode Exit fullscreen mode

If missing:

az aks update \
  --resource-group <rg> \
  --name <cluster> \
  --enable-azure-file-csi-driver
Enter fullscreen mode Exit fullscreen mode

4️⃣ kubectl wait Timeout

Sometimes kubectl wait misses the transition.

Use polling instead:

kubectl get pvc -n rwx-demo
Enter fullscreen mode Exit fullscreen mode

If STATUS = Bound → provisioning succeeded.


Performance Tips

  • For Linux-only clusters, consider NFS-based Azure Files
  • For high-performance ML or analytics workloads, evaluate Azure NetApp Files
  • Monitor IOPS and throughput for scaling decisions

Final Thoughts

RWX storage unlocks:

  • True HA CMS deployments
  • Distributed batch processing
  • Shared AI datasets
  • Multi-replica CI environments

And with AKS + Azure Files, it’s fully managed and production-ready.

Top comments (0)