--- title: "VAST CSI Driver Deployment on Amazon EKS" slug: "vast-csi-driver-deployment-on-amazon-eks" description: "Learn to deploy and manage the VAST CSI driver on AWS EKS, covering authentication, storage classes, and NFS connectivity for optimal performance." updated: 2026-10-28T02:14:35Z published: 2026-10-28T02:14:35Z canonical: "docs.vastdata.com/vast-csi-driver-deployment-on-amazon-eks" --- > ## Documentation Index > Fetch the complete documentation index at: https://docs.vastdata.com/llms.txt > Use this file to discover all available pages before exploring further. # VAST CSI Driver Deployment on Amazon EKS ## Objective > [!NOTE] > This procedure was written to provide a clear set of instructions for deploying, managing, and using the Vast CSI driver within the AWS EKS cluster. > > This procedure covers both **RWX / ReadWriteMany** StorageClass > > Topics covered in this procedure: > > - AWS SSO authentication > - Validate the EKS cluster > - Installing VAST CSI using Helm > - Enable Snapshot CRD > - Create VAST StorageClass > - Validated PVC and pod status > - NFS mount and I/O instructions > - Cleanup and uninstall ## Prerequisites Before starting, verify that the required tools are installed: ```plaintext awscli eksctl kubectl helm ``` Required access and information: | **Elements** | **Values used in this LB** | | --- | --- | | AWS profile | `AWS-Polaris-Test` | | AWS region | `us-east-1` | | AWS account ID | `xxxxxxxxxxxx` | | EKS cluster | Created and running | | Worker nodes | 3 EKS managed worker nodes | | VAST management endpoint | Example: `10.102.28.4` | | VAST NFS VIP / VIP pool | Example VIP: `10.102.14.237`, VIP pool: `protocolsPool` | | VAST credentials | Required for CSI secret | | VAST view/path | Example: `CSIVIEW` | | Network access | EKS worker nodes must reach VAST management and NFS VIPs | ### EKS and environmental preparations If you are using the `.aws/credentials` file AWS SSO profile, make sure to have a configuration based on the below complied with your actual details: ```plaintext [profile AWS-Polaris-Test] sso_start_url = https://identitycenter.amazonaws.com/ssoins-xxxxxxxxxxxxxxx sso_region = us-east-1 sso_account_id = xxxxxxxxxxxx sso_role_name = AWS-Polaris-Test region = us-east-1 output = json ``` ## Set working environment variables Define the variables below in your shell before moving forward. ```plaintext export AWS_PROFILE=AWS-Polaris-Test export AWS_REGION=us-east-1 export EKS_CLUSTER_NAME=eks-solutions-poc-v3 export EKS_NODEGROUP_NAME=eks-solutions-poc-eks-workers export VAST_MGMT_ENDPOINT=10.102.28.4 export VAST_NFS_VIP=10.102.14.237 export VAST_VIP_POOL=protocolsPool export VAST_VIEW_PATH=CSIVIEW export VAST_VIEW_POLICY=default ``` **Note**: `VAST_MGMT_ENDPOINT` is the VAST management/API endpoint used by the CSI driver. `VAST_NFS_VIP` is used only for validating NFS connectivity from the EKS worker nodes. The actual NFS mount VIP used by the pod may be selected dynamically from the configured VAST VIP pool. ### Identify the VAST Management Endpoint Run the below command: ```plaintext vastcloud cluster list ``` Example output: ```plaintext ╭──────────────────────┬─────────┬────────────┬─────────────────────┬─────────────┬──────────╮ │ name                 │ state   │ ip address │ management url      │ monitor url │ provider │ ├──────────────────────┼─────────┼────────────┼─────────────────────┼─────────────┼──────────┤ │ voc-aws-eks-test     │ running │            │ https://10.102.28.4 │             │ aws      │ ╰──────────────────────┴─────────┴────────────┴─────────────────────┴─────────────┴──────────╯ ``` In this example, we used the following parameters: | **Field** | **Value** | | --- | --- | | VAST cluster name | voc-aws-eks-test | | Cluster state | running | | Management URL | `https://10.102.28.4` | | Management endpoint for CSI | `10.102.28.4` | | Provider | aws | The CSI Helm endpoint parameter should point to the VAST management endpoint: ```plaintext --set endpoint=${VAST_MGMT_ENDPOINT} ``` The NFS mount traffic should use the relevant VAST-VIP pool and VIPs that are reachable from the EKS worker nodes. ## Identify the VAST NFS VIP / VIP Pool `VAST_NFS_VIP` should be taken from the VAST VIP pool configured for the cluster. In our example: ```plaintext export VAST_NFS_VIP=10.102.14.237 export VAST_VIP_POOL=protocolsPool ``` Use this VIP to validate that EKS worker nodes can reach the VAST data path over NFS. ## AWS and EKS Networking Requirements EKS worker nodes must have network connectivity to the VAST cluster. Before proceeding, please verify that the following are compared: | **Source** | **Destination** | **Port** | **Purpose** | | --- | --- | --- | --- | | EKS worker node security group | VAST NFS VIPs | `2049/TCP` | NFS data traffic | | EKS worker node security group | VAST management endpoint | `443/TCP` | VAST API / management | | EKS worker node security group | VAST management endpoint | `12345/TCP`, if used | VAST management/API access depending on environment | #### Pro tips: > [!TIP] > - If EKS nodes are deployed in private subnets, routing must exist between the EKS VPC/subnets and the VAST network. > - Security groups, NACLs, firewalls, and routing tables must allow traffic from the EKS worker nodes to the VAST data VIPs and management endpoint. > - DNS resolution is optional if IP addresses are used directly, but required if using FQDNs. > - The EKS VPC CIDR or worker node subnet CIDRs must be allowed in the relevant VAST View Policy. Run basic validation using the commands below from an EKS worker node: ```plaintext nc -vz ${VAST_MGMT_ENDPOINT} 443 nc -vz ${VAST_NFS_VIP} 2049 ``` Expected result: ```plaintext Connection to 10.102.28.4 port 443 [tcp/https] succeeded! Connection to 10.102.14.237 port 2049 [tcp/nfsd] succeeded! ``` At this point should should be ready to deploy the EKS cluster and configure the Vast-CSI driver. ## Create ESK cluster ### Step 1 - AWS Authentication Login with AWS SSO: ```plaintext aws sso login --profile ${AWS_PROFILE} ``` Validate access: ```plaintext aws sts get-caller-identity --profile ${AWS_PROFILE} ``` Expected results: ```plaintext {  "UserId": "AROARTN2ZMSY4WUDBTRWL:vast.user@vastdata.com",  "Account": "xxxxxxxxxxxx",  "Arn": "arn:aws:sts::xxxxxxxxxxxx:assumed-role/AWSReservedSSO_AWS-Polaris-Test_aaf44d356dcb8d5b/vast.user@vastdata.com" } ``` ### Step 2 - EKS Cluster Deployment Example Create the following `cluster.yaml` file. ```yaml apiVersion: eksctl.io/v1alpha5 kind: ClusterConfig metadata:  name: eks-solutions-poc-v3  region: us-east-1 vpc:  id: "vpc-090f788c17996b6cd"  securityGroup: "sg-0bdb7e6ea502e3cb6"  sharedNodeSecurityGroup: "sg-0bdb7e6ea502e3cb6"  manageSharedNodeSecurityGroupRules: false  clusterEndpoints:    publicAccess: true    privateAccess: true  subnets:    private:      us-east-1a:        id: "subnet-087df6d7c877a44c6"      us-east-1b:        id: "subnet-05b4de7ad0272d1ed"      us-east-1c:        id: "subnet-05dab919771df638f" iam:  serviceRoleARN: "arn:aws:iam::xxxxxxxxxxxx:role/eks-cluster-role" managedNodeGroups:  - name: eks-solutions-poc-eks-workers    instanceType: m5.large    minSize: 1    maxSize: 5    desiredCapacity: 3    privateNetworking: true    iam:      instanceRoleARN: "arn:aws:iam::xxxxxxxxxxxx:role/eks-nodegroup-role"    securityGroups:      attachIDs:        - "sg-0bdb7e6ea502e3cb6" ``` Create the EKS cluster by running the command below: ```plaintext eksctl create cluster -f cluster.yaml --profile ${AWS_PROFILE} ``` This will create: | **Element** | **Value** | | --- | --- | | EKS cluster name | `eks-solutions-poc-v3` | | Region | `us-east-1` | | AWS profile | `AWS-Polaris-Test` | | Node group | `eks-solutions-poc-eks-workers` | | Desired worker nodes | 3 | | Minimum worker nodes | 1 | | Maximum worker nodes | 5 | | Node type | `m5.large` | | Node group type | Managed node group | ### Step 3 - Validate EKS Cluster and Access #### 3.1 Confirmation Run the below command to view the cluster, and it’s state. ```plaintext aws eks describe-cluster \  --name ${EKS_CLUSTER_NAME} \  --region ${AWS_REGION} \  --profile ${AWS_PROFILE} \  --query 'cluster.{Name:name,Status:status,Endpoint:endpoint,Version:version}' \  --output table ``` Expected results: ```plaintext --------------------------------------------------------------------------------------------------------------------------- |                                                     DescribeCluster                                                     | +---------------------------------------------------------------------------+-----------------------+---------+-----------+ |                                 Endpoint                                  |         Name          | Status  |  Version  | +---------------------------------------------------------------------------+-----------------------+---------+-----------+ |  https://E2D351D212805F5F064120B6508CF901.gr7.us-east-1.eks.amazonaws.com |  eks-solutions-poc-v3 |  ACTIVE |  1.34     | +---------------------------------------------------------------------------+-----------------------+---------+-----------+ ``` #### 3.2 Fetch kubeconfig Credentials ```plaintext aws eks update-kubeconfig \  --name ${EKS_CLUSTER_NAME} \  --region ${AWS_REGION} \  --profile ${AWS_PROFILE} ``` #### 3.3 Verify kubectl Connectivity ```plaintext kubectl cluster-info kubectl get nodes -o wide ``` Expected results: ```plaintext 3 worker nodes in Ready state ``` ## VAST CSI driver ### Step 1 - Create Namespace ```plaintext kubectl create namespace vast-csi ``` Verify: ```plaintext kubectl get namespace vast-csi ``` Expected results: ```plaintext NAME       STATUS   AGE vast-csi   Active   12s ``` ### Step 2 - Add VAST CSI Helm Repository ```plaintext helm repo add vastcsi https://vast-data.github.io/vast-csi helm repo update ``` Verify: ```plaintext helm search repo vastcsi ``` ### Step 3 - Create VAST Credentials Secret The CSI driver requires credentials to communicate with the VAST management endpoint. For lab use, you can create the secret interactively without exposing the password in shell history: ```plaintext read -s -p "Enter VAST password: " VAST_PASS echo kubectl -n vast-csi create secret generic vastsecret \  --from-literal=username=admin \  --from-literal=password="${VAST_PASS}" unset VAST_PASS ``` Verify: ```plaintext kubectl -n vast-csi get secret vastsecret ``` Expected results: ```plaintext NAME         TYPE     DATA   AGE vastsecret   Opaque   2      60m ``` **Security note**: For lab use, creating the secret directly from the command line is acceptable. In production environments, avoid storing passwords in shell history. Use a secure secret management workflow, such as: - AWS Secrets Manager - External Secrets Operator - Sealed Secrets - Controlled CI/CD secret injection - Kubernetes secret encryption at rest ### Step 4 - Install Snapshot CRDs Install the snapshot CRDs once per Kubernetes cluster: ```plaintext kubectl apply -f https://raw.githubusercontent.com/kubernetes-csi/external-snapshotter/v6.0.1/client/config/crd/snapshot.storage.k8s.io_volumesnapshotclasses.yaml kubectl apply -f https://raw.githubusercontent.com/kubernetes-csi/external-snapshotter/v6.0.1/client/config/crd/snapshot.storage.k8s.io_volumesnapshotcontents.yaml kubectl apply -f https://raw.githubusercontent.com/kubernetes-csi/external-snapshotter/v6.0.1/client/config/crd/snapshot.storage.k8s.io_volumesnapshots.yaml ``` Verify: ```plaintext kubectl get crd | grep volumesnapshot ``` Expected results: ```plaintext volumesnapshotclasses.snapshot.storage.k8s.io    2026-05-18T09:33:15Z volumesnapshotcontents.snapshot.storage.k8s.io   2026-05-18T09:33:40Z volumesnapshots.snapshot.storage.k8s.io          2026-05-18T09:33:51Z ``` ### Step 5 - Optional: Create VolumeSnapshotClass If Kubernetes snapshots are required, create a `VolumeSnapshotClass `for the VAST CSI driver. ```plaintext kubectl apply -f - <<'YAML' apiVersion: snapshot.storage.k8s.io/v1 kind: VolumeSnapshotClass metadata:  name: vast-snapshot-class driver: csi.vastdata.com deletionPolicy: Delete YAML ``` Verify: ```plaintext kubectl get volumesnapshotclass ``` Expected results: ```plaintext NAME                  DRIVER             DELETIONPOLICY   AGE vast-snapshot-class   csi.vastdata.com   Delete           10s ``` Note: Installing the Snapshot CRDs only adds the Kubernetes snapshot API resources. A `VolumeSnapshotClass `is still required before users can create snapshots through the CSI snapshot workflow. ### Step 6 - Install VAST CSI Driver on EKS Install the VAST CSI driver using Helm: ```plaintext helm install vast-csi vastcsi/vastcsi -n vast-csi \  --set endpoint=${VAST_MGMT_ENDPOINT} \  --set verifySsl=false \  --set secretName=vastsecret \  --set deletionVipPool=${VAST_VIP_POOL} \  --set deletionViewPolicy=${VAST_VIEW_POLICY} \  --set controller.securityContext.privileged=true \  --set node.securityContext.privileged=true \  --set "mountOptions[0]=nolock" \  --set "mountOptions[1]=vers=3" \  --set "mountOptions[2]=proto=tcp" ``` Expected results: ```plaintext NAME: vast-csi LAST DEPLOYED: Mon May 18 12:40:52 2026 NAMESPACE: vast-csi STATUS: deployed REVISION: 1 DESCRIPTION: Install complete TEST SUITE: None NOTES: Thank you for installing vastcsi. Your release is named vast-csi. The release is installed in namespace vast-csi ``` Parameters: | **Element** | **Value meaning** | | --- | --- | | `endpoint` | VAST management/API endpoint | | `verifySsl` | Whether to verify the VAST management endpoint SSL certificate | | `secretName` | Kubernetes secret containing VAST credentials | | `deletionVipPool` | VAST VIP pool used by CSI | | `deletionViewPolicy` | VAST View Policy | | `controller.securityContext.privileged` | Allows CSI controller operations that may require elevated permissions | | `node.securityContext.privileged` | Allows CSI node plugin to perform mount-related operations on worker nodes | | `mountOptions` | NFS mount options used by pods | **Security note**: > [!WARNING] > The CSI node plugin commonly requires elevated privileges because it performs mount operations on the Kubernetes worker node. In hardened EKS environments, Pod Security Admission, OPA, Kyverno, or other admission controllers may block privileged pods. > > If CSI pods fail to start, validate the cluster security policies and namespace-level pod security configuration. ### Step 7 - Verify CSI Pods ```plaintext kubectl get pods -n vast-csi -o wide ``` Expected results: ```plaintext NAME                                  READY   STATUS    RESTARTS   AGE   IP              NODE                            NOMINATED NODE   READINESS GATES csi-vast-controller-6679cdb99-d656w   5/5     Running   0          30s   10.102.86.247   ip-10-102-86-247.ec2.internal             csi-vast-node-54b9p                   2/2     Running   0          30s   10.102.2.97     ip-10-102-2-97.ec2.internal               csi-vast-node-lf9x6                   2/2     Running   0          30s   10.102.86.247   ip-10-102-86-247.ec2.internal             csi-vast-node-nrxld                   2/2     Running   0          30s   10.102.56.49    ip-10-102-56-49.ec2.internal               ``` Since this EKS cluster has 3 worker nodes, expect 3 VAST CSI node pods. Check the DaemonSet: ```plaintext kubectl -n vast-csi get daemonset ``` Expected results: ```plaintext NAME            DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR   AGE csi-vast-node   3         3         3       3            3                    116s ``` Check logs if needed: ```plaintext kubectl -n vast-csi logs -l app=csi-vast-node --tail=100 kubectl -n vast-csi logs -l app=csi-vast-controller --tail=100 ``` ### Step 8 - Create StorageClass with NFS Mount Options Create or update the StorageClass through Helm: ```plaintext helm upgrade vast-csi vastcsi/vastcsi -n vast-csi --reuse-values \  --set "storageClasses.vastdata-filesystem.vipPool=${VAST_VIP_POOL}" \  --set "storageClasses.vastdata-filesystem.storagePath=${VAST_VIEW_PATH}" \  --set "storageClasses.vastdata-filesystem.viewPolicy=${VAST_VIEW_POLICY}" \  --set "storageClasses.vastdata-filesystem.mountOptions[0]=nolock" \  --set "storageClasses.vastdata-filesystem.mountOptions[1]=vers=3" \  --set "storageClasses.vastdata-filesystem.mountOptions[2]=proto=tcp" ``` Verify: ```plaintext kubectl get storageclass vastdata-filesystem ``` Describe: ```plaintext kubectl describe storageclass vastdata-filesystem ``` Expected results: ```yaml Name:                  vastdata-filesystem IsDefaultClass:        No Annotations:           meta.helm.sh/release-name=vast-csi,meta.helm.sh/release-namespace=vast-csi,storageclass.kubernetes.io/is-default-class=false Provisioner:           csi.vastdata.com Parameters:            eph_volume_name_fmt=csi:{namespace}:{name}:{id},lb_strategy=roundrobin,root_export=CSIVIEW,view_policy=default,vip_pool_fqdn_random_prefix=true,vip_pool_name=protocolsPool,volume_name_fmt=csi:{namespace}:{name}:{id} AllowVolumeExpansion:  True MountOptions:  nolock  vers=3  proto=tcp ReclaimPolicy:      Delete VolumeBindingMode:  Immediate Events:             ``` **GitOps note:** > [!NOTE] > Using Helm to manage the StorageClass is valid and keeps the object aligned with the VAST CSI release. > > For GitOps workflows, consider exporting the generated StorageClass YAML and storing it in version control: > > ```plaintext > kubectl get storageclass vastdata-filesystem -o yaml > vastdata-filesystem-storageclass.yaml > ``` ### Step 9 - Create Test PVC ```plaintext kubectl apply -f - <<'YAML' apiVersion: v1 kind: PersistentVolumeClaim metadata:  name: vast-pvc spec:  accessModes:  - ReadWriteMany  resources:    requests:      storage: 10Gi  storageClassName: vastdata-filesystem YAML ``` Verify: ```plaintext kubectl get pvc vast-pvc ``` Expected results: ```plaintext NAME       STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS          VOLUMEATTRIBUTESCLASS   AGE vast-pvc   Bound    pvc-44a2788d-c10e-4d66-acd2-34baa322d6f3   10Gi       RWX            vastdata-filesystem                   26s ``` Describe if needed: ```plaintext kubectl describe pvc vast-pvc ``` Expected success event: ```plaintext Successfully provisioned volume pvc-44a2788d-c10e-4d66-acd2-34baa322d6f3 ``` ### Step 10 - Create Test Pod ```plaintext kubectl apply -f - <<'YAML' apiVersion: v1 kind: Pod metadata:  name: vast-test-pod spec:  containers:  - name: app    image: busybox:1.36    command: ["sh","-c","echo hello-from-eks > /mnt/data/hello.txt; sleep 3600"]    volumeMounts:    - name: vast-storage      mountPath: /mnt/data  volumes:  - name: vast-storage    persistentVolumeClaim:      claimName: vast-pvc YAML ``` Verify” ```plaintext kubectl get pod vast-test-pod -o wide ``` Expected results: ```plaintext NAME            READY   STATUS    RESTARTS   AGE   IP             NODE                           NOMINATED NODE   READINESS GATES vast-test-pod   1/1     Running   0          26s   10.102.48.21   ip-10-102-56-49.ec2.internal             ``` ### Step 11 - Verify Mount and I/O ```plaintext kubectl exec -it vast-test-pod -- sh -c "mount | grep /mnt/data; ls -la /mnt/data; cat /mnt/data/hello.txt" ``` Expected results: ```plaintext 10.102.16.253:/CSIVIEW/pvc-44a2788d-c10e-4d66-acd2-34baa322d6f3 on /mnt/data type nfs (rw,relatime,vers=3,rsize=1048576,wsize=1048576,namlen=255,hard,nolock,proto=tcp,timeo=600,retrans=2,sec=sys,mountaddr=10.102.16.253,mountvers=3,mountport=20048,mountproto=tcp,local_lock=all,addr=10.102.16.253) total 1 drwxrwxrwx    2 root     root          4096 May 18 09:47 . drwxr-xr-x    3 root     root            18 May 18 09:47 .. -rw-r--r--    1 nobody   nobody          15 May 18 09:47 hello.txt hello-from-eks ``` Additional write test: ```plaintext kubectl exec -it vast-test-pod -- sh -c "date > /mnt/data/date.txt && cat /mnt/data/date.txt" ``` #### Tip: Handling `nobody:nobody` Ownership on VAST NFS Mounts During pod mount validation, files may appear as owned by `nobody:nobody`: ```plaintext -rw-r--r-- 1 nobody nobody ... ``` This usually indicates that the NFS client user is being mapped to `nobody:nobody`, commonly due to root squashing or UID/GID mapping behavior on the VAST View Policy. For a quick functional CSI validation, this may still be acceptable if the pod can successfully create, read, and delete files. For production workloads, ensure the VAST View Policy and the Kubernetes pod security context are aligned. Check the UID/GID used by the container: ```plaintext kubectl exec -it vast-test-pod -- id ``` **Option 1**: Configure the application pod to run with a specific UID/GID: ```plaintext securityContext:  runAsUser: 1000  runAsGroup: 1000  fsGroup: 1000 ``` **Option 2**: Adjust the VAST View Policy and path permissions so the expected Kubernetes UID/GID has access to the exported path. For troubleshooting, verify: - VAST View Policy root squash behavior - Allowed client CIDRs - POSIX permissions on the target path - UID/GID used by the application container - Whether the application requires root or can run as a non-root user **Best practice:** In production, avoid relying on root access from containers. Use explicit UID/GID ownership and permissions instead. ### Step 12 - Check CSI Driver Version #### 12.1 Via Helm ```plaintext helm -n vast-csi list ``` Expected results: ```plaintext NAME      NAMESPACE  REVISION  UPDATED                              STATUS    CHART          APP VERSION vast-csi  vast-csi   2         2026-05-18 12:44:40.893024 +0300 IDT deployed  vastcsi-2.6.5 ``` #### 12.2 Via Running Pods ```plaintext kubectl -n vast-csi get pods -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{range .spec.containers[*]}{.image}{" "}{end}{"\n"}{end}' | grep -i vastdataorg/csi ``` Expected results: ```plaintext csi-vast-controller-6679cdb99-d656w  registry.k8s.io/sig-storage/csi-provisioner:v4.0.0 registry.k8s.io/sig-storage/csi-attacher:v4.5.0 registry.k8s.io/sig-storage/csi-snapshotter:v7.0.1 registry.k8s.io/sig-storage/csi-resizer:v1.10.0 vastdataorg/csi:v2.6.5 csi-vast-node-54b9p                  registry.k8s.io/sig-storage/csi-node-driver-registrar:v2.10.0 vastdataorg/csi:v2.6.5 csi-vast-node-lf9x6                  registry.k8s.io/sig-storage/csi-node-driver-registrar:v2.10.0 vastdataorg/csi:v2.6.5 csi-vast-node-nrxld                  registry.k8s.io/sig-storage/csi-node-driver-registrar:v2.10.0 vastdataorg/csi:v2.6.5 ``` ### Step 13 - Delete / Cleanup Test Resources #### 13.1 Delete Test Pod ```plaintext kubectl delete pod vast-test-pod --ignore-not-found ``` #### 13.2 Delete PVC ```plaintext kubectl delete pvc vast-pvc --ignore-not-found ``` Expected results: ```plaintext persistentvolumeclaim "vast-pvc" deleted from default namespace ``` #### 13.3 Verify PV Cleanup ```plaintext kubectl get pv | grep -i vast || true ``` A temporary `Released `state may appear while the CSI driver cleans up the backing resource: ```plaintext pvc-44a2788d-c10e-4d66-acd2-34baa322d6f3   10Gi   RWX   Delete   Released   default/vast-pvc   vastdata-filesystem     7m53s ``` In a healthy cleanup flow, deleting the pod first and then deleting the PVC should allow Kubernetes and the CSI driver to clean up the related PV normally. ### Step 14 - Force-Delete Stuck PVs Use this only if a PV remains stuck in `Terminating`, `Released`, or another non-clean state after normal cleanup. Check leftover PVs: ```plaintext kubectl get pv | grep -i vast || true ``` For each stuck PV: ```plaintext kubectl patch pv -p '{"metadata":{"finalizers":null}}' --type=merge kubectl delete pv --force --grace-period=0 ``` Example: ```plaintext kubectl patch pv pvc-44a2788d-c10e-4d66-acd2-34baa322d6f3 \  -p '{"metadata":{"finalizers":null}}' \  --type=merge kubectl delete pv pvc-44a2788d-c10e-4d66-acd2-34baa322d6f3 \  --force \  --grace-period=0 ``` **Warning**: > [!WARNING] > Removing finalizers is a destructive administrative action. Use it only after confirming that: > > - The application pod was deleted > - The PVC was deleted > - The backing VAST resource state is understood > - No application still depends on the PV ### Step 15 - Verify Cleanup ```plaintext kubectl get pv | grep -i vast || true kubectl get pvc --all-namespaces | grep -i vast || true kubectl get volumeattachment | grep -i vast || true ``` Expected results: ```plaintext No resources found ``` ### Step 16 - Uninstall Instructions #### 16.1 Remove Workloads ```plaintext kubectl delete pod vast-test-pod vast-test-pod-2 vast-test-pod-pvc2 --ignore-not-found kubectl delete pvc vast-pvc vast-pvc-2 --ignore-not-found ``` #### 16.2 Verify PVC and PV Deletion ```plaintext kubectl get pvc --all-namespaces kubectl get pv | grep -i vast || true ``` Verify that: - PVCs are removed - PVs transition to Released or Deleted - Corresponding VAST resources are removed if dynamic provisioning was used #### 16.3 Remove StorageClass ```plaintext kubectl delete storageclass vastdata-filesystem --ignore-not-found ``` #### 16.4 Remove VolumeSnapshotClass, If Created ```plaintext kubectl delete volumesnapshotclass vast-snapshot-class --ignore-not-found ``` #### 16.5 Helm Uninstall CSI Driver ```plaintext helm uninstall vast-csi -n vast-csi ``` #### 16.6 Namespace Cleanup ```plaintext kubectl delete namespace vast-csi ``` #### 16.7 Final Verification ```plaintext kubectl get csidriver | grep -i vast || true kubectl get storageclass | grep -i vast || true kubectl get volumesnapshotclass | grep -i vast || true kubectl get pods -n vast-csi --ignore-not-found ``` Expected results: ```plaintext No VAST CSI resources remain ``` ### Optional: Delete the EKS Cluster Only run this if the full EKS test environment should be removed. ```plaintext eksctl delete cluster \  --name ${EKS_CLUSTER_NAME} \  --region ${AWS_REGION} \  --profile ${AWS_PROFILE} ``` ### Quick Command Summary ```plaintext export AWS_PROFILE=AWS-Polaris-Test export AWS_REGION=us-east-1 export EKS_CLUSTER_NAME=eks-solutions-poc-v3 export EKS_NODEGROUP_NAME=eks-solutions-poc-eks-workers export VAST_MGMT_ENDPOINT=10.102.28.4 export VAST_NFS_VIP=10.102.14.237 export VAST_VIP_POOL=protocolsPool export VAST_VIEW_PATH=CSIVIEW export VAST_VIEW_POLICY=default aws sso login --profile ${AWS_PROFILE} aws sts get-caller-identity --profile ${AWS_PROFILE} eksctl create cluster -f cluster.yaml --profile ${AWS_PROFILE} aws eks update-kubeconfig \  --name ${EKS_CLUSTER_NAME} \  --region ${AWS_REGION} \  --profile ${AWS_PROFILE} kubectl get nodes -o wide nc -vz ${VAST_MGMT_ENDPOINT} 443 nc -vz ${VAST_NFS_VIP} 2049 kubectl create namespace vast-csi helm repo add vastcsi https://vast-data.github.io/vast-csi helm repo update read -s -p "Enter VAST password: " VAST_PASS echo kubectl -n vast-csi create secret generic vastsecret \  --from-literal=username=admin \  --from-literal=password="${VAST_PASS}" unset VAST_PASS kubectl apply -f https://raw.githubusercontent.com/kubernetes-csi/external-snapshotter/v6.0.1/client/config/crd/snapshot.storage.k8s.io_volumesnapshotclasses.yaml kubectl apply -f https://raw.githubusercontent.com/kubernetes-csi/external-snapshotter/v6.0.1/client/config/crd/snapshot.storage.k8s.io_volumesnapshotcontents.yaml kubectl apply -f https://raw.githubusercontent.com/kubernetes-csi/external-snapshotter/v6.0.1/client/config/crd/snapshot.storage.k8s.io_volumesnapshots.yaml kubectl apply -f - <<'YAML' apiVersion: snapshot.storage.k8s.io/v1 kind: VolumeSnapshotClass metadata:  name: vast-snapshot-class driver: csi.vastdata.com deletionPolicy: Delete YAML helm install vast-csi vastcsi/vastcsi -n vast-csi \  --set endpoint=${VAST_MGMT_ENDPOINT} \  --set verifySsl=false \  --set secretName=vastsecret \  --set deletionVipPool=${VAST_VIP_POOL} \  --set deletionViewPolicy=${VAST_VIEW_POLICY} \  --set controller.securityContext.privileged=true \  --set node.securityContext.privileged=true \  --set "mountOptions[0]=nolock" \  --set "mountOptions[1]=vers=3" \  --set "mountOptions[2]=proto=tcp" kubectl get pods -n vast-csi -o wide helm upgrade vast-csi vastcsi/vastcsi -n vast-csi --reuse-values \  --set "storageClasses.vastdata-filesystem.vipPool=${VAST_VIP_POOL}" \  --set "storageClasses.vastdata-filesystem.storagePath=${VAST_VIEW_PATH}" \  --set "storageClasses.vastdata-filesystem.viewPolicy=${VAST_VIEW_POLICY}" \  --set "storageClasses.vastdata-filesystem.mountOptions[0]=nolock" \  --set "storageClasses.vastdata-filesystem.mountOptions[1]=vers=3" \  --set "storageClasses.vastdata-filesystem.mountOptions[2]=proto=tcp" kubectl get storageclass vastdata-filesystem kubectl describe storageclass vastdata-filesystem ```