When it comes to accessing Azure NetApp Files volumes for Kubernetes applications, there are a few ways to achieve it:
This blog walks you through the options, as well as factors to consider when selecting a persistent volume provisioner.
Before jumping into the specifics, here are some key concepts to remember:
Unless you are looking to create a handful of PVs, a solution that is automated and invoked directly through the Kubernetes plane is what you want. External provisioners such as the NFS Subdir External Provisioner provide Kubernetes and storage admins with the ability to:
So how does it work? Here’s a step-by-step guide on setting it all up. I am working on a 3-node Azure Kubernetes Service (AKS) cluster installed in South Central US.
The NFS Subdir External Provisioner works by creating subdirectories within an NFS server, each of which represents a PV. It requires an “existing and already configured NFS server”. In my case, I am going to:
This isn’t the only way to go. Multiple options exist. Alternatively, you can choose to write an external provisioner.
Deploy the external provisioner by cloning the GitHub repo and following the instructions provided. I am creating a dedicated namespace called “external-provisioner”.
mkdir external-provisioner
cd external-provisioner/
git clone https://github.com/kubernetes-sigs/nfs-subdir-external-provisioner.git
cd nfs-subdir-external-provisioner/
kubectl create ns external-provisioner
NS=$(kubectl config get-contexts|grep -e "^\*" |awk '{print $5}')
NAMESPACE=${NS:-external-provisioner}
sed -i'' "s/namespace:.*/namespace: $NAMESPACE/g" ./deploy/rbac.yaml ./deploy/deployment.yaml
kubectl create -f deploy/rbac.yaml
Edit the deployment.yaml file to add the NFS server IP as well as the path under which PVs will be created. Before this step, let us create an ANF volume that will be used as the NFS server. You can do this using the CLI or the Azure dashboard.
Once the ANF volume has been created, obtain the NFS server IP.
You are now ready to deploy the external provisioner. Go ahead and edit the deploy/deployment.yaml file and make the following change:
cat deploy/deployment.yaml | grep "NFS_SERVER" -A 10
- name: NFS_SERVER
value: 10.0.0.4
- name: NFS_PATH
value: /nfs-server
volumes:
- name: nfs-client-root
nfs:
server: 10.0.0.4
path: /nfs-server
kubectl create -f deploy/deployment.yaml
The last thing to do before deploying applications and creating PVCs is to define a storageClass.
cat deploy/class.yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: external-anf-storage
provisioner: k8s-sigs.io/nfs-subdir-external-provisioner
parameters:
onDelete: "retain"
archiveOnDelete: "false"
kubectl create -f deploy/class.yaml
We are now ready to test it out. With all the pieces in place, it is now time to deploy an application and create a PVC. In this example, PostgreSQL is installed using the Helm chart available here.
curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3chmod 700 get_helm.sh./get_helm.sh
kubectl create ns postgresql
helm repo add azure-marketplace https://marketplace.azurecr.io/helm/v1/repo helm install postgresql --set global.storageClass=external-anf-storage azure-marketplace/postgresql -n postgresql
kubectl get pvc,pods -n postgresql
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
persistentvolumeclaim/data-postgresql-postgresql-0 Bound pvc-500aa086-9461-411a-92aa-3c74a4efae49 8Gi RWO external-anf-storage 3m6s
NAME READY STATUS RESTARTS AGE
pod/postgresql-postgresql-0 1/1 Running 0 3m6s
And there you have it. A running instance of PostgreSQL that writes to a volume created by the external provisioner.
Let’s take a deeper look at how it all works:
Astra Trident offers a dynamic CSI specification compliant storage provisioner for Kubernetes with a rich set of features. It is a storage orchestrator purpose-built for Kubernetes. With 10 CSI compliant storage drivers, it provides a one-stop integration point for storage across NetApp platforms on-premises and in the cloud. For this discussion, we will keep it specific to ANF.
Let’s install it and see how it works!
Installing Trident is easy. You can choose from multiple options. I am using the Trident operator.
wget https://github.com/NetApp/trident/releases/download/v21.10.1/trident-installer-21.10.1.tar.gz
tar xzvf trident-installer-21.10.1.tar.gz
kubectl create ns trident
kubectl create -f trident-installer/deploy/bundle.yaml -n trident
kubectl create -f trident-installer/deploy/crds/tridentorchestrator_cr.yaml
To check that it’s installed:
kubectl get pods -n trident
NAME READY STATUS RESTARTS AGE
trident-csi-6g6mc 2/2 Running 0 61s
trident-csi-7dfb84875-kvr82 6/6 Running 0 61s
trident-csi-8s7f6 2/2 Running 0 61s
trident-csi-rjkmm 2/2 Running 0 61s
trident-operator-68fdbccdb7-gjph7 1/1 Running 0 91s
trident-installer/tridentctl version -n trident
+----------------+----------------+
| SERVER VERSION | CLIENT VERSION |
+----------------+----------------+
| 21.10.1 | 21.10.1 |
+----------------+----------------+
Trident is up and running! Next, we provide the details of the Azure subscription to utilize. Refer to the documentation for detailed instructions.
cat backend-anf.json
{
"version": 1,
"storageDriverName": "azure-netapp-files",
"backendName": "anf-standard",
"location": "southcentralus",
"subscriptionID": "xxxxxxxxxx-xxxx-xxx",
"tenantID": "xxxxxxxxxxxxxxxxxxx",
"clientID": " xxxxxxxxxxxxxxxxxxx ",
"clientSecret": " xxxxxxxxxxxxxxxxxxx ",
"serviceLevel": "Standard",
"virtualNetwork": "aks-vnet-32566518",
"subnet": "anf-subnet"
}
tridentctl create backend -f backend-anf.json -n trident
+--------------+--------------------+--------------------------------------+--------+---------+
| NAME | STORAGE DRIVER | UUID | STATE | VOLUMES |
+--------------+--------------------+--------------------------------------+--------+---------+
| anf-standard | azure-netapp-files | ca468b15-7a7a-4b13-ba03-b90cb1c5cd45 | online | 0 |
+--------------+--------------------+--------------------------------------+--------+---------+
We are almost ready to start using Trident. The last step is to create a StorageClass as shown below.
cat storage-class-anf.yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: trident-anf-standard
provisioner: csi.trident.netapp.io
parameters:
backendType: "azure-netapp-files"
fsType: "nfs"
kubectl create -f storage-class-anf.yaml
With that in place, let us install postgreSQL in a different namespace using Astra Trident.
kubectl create ns postgresql-trident
helm install postgresql-trident --set global.storageClass=trident-anf-standard azure-marketplace/postgresql -n postgresql-trident
kubectl get pods,pvc -n postgresql-trident
NAME READY STATUS RESTARTS AGE
pod/postgresql-trident-postgresql-0 1/1 Running 0 58s
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
persistentvolumeclaim/data-postgresql-trident-postgresql-0 Bound pvc-4789e5ee-a5d4-406a-9ed0-051a60737790 100Gi RWO trident-anf-standard 58s
There are notable differences between Astra Trident and the external subdir provisioner:
Key to every organization is a data fabric. Applications and their associated data must be protected and easily transferable between clusters. For Kubernetes, it boils down to:
Astra Control Service is a fully managed solution that is hosted on Azure by NetApp. It enables Kubernetes admins to:
Astra Trident works in conjunction with Astra Control Service to offer comprehensive data management through a unified control pane.
Here is a table that summarizes the key differentiators.
Factor |
NFS Subdir Provisioner |
Astra Trident |
Volume Snapshots and clones |
Not supported |
Supported |
Volume expansions |
Not supported |
Supported |
Data management (app backup/DR/migration) |
Not supportable |
With Astra Control Service |
Minimum volume size |
1MiB |
100GiB |
Number of used IPs in a VNet |
1 |
Number of volumes created |
Number of volumes per capacity pool |
N/A |
500 [adjustable upon request] |
Throughput limit |
Depends on parent volume size. Shared by constituent volumes |
Depends on volume size. Independent for each volume |
Testing and maintenance |
Community supported |
Open-source and supported by NetApp |
Astra Trident provides a richer set of features and is foundational for application data protection and mobility use cases for business-critical workloads when used with Astra Control Service. The NFS subdir external provisioner is a good fit for basic Kubernetes environments that don’t have strict requirements for secure multi-tenancy, data protection and data mobility. Starting out with the external nfs-provisoner for ANF may seem quick and easy but the limitations can outweigh the benefits fast.
Here are some helpful links: