Nutanix Enterprise AI on NKPPart 2: Nutanix Files for Kubernetes

Published
Reading
19 min

Tested onNKP 2.19Nutanix Files 5.4.0.1Nutanix CSI 3.9.0Prism Central 7.6Lab date On a different version, check the compatibility matrix and the release notes before applying.

Ler em português

Cover of the Nutanix Enterprise AI on NKP series, with part 2, Nutanix Files, highlighted

Summary: Nutanix Enterprise AI stores models on a ReadWriteMany (RWX) volume, and NKP’s default storage class is Nutanix Volumes, ReadWriteOnce; RWX comes from Nutanix Files. In this part I deploy Nutanix Files 5.4.0.1 from Prism Central (3 FSVMs, 5 TiB, 27 minutes), enable NFS v3 and v4, test the mount from a VM and connect Files to Kubernetes. A configuration detail worth knowing: the NKP 2.19 CSI runs in Prism Central mode, and dynamic Files provisioning needs its own secret with a REST API user from the file server. In the end, an RWX volume is ready in 6 seconds, and two pods on different nodes write to the same file. This is part 2 of 4.

Where we are

The series follows the enablement of Nutanix Enterprise AI (NAI) in a lab with NKP 2.19 and a Nutanix HCI cluster with no GPU.

PartTopic
1NAI: architecture, licensing and sizing
2Nutanix Files for Kubernetes: the RWX NAI requires (this post)
3From the catalog to the first token: dedicated cluster, NAI 2.8.1 and license
4CPU, GPU and MCP: NAI in a hybrid architecture

Before installing NAI, I read the 2.8.1 User Guide and the two Nutanix Validated Designs that cover it. All three agree on one prerequisite NKP does not ship ready: shared NFS storage. This part solves it end to end, and it applies to any NKP application that needs RWX, not just NAI.


Why NAI needs RWX

A Kubernetes volume has an access mode. The two that matter here:

ModeShortWho mountsExample on NKP
ReadWriteOnceRWOOne node at a timenutanix-volume (Nutanix Volumes, iSCSI), the default storage class
ReadWriteManyRWXSeveral nodes at onceNeeds NFS: Nutanix Files with the CSI

NAI downloads each model once and keeps it on a shared volume. When an endpoint gets a second replica, or when a pod is recreated on another node, it reads the weights from the same place, without downloading everything again. That is why the model volume must be RWX.

What the NAI 2.8.1 User Guide asks for in storage:

ItemRequirementFor
Block (RWO)≥ 150 GiBPostgreSQL, ClickHouse, Valkey, audit logs
NFS (RWX)≥ 2 TiB, storage class with volumeBindingMode: ImmediateValidated or custom models
NFSv4 exportA separate shareImporting custom or manually downloaded models
S31 TiB (optional)Another way to import models

Useful beyond NAI

JupyterHub with shared directories, ML pipelines reading the same dataset from several pods, CMSs with shared uploads: anything that needs RWX on NKP goes through the same path as this post.

The architecture

Nutanix Files runs as a set of VMs on the HCI cluster itself, the FSVMs (File Server VMs). They serve NFS to clients and store data in a storage container on the cluster. On the Kubernetes side, the Nutanix CSI does two different things: through the Files REST API, it creates one share per requested volume; through NFS, it mounts that share on the node where the pod runs.

PieceRole
FSVMFile server VM; with 3, an export stays online if one FSVM fails
Client networkWhere clients (Kubernetes nodes, VMs) mount NFS
Storage networkInternal: FSVMs talking to the CVMs and to each other
Storage containerCreated by the wizard just for the file server
CSI controllerTalks to the Files API to create, expand and delete shares
CSI nodeMounts NFS on the node for the pod to use

Planning: the decisions before the wizard

Size

The Nutanix NVDs use FSVMs with 12 vCPU and 64 GB in production. In a lab, the scarce resource is memory, so I went with the supported minimum.

ItemNVD (production)LabWhy
FSVMs33Minimum for file server high availability
vCPU / memory per FSVM12 / 64 GB4 / 12 GBSupported minimum; can grow later, online
Capacity—5 TiBAbove the 2 TiB NAI asks for, with room for models and other apps

The 3 FSVMs add up to 36 GB of RAM. I ran the cluster math first: the lab has 3 hosts, and I want everything to keep running if one host fails (N+1), which caps usage at about two thirds of total memory.

Network

The wizard asks for two networks. The lab has a single VLAN, managed by AHV IPAM, so both went there.

NetworkIPs needed (3 FSVMs)In the lab
Client3 (one per FSVM)Same VLAN as the VMs, IPs from IPAM
Storage4 (FSVMs + 1)Same VLAN, IPs from IPAM

Files requires a subnet with IPAM

The wizard only lists managed subnets (with IPAM). IPs come from the pool automatically; write them down after the deployment and record them in your addressing plan. In production, the NVDs recommend the client network on a separate subnet for security; in the lab, this is a conscious deviation.

DNS and NTP

Files asks for DNS and NTP servers. The lab has no internal DNS, and I wanted to confirm what the gateway resolved before filling in the form:

Terminal window
$ dig @192.0.2.1 pe.lab.example.local
;; WARNING: .local is reserved for Multicast DNS
;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN
;; AUTHORITY SECTION:
. 86400 IN SOA a.root-servers.net. nstld.verisign-grs.com. ...

NXDOMAIN with the internet root SOA: the gateway only forwards queries out and does not know the internal domain. The practical consequence: clients will mount Files by IP, not by name. It works well, and the CSI accepts an IP normally.

Warning

.local is reserved dig itself warns about it: the .local suffix belongs to mDNS (RFC 6762). In customer environments, prefer a subdomain of a real domain, such as lab.company.com.

License

Files is licensed through Nutanix Unified Storage (NUS), metered in usable TiB. Before deploying, I checked what was applied to the cluster:

Licenses applied to the cluster: NCI Ultimate and NCI Security, NCM Ultimate and two NUS Pro lines, 1 TiB included with NCI and 50 TiB

LicenseQuantityNote
NUS Pro included with NCI Ultimate1 TiBComes with NCI Ultimate
NUS Pro50 TiBThe lab license
NCI Security60 coresThis is Flow Network Security

If you have NCI Ultimate

NCI Ultimate already includes 1 TiB of NUS Pro. You can start a small file server without buying anything else.


Deploying the file server from Prism Central

Goal: a file server with 3 FSVMs, 5 TiB and NFS, created through the Prism Central wizard (Files → File Servers → New File Server).

The starting point, with no file server:

Prism Central, Files, File Servers: There are no File Servers available

1. Location: Prism Central or Prism Element

The first screen asks for the provider (Nutanix, AWS or Azure) and already shows a warning: some features are not supported on file servers deployed through Prism Central; to use them, deploy from Prism Element.

Wizard warning: some features are not supported on file servers deployed through Prism Central

I went ahead with Prism Central. This warning matters for the protection choice (see the protection section).

2. Cluster and version

The wizard only lists versions that are compatible and available in LCM. There were 13; I picked the newest, 5.4.0.1.

Cluster and file server version selection: 13 compatible versions, 5.4.0.1 selected

3. Basics and sizing

Name (up to 15 characters, no dots), DNS domain, logical capacity and FSVM size.

File Server Basics screen: name files-lab, domain, 5 TiB, 3 FSVMs with 4 vCPU and 12 GB

FieldValue
Namefiles-lab
DNS Domainlab.example.local
File Server Size (Logical)5 TiB
Number of FSVMs3
vCPUs / Memory4 / 12 GB

4. Client and storage networks

Both screens show the IPAM range, how many IPs are free and how many the file server will use: 3 on client, 4 on storage.

Client network: vlan-prod, IPAM prefix and range, 107 free IPs, 3 needed

Storage network: same VLAN, 104 free IPs, 4 needed

5. Settings: DNS, NTP and two switches for Kubernetes

This is the most important screen, because nothing here can change after deployment.

Settings screen: DNS, NTP, Default profile, Direct Attach and Containerized Workload enabled

The Deployment Profile field has three options:

Deployment profiles: Default, General Dedicated and AI/ML Dedicated

ProfileWhat it doesWhen to use
DefaultShared resources, no special optimizationGeneral use (the lab’s choice)
General DedicatedFSVM and CVM on separate NUMA nodesMore predictable performance
AI/ML DedicatedDirect Attach + dedicated NUMA, one file server per clusterHigh-throughput AI workloads (disabled in the lab)

And the two switches:

OptionWhat it doesDecision
Direct Attach modeAttaches volume groups directly to the FSVMs, keeping storage traffic off the network. Lower latency. Not compatible with Metro Availability or cross-hypervisor DROn (the lab uses neither)
Containerized WorkloadPre-creates volume groups during deployment and scale-out to speed up share creation and deletion by KubernetesOn: exactly the CSI use case

6. Summary

Summary before Create: FQDN, cluster, version 5.4.0.1, 5 TiB, 3 FSVMs with 4 vCPU and 12 GB, networks, DNS, NTP, profile and options


The deployment: 27 minutes

Prism Central created the 3 FSVMs in the first 90 seconds, then mounted the Files image and configured the file server cluster.

Create File Server task at 5%, with the three FSVMs already created

Create File Server task completed in 27 minutes and 18 seconds

TimeEvent
22:11Create File Server task starts
22:123 FSVMs created (one per host)
22:15Artifacts downloaded and 5.4.0.1 image mounted
22:38Succeeded (27 min 18 s)
22:37 to 22:42Volume groups pre-created (Containerized Workload)

File server list: files-lab, deployed through Prism Central, 3 FSVMs, version 5.4.0.1

The file server dashboard opened Healthy, with no alerts and 5 TiB free:

files-lab dashboard: Healthy, 0 alerts, 5 TiB free, no shares, features such as Smart DR and Smart Tiering off

Right after Succeeded, Files ran two more tasks: FS Deploy VG Create and Volume Group Manage. That is Containerized Workload at work, pre-creating the volume groups Kubernetes shares will use.

Post-deployment tasks completed: Volume Group Manage with VG subtasks and FS Deploy VG Create

Wait for the post-deployment tasks

Create the first share only after FS Deploy VG Create and Volume Group Manage reach 100%. In the lab, that took another 5 minutes.

The file server network

The network screen shows the layout and the IPs IPAM handed out:

File server diagram: clients, NTP, DNS and AD on the external network; three FSVMs; internal network to storage; NTNX_files-lab_ctr container

FSVMClient IP (NFS mount)Storage IP
NTNX-files-lab-1192.0.2.128192.0.2.152
NTNX-files-lab-2192.0.2.132192.0.2.194
NTNX-files-lab-3192.0.2.129192.0.2.157

Client IPs of the three FSVMs

The fourth storage IP (the wizard’s “+1”) does not show in the UI table. It exists; look it up in the subnet IPAM if you need to record it.

The container Files creates

The wizard creates a storage container just for the file server, NTNX_files-lab_ctr. I checked its properties against the GPT-in-a-Box NVD:

NTNX_files-lab_ctr container: RF2, compression on with a 60-minute delay, deduplication and erasure coding off

PropertyLabNVD
Replication Factor22
CompressionOn (60 min delay)On (60 min)
DeduplicationOffOff
Erasure CodingOffOff

Same as recommended, without touching anything. The 32 GiB already used right after deployment are the pre-created volume groups.


Enabling NFS

The file server starts with no protocol. Under Configuration → Authentication, I enabled NFS only:

Protocols: SMB off (requires Active Directory), NFS with Unmanaged user management; by default only NFSv3 is checked

OptionValueWhy
SMBOffRequires Active Directory; not needed for Kubernetes
User ManagementUnmanagedNo AD and no LDAP; access is controlled by client IP, as the CSI expects
NFSv3On (default)Compatibility
NFSv4OnUnchecked by default. Needed for mount -t nfs4
NFS over TLSOffInternal lab network

Enable NFSv4 before the exports

The factory default is NFSv3 only. Check Enable NFSv4 by default for all exports before creating exports, or every export is born without v4.

First export and the manual test

Before involving Kubernetes, I tested Files on its own, with a 10 GiB export mounted from a Linux VM.

Standard or Distributed

Standard type: data and connections served by a single FSVM

Distributed type: top-level directories spread across the FSVMs

TypeHow it worksWhen to use
StandardOne FSVM serves the whole exportMost cases; this is what the CSI creates
DistributedTop-level directories are spread across FSVMsMany clients or large capacity, such as user home directories

Squash and sudo

On the permissions screen, the default is Root Squash:

Export summary with Squash: Root squash

With root squash, the client’s root becomes an anonymous user on the server. Since my test wrote with sudo, it would fail with Permission denied. For the test, I switched it to None:

Export summary with Squash: None, NFSV3V4, Read-write

Mounting from a VM

Terminal window
$ sudo apt install -y nfs-common
$ sudo mount -t nfs4 192.0.2.128:/teste-nfs /mnt/teste-nfs
$ echo "ok $(date)" | sudo tee /mnt/teste-nfs/teste.txt
ok Fri Oct 30 01:56:55 AM UTC 2026
$ df -h /mnt/teste-nfs
Filesystem Size Used Avail Use% Mounted on
192.0.2.132:/teste-nfs 0 0 0 - /mnt/teste-nfs
$ mount | grep teste-nfs
192.0.2.132:/teste-nfs on /mnt/teste-nfs type nfs4 (rw,vers=4.2,proto=tcp,sec=sys,addr=192.0.2.132)

Three things to notice:

  1. I mounted through .128 and ended up on .132. On a Standard export, a single FSVM serves the whole export, and Files uses NFSv4 redirection to send the client to it. The client can use any client IP.
  2. NFS 4.2, negotiated automatically.
  3. df shows size 0. Files does not expose the export quota to the NFS client. It is not an error; good to know so it does not surprise you.

Kubernetes seeing Files

What NKP already has

NKP installs the Nutanix CSI on every cluster. The workload cluster inventory:

Terminal window
$ kubectl get sc
NAME PROVISIONER VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION
dkp-object-store <workspace>.ceph.rook.io/bucket Immediate false
nutanix-volume (default) csi.nutanix.com WaitForFirstConsumer true
$ kubectl get csidrivers
NAME ATTACHREQUIRED PODINFOONMOUNT MODES
csi.nutanix.com true true Persistent
$ kubectl -n ntnx-system get ds,deploy -o wide | grep csi
daemonset.apps/nutanix-csi-node 6 6 6 ... docker.io/nutanix/ntnx-csi:3.9.0
deployment.apps/nutanix-csi-controller 2/2 ... docker.io/nutanix/ntnx-csi:3.9.0

The driver is 3.9.0, the default storage class is Volumes (RWO), and there is a single credentials secret, ntnx-system/nutanix-csi-credentials.

The detail: the CSI runs in Prism Central mode

The CSI 3.x documentation shows dynamic Files with the driver talking to Prism Element, and a secret with a second key, files-key. Before copying the example, I checked who the NKP CSI talks to, without exposing any password:

Terminal window
# Only the secret key names
$ kubectl -n ntnx-system get secret nutanix-csi-credentials \
-o go-template='{{range $k,$v := .data}}{{$k}}{{"\n"}}{{end}}'
key
# Only host and port of the key (the command cuts user and password)
$ kubectl -n ntnx-system get secret nutanix-csi-credentials \
-o jsonpath='{.data.key}' | base64 -d | cut -d: -f1,2
192.0.2.88:9440
$ kubectl -n ntnx-system get deploy nutanix-csi-controller -o yaml \
| grep -iE 'usepc|use_pc|management-plane|mixed'
app.kubernetes.io/management-plane: PrismCentral
- name: USE_PC
- --use-mixed-mode=false

The address is Prism Central’s, and the controller has USE_PC. The NKP 2.19 CSI runs in PC mode.

How dynamic Files works in PC mode

The main documentation shows PE mode. PC mode also supports dynamic Files with its own secret holding the Prism Central key (key) and the file server key (files-key: <file server>:<user>:<password>). The CSI log confirms it: “Using Files secrets available in PC Mode”.

Do not edit the NKP secret

nutanix-csi-credentials is managed by NKP. Create a separate secret just for the Files storage class.

1. REST API user on the file server

The files-key uses a user of the file server’s own API, not a Prism user. It is created in the file server console, under Configuration → Manage Roles → REST API access users:

Manage Roles: REST API user csi-nkp being added, password masked

Click the ✓

The user row stays in edit mode until you click the ✓ on the right. Without it, the user is not saved.

2. Dedicated secret

The script reads the Prism Central key from the NKP secret and builds the new secret without printing anything:

Terminal window
read -rp "File server REST API user: " FU
read -rsp "Password (hidden): " FP; echo
PCKEY=$(kubectl -n ntnx-system get secret nutanix-csi-credentials \
-o jsonpath='{.data.key}' | base64 -d)
kubectl -n ntnx-system create secret generic nutanix-files-csi \
--from-literal=key="$PCKEY" \
--from-literal=files-key="192.0.2.128:$FU:$FP"
unset PCKEY FP

I used the client IP in files-key, not the name, because the lab nodes cannot resolve the internal domain.

3. The storage class

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: nai-nfs
provisioner: csi.nutanix.com
parameters:
storageType: NutanixFiles
dynamicProv: ENABLED
nfsServerName: files-lab # file server name in Prism
nfsServer: 192.0.2.128 # client IP: mount and API
squashType: "none"
csi.storage.k8s.io/provisioner-secret-name: nutanix-files-csi
csi.storage.k8s.io/provisioner-secret-namespace: ntnx-system
csi.storage.k8s.io/node-publish-secret-name: nutanix-files-csi
csi.storage.k8s.io/node-publish-secret-namespace: ntnx-system
csi.storage.k8s.io/controller-expand-secret-name: nutanix-files-csi
csi.storage.k8s.io/controller-expand-secret-namespace: ntnx-system
allowVolumeExpansion: true
reclaimPolicy: Delete
volumeBindingMode: Immediate # required by NAI
ParameterValueWhy
dynamicProv: ENABLEDA new share per PVCEach volume isolated, deleted with its PVC
nfsServerNamefiles-labThe CSI looks up the file server by name
nfsServerClient IPUsed for the mount and, with files-key, for the API
squashTypenoneLab; consider root-squash in production depending on the images that will write
volumeBindingModeImmediateRequired by NAI; the NKP default is WaitForFirstConsumer

The RWX test: two nodes, one file

The test creates a 2 GiB RWX PVC and a deployment with 2 replicas, forced onto different nodes (podAntiAffinity). Each replica writes a line every 5 seconds to the same file:

apiVersion: v1
kind: PersistentVolumeClaim
metadata: { name: rwx-teste }
spec:
accessModes: [ReadWriteMany]
storageClassName: nai-nfs
resources: { requests: { storage: 2Gi } }
---
apiVersion: apps/v1
kind: Deployment
metadata: { name: rwx-escritor }
spec:
replicas: 2
selector: { matchLabels: { app: rwx-escritor } }
template:
metadata: { labels: { app: rwx-escritor } }
spec:
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector: { matchLabels: { app: rwx-escritor } }
topologyKey: kubernetes.io/hostname
containers:
- name: c
image: busybox:1.36
command: ["sh","-c","while true; do echo \"$(date -u +%H:%M:%S) $(hostname) no nó $NODE\" >> /dados/log.txt; sleep 5; done"]
env: [{ name: NODE, valueFrom: { fieldRef: { fieldPath: spec.nodeName } } }]
volumeMounts: [{ name: d, mountPath: /dados }]
volumes: [{ name: d, persistentVolumeClaim: { claimName: rwx-teste } }]

The result (the log lines are in Portuguese, as in the lab script: “no nó” means “on node”):

Terminal window
$ kubectl -n files-teste get pvc rwx-teste
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
rwx-teste Bound pvc-bc03c1b0-8456-4cda-a43c-3a5f70b446ea 2Gi RWX nai-nfs 6s
$ kubectl -n files-teste get pods -o wide
NAME READY STATUS NODE
rwx-escritor-68f798cf6d-v5s5s 1/1 Running worker-a
rwx-escritor-68f798cf6d-wrlph 1/1 Running worker-b
$ kubectl -n files-teste exec <pod> -- tail -6 /dados/log.txt
02:38:48 rwx-escritor-68f798cf6d-wrlph no nó worker-b
02:38:50 rwx-escritor-68f798cf6d-v5s5s no nó worker-a
02:38:53 rwx-escritor-68f798cf6d-wrlph no nó worker-b
02:38:55 rwx-escritor-68f798cf6d-v5s5s no nó worker-a
02:38:58 rwx-escritor-68f798cf6d-wrlph no nó worker-b
02:39:00 rwx-escritor-68f798cf6d-v5s5s no nó worker-a
lines per pod:
5 rwx-escritor-68f798cf6d-v5s5s
5 rwx-escritor-68f798cf6d-wrlph
$ kubectl -n files-teste exec <pod> -- mount | grep /dados
192.0.2.128:/pvc-bc03c1b0-... on /dados type nfs4 (rw,vers=4.2,proto=tcp,...)

The lines from both replicas interleave: two nodes writing to the same file. That is RWX.

What the CSI did under the hood

The controller log shows the full path, in about 2.6 seconds:

Using Files secrets available in PC Mode
GET https://192.0.2.128:9440/api/files/v4.0/config/file-servers
POST https://192.0.2.128:9440/api/files/v4.0/config/file-servers/<uuid>/mount-targets
Task completed with status: SUCCEEDED, progress: 100%
Setting cfg.volumePath with value: pvc-bc03c1b0-8456-4cda-a43c-3a5f70b446ea
ControllerPublishVolume called ... nfsServer:192.0.2.128 nfsServerName:files-lab provNFSShare:ENABLED
StepWhat happened
1The CSI found files-lab through the Files v4 API, using files-key
2It created a mount target (the share) named after the PV
3It waited for the task to finish (SUCCEEDED)
4It published the volume to both nodes, which mounted it over NFS 4.2

Three informational messages worth knowing:

MessageWhat it means
FailedScheduling ... pod has unbound immediate PersistentVolumeClaimsThe pods tried to start before the PVC was Bound. Gone in seconds
NutanixFiles: Unknown option "storageType"Informational log; the parameter is ignored at that point
df with size 0Files does not expose the quota to the NFS client; the PV shows 2 GiB

The lifecycle, seen from Files

With the test running, the volume shows up in the Files console as a share named after the PV:

Shares & Exports: share pvc-bc03c1b0 created by the CSI next to nai-modelos

I deleted the test namespace. With reclaimPolicy: Delete, the CSI removed the share on its own:

Shares & Exports after cleanup: only nai-modelos remains


The NAI model export

NAI also asks for a separate NFSv4 export to import custom or manually downloaded models. I created nai-modelos (Portuguese for “nai-models”): Standard, NFS v3 and v4, Read-Write, squash None, no size limit.

nai-modelos export summary: Standard, NFSV3V4, Read-write, squash None

nai-modelos share properties: path, description, mount path and 5 TiB max size

“Max Size 5 TiB” means the export can use the whole file server. The Mount Path shows the DNS name; without internal DNS, use the client IP.

Protection: Protection Domain, Smart DR or SSR

The file server console offers two kinds of protection:

Data Protection: Protection Domain (Prism Element) and Smart DR, both off

When configuring the Protection Domain, the screen shows it applies to file servers created from Prism Element:

Tooltip: this feature is supported on PE created file servers only

OptionWhat it doesIn the lab
Protection DomainSnapshot of the whole file server, with optional async replicationDoesn’t apply to the lab: it’s for file servers created from Prism Element
Smart DRPer-share replication to another file server, with one-click failoverRequires a second file server
Self Service RestorePer-share snapshots so users can restore filesPossible; of little use for models, which can be downloaded again

Self Service Restore: no share with SSR and the Default policy, 1-hour minimum interval, 38 snapshots and 4 schedules (24 hourly, 7 daily, 4 weekly and 3 monthly)

In the lab, I decided not to protect the file server: models can be downloaded again, and the NAI data that matters (database, metrics, cache) lives on RWO volumes, on Nutanix Volumes. Protecting those volumes is a job for NDK and Velero.

Decide in the wizard: Prism Central or Prism Element

If the file server needs a Protection Domain or async replication, deploy it from Prism Element. From Prism Central, protection is Smart DR, per share and with a second file server. Read the View Incompatible Features link on the first wizard screen before deciding.


Lab × Nutanix Validated Design

TopicNVDLabStatus
FSVMs33Same
FSVM size12 vCPU / 64 GB4 vCPU / 12 GBConscious deviation
Storage networkSame subnet as the CVMsSame VLANSame
Client networkSeparate subnetSame VLANConscious deviation
IPs4 storage + 3 client4 + 3Same
ContainerSeparate, RF2, compression, no dedup or ECSameSame
Protocol and CSINFS, dynamic provisioningNFS, dynamicSame
Export for custom modelsYesnai-modelosSame
Objects (S3)3 workers + 2 load balancersNot installedLater (~104 GB of RAM)

The numbers

MeasureValue
File server deployment27 min 18 s
Post-deployment tasks (volume groups)~5 min
Share creation by the CSI (v4 API)~2.6 s
RWX PVC Bound6 s
Pods ready (including image pull)~22 s
Memory of the 3 FSVMs36 GB
Capacity5 TiB logical

What I learned

  1. NKP’s RWX comes from Nutanix Files. The default storage class is Nutanix Volumes (RWO); for NAI, and for any app with a shared volume, add Files and a dedicated storage class.
  2. The NKP 2.19 CSI runs in Prism Central mode. Dynamic Files works in that mode with a dedicated secret holding key (PC) and files-key (file server REST API user).
  3. Containerized Workload and Direct Attach are the right options for Kubernetes, and they cannot change after deployment.
  4. Enable NFSv4 before creating exports. The factory default is NFSv3 only.
  5. Root squash and sudo do not mix in a manual test; choose the squash setting consciously in the storage class.
  6. For a Protection Domain, deploy the file server from Prism Element. From Prism Central, protection is Smart DR.
  7. Without internal DNS, mount by IP. Files redirects the client to the right FSVM.

Checklist: Nutanix Files for NKP

  • NUS license applied to the cluster (NCI Ultimate includes 1 TiB)
  • Memory for the FSVMs within the cluster’s N+1
  • Subnet with IPAM and free IPs (FSVMs on client; FSVMs + 1 on storage)
  • DNS and NTP reachable from the client network
  • Decided: Prism Central or Prism Element (protection)
  • Containerized Workload and Direct Attach enabled in the wizard
  • Post-deployment tasks finished before the first share
  • NFSv4 enabled
  • REST API user created (and saved with the ✓)
  • Dedicated secret with key and files-key, without touching the NKP secret
  • RWX storage class with Immediate
  • Test with 2 pods on different nodes, and the share gone after cleanup
  • Separate export for custom models (if you will use NAI)

What I haven’t tested yet

  • Nutanix Objects (S3), which the NVD uses in its design: I did not install it in the lab, and it is planned for later (~104 GB of RAM).
  • File server protection with Smart DR, which needs a second file server. In the lab, I chose not to protect Files, because the models can be downloaded again.
  • The NVD’s production sizing: 12 vCPU / 64 GB FSVMs and the client network on a separate subnet. In the lab, I stayed at the supported minimum and on a single VLAN, as a conscious deviation.

Next part

In Part 3, the cluster dedicated to NAI on NKP 2.19, the catalog dependencies, NAI 2.8.1 and the license, which has only a 2-day trial after installation.

References

Nutanix

Projects and community

Independent

Comments

Comments use GitHub Discussions; you need a GitHub account.