All Products
Search
Document Center

Container Service for Kubernetes:Use CNFS to manage isolated NAS volumes (recommended)

Last Updated:Mar 26, 2026

In multi-tenant workloads or any scenario where pods must not share storage, you need per-pod data isolation without provisioning separate NAS file systems. Container Network File System (CNFS) solves this by mapping each directory in a single NAS file system to an independent persistent volume (PV), so different pods mount separate subdirectories and cannot access each other's data.

This topic uses a StatefulSet to walk through creating isolated NAS volumes, verifying that data is mounted correctly, and confirming that writes in one pod are invisible to another.

Prerequisites

Before you begin, ensure that you have:

Component version requirements — verify these if you have an existing cluster:

For a CNFS overview, see CNFS overview. To learn how to manage NAS file systems with CNFS, see Use CNFS to manage NAS file systems (recommended).

How it works

When you set volumeAs: subpath in a StorageClass and reference a CNFS object, the CSI plug-in provisions each persistent volume claim (PVC) as a distinct subdirectory under the NAS file system root. Because each pod mounts a different subdirectory, writes in one pod's /data path are not visible in another pod's /data path — even though all pods share the same underlying NAS file system.

Step 1: Create the workload

First, get the name of your CNFS object:

kubectl get cnfs

The output lists available CNFS objects. Note the name of the one that manages your NAS file system — you will reference it as the value of containerNetworkFileSystem in the StorageClass.

Create a StorageClass named cnfs-nas-sc and a StatefulSet named cnfs-nas-dynamic-sts. The StatefulSet uses volumeClaimTemplates to automatically provision a separate PVC (and therefore a separate NAS subdirectory) for each pod replica.

cat << EOF | kubectl apply -f -
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: cnfs-nas-sc
mountOptions:
  - nolock,tcp,noresvport
  - vers=3
parameters:
  volumeAs: subpath
  containerNetworkFileSystem: cnfs-nas-filesystem # Replace with your CNFS object name.
  path: "/"
  archiveOnDelete: "false"
provisioner: nasplugin.csi.alibabacloud.com
reclaimPolicy: Delete
allowVolumeExpansion: true
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: cnfs-nas-dynamic-sts
  labels:
    app: busybox
spec:
  serviceName: "busybox"
  replicas: 2
  selector:
    matchLabels:
      app: busybox
  template:
    metadata:
      labels:
        app: busybox
    spec:
      containers:
      - name: busybox
        image: busybox
        command: ["/bin/sh"]
        args: ["-c", "sleep 3600;"]
        volumeMounts:
        - mountPath: "/data"
          name: pvc
  volumeClaimTemplates:
  - metadata:
      name: pvc
    spec:
      accessModes: [ "ReadWriteOnce" ]
      storageClassName: "cnfs-nas-sc" # Reference the StorageClass named cnfs-nas-sc.
      resources:
        requests:
          storage: 50Gi
EOF

Key StorageClass parameters:

ParameterDescription
volumeAs: subpathProvisions each PVC as a subdirectory of the NAS file system, enabling per-pod isolation.
containerNetworkFileSystemThe name of the CNFS object that manages your NAS file system. Run kubectl get cnfs to find it.
path: "/"The base path in the NAS file system under which subdirectories are created.
archiveOnDelete: "false"Deletes the NAS subdirectory when the PVC is deleted. Set to "true" to retain the data.
reclaimPolicy: DeleteDeletes the PV when the PVC is deleted.
allowVolumeExpansion: trueAllows you to expand the PVC size after creation.

Step 2: Verify the mount

Run the following command to confirm the NAS volume is mounted in cnfs-nas-dynamic-sts-0:

kubectl exec cnfs-nas-dynamic-sts-0 -- mount | grep nfs

Expected output:

971134b0e8-****.cn-zhangjiakou.nas.aliyuncs.com:/nas-95115c94-2ceb-4a83-b4f4-37bd35df**** on /data type nfs (rw,nosuid,nodev,relatime,user_id=0,group_id=0,default_permissions,allow_other)

The NAS file system is mounted at /data. Each pod in the StatefulSet mounts a different subdirectory, indicated by the unique path suffix in the output.

Step 3: Write data to the volume

To confirm that isolation works, write a test file to cnfs-nas-dynamic-sts-0 and then check whether it appears in cnfs-nas-dynamic-sts-1. Because each pod mounts a separate NAS subdirectory, the file written in one pod must not be visible in the other.

Write a 1 GB temporary file to /data in cnfs-nas-dynamic-sts-0:

kubectl exec cnfs-nas-dynamic-sts-0 -ti -- sh -c 'dd if=/dev/zero of=/data/1G.tmpfile bs=1G count=1;'

Verify the file exists in cnfs-nas-dynamic-sts-0:

kubectl exec cnfs-nas-dynamic-sts-0 -- ls -arlth /data

Expected output:

total 1G
-rw-r--r--    1 root     root        1.0G Dec 15 12:11 1G.tmpfile

Step 4: Confirm isolation between pods

Run the following command to check whether the file appears in cnfs-nas-dynamic-sts-1:

kubectl exec cnfs-nas-dynamic-sts-1 -- ls -arlth /data

Expected output:

sh-4.4# ls -arlth
total 8.0K
drwxr-xr-x 1 root root 4.0K Dec 15 18:07 ..
drwxr-xr-x 2 root root 4.0K Dec 15 18:07 .

The directory is empty. Together, steps 3 and 4 confirm that cnfs-nas-dynamic-sts-0 and cnfs-nas-dynamic-sts-1 write to isolated NAS subdirectories — data written in one pod is not visible in the other.

What's next