Introduction
Understand how OpenEBS provides Kubernetes-native persistent storage on Azure
Create an Arm64 virtual machine powered by Azure Cobalt 100
Deploy OpenEBS on an Arm-based virtual machine
Validate persistent storage with OpenEBS on an Arm-based virtual machine
Allow access to the OpenEBS application on Azure
Next Steps
In this section, you’ll create a PersistentVolumeClaim (PVC), deploy a stateful NGINX application, and validate persistent storage behavior using OpenEBS LocalPV.
You’ll verify that data persists on the single-node cluster even after the application pod is deleted and recreated.
Create a PersistentVolumeClaim (PVC) manifest:
cat > pvc.yaml <<EOF
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: openebs-pvc
spec:
storageClassName: openebs-hostpath
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 5Gi
EOF
Apply the PVC:
kubectl apply -f pvc.yaml
The output is similar to:
persistentvolumeclaim/openebs-pvc created
Verify that the PVC was created successfully:
kubectl get pvc
The output is similar to:
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS VOLUMEATTRIBUTESCLASS AGE
openebs-pvc Bound pvc-4784909a-837e-457d-90aa-0aa6867f26de 5Gi RWO openebs-hostpath <unset> 134m
The PVC is dynamically provisioned by OpenEBS LocalPV.
Create the deployment manifest:
cat > nginx-openebs.yaml <<EOF
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-openebs
spec:
replicas: 1
selector:
matchLabels:
app: nginx-openebs
template:
metadata:
labels:
app: nginx-openebs
spec:
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80
volumeMounts:
- name: openebs-storage
mountPath: /usr/share/nginx/html
volumes:
- name: openebs-storage
persistentVolumeClaim:
claimName: openebs-pvc
EOF
Deploy the application:
kubectl apply -f nginx-openebs.yaml
The output is similar to:
deployment.apps/nginx-openebs created
Check the pod status:
kubectl get pods
The output is similar to:
NAME READY STATUS RESTARTS AGE
nginx-openebs-84d6bfddd4-6rf5v 1/1 Running 0 133m
Check the PVC:
kubectl get pvc
The output is similar to:
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS VOLUMEATTRIBUTESCLASS AGE
openebs-pvc Bound pvc-4784909a-837e-457d-90aa-0aa6867f26de 5Gi RWO openebs-hostpath <unset> 136m
Check the persistent volume:
kubectl get pv
The output is similar to:
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS VOLUMEATTRIBUTESCLASS REASON AGE
pvc-4784909a-837e-457d-90aa-0aa6867f26de 5Gi RWO Delete Bound default/openebs-pvc openebs-hostpath <unset> 134m
The output confirms that the persistent volume has been dynamically created and attached.
Get the pod name:
POD=$(kubectl get pod -l app=nginx-openebs -o jsonpath='{.items[0].metadata.name}')
Write test data into the mounted volume:
kubectl exec -it $POD -- sh -c 'echo "OpenEBS on Azure Cobalt D4ps Arm64" > /usr/share/nginx/html/index.html'
Verify the data:
kubectl exec -it $POD -- cat /usr/share/nginx/html/index.html
The output is similar to:
OpenEBS on Azure Cobalt D4ps Arm64
Delete the NGINX pod:
kubectl delete pod -l app=nginx-openebs
Wait for Kubernetes to recreate the pod:
kubectl get pods -w
Press Ctrl + C after the new pod reaches the Running state.
Get the new pod name:
NEW_POD=$(kubectl get pod -l app=nginx-openebs -o jsonpath='{.items[0].metadata.name}')
Verify the data again:
kubectl exec -it $NEW_POD -- cat /usr/share/nginx/html/index.html
The output is similar to:
OpenEBS on Azure Cobalt D4ps Arm64
This response confirms that the persistent volume retains data on the single-node cluster even after the pod is deleted and recreated.
Create a NodePort service to expose the NGINX application externally:
kubectl expose deployment nginx-openebs \
--type NodePort \
--port 80
Verify the service and note the NodePort assigned:
kubectl get svc
The output is similar to:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.x.x.x <none> 443/TCP 143m
nginx-openebs NodePort 10.x.x.x <none> 80:31635/TCP 7s
Note the NodePort value (in this example 31635). You’ll need it to create the Azure firewall rule in the next section. Your value might differ because Kubernetes assigns NodePorts dynamically.
You’ve now successfully created dynamically provisioned persistent volumes using OpenEBS LocalPV on a single-node Kubernetes cluster running on an Arm-based Azure VM.
You’ve also validated persistent storage functionality by recreating application pods while preserving data across restarts, and exposed the application as a Kubernetes NodePort service.
Next, you’ll open the NodePort in the Azure Network Security Group so the application is reachable from your browser.