Skip to content

Helm Installation

The recommended way to deploy the flexFS CSI driver is with the provided Helm chart.

  • Kubernetes 1.25 or later (1.27 or later for ReadWriteOncePod claims and for sharing a ReadWriteOnce volume between pods on one node; see Access modes)
  • Helm 3
  • /dev/fuse available on all worker nodes (most Linux distributions include it by default)
  • Cluster must allow privileged pods in the kube-system namespace (the node DaemonSet requires privileged mode for FUSE access)

The Helm chart is distributed as a .tgz archive from get.flexfs.io. Download and extract it:

Terminal window
curl -fsSLO https://get.flexfs.io/v1.9.x/k8s/flexfs-csi-driver.tgz
tar -xzf flexfs-csi-driver.tgz

Extraction creates a flexfs-csi-driver/ directory containing the chart:

flexfs-csi-driver/
├── Chart.yaml
├── values.yaml
└── templates/
├── clusterrole.yaml
├── clusterrolebinding.yaml
├── csidriver.yaml
├── daemonset.yaml
├── deployment.yaml
└── serviceaccount.yaml
FieldValue
Chart nameflexfs-csi-driver
Chart typeapplication
Homehttps://flexfs.io
Default namespacekube-system

The following table lists the configurable values in values.yaml and their defaults:

KeyDefaultDescription
clusterRole.nameflexfs-csi-controllerClusterRole name
clusterRoleBinding.nameflexfs-csi-controllerClusterRoleBinding name
daemonSet.appflexfs-csi-nodeNode pod label
daemonSet.nameflexfs-csi-nodeNode DaemonSet name
daemonSet.namespacekube-systemNode DaemonSet namespace
deployment.appflexfs-csi-controllerController pod label
deployment.nameflexfs-csi-controllerController Deployment name
deployment.namespacekube-systemController Deployment namespace
deployment.replicas2Controller replica count
driver.imageflexfs/csi-driver-<major>.<minor>:latestCSI driver container image
driver.imagePullPolicyAlwaysImage pull policy
driver.nameflexfs-csi-driverContainer name
kubeletDir/var/lib/kubeletKubelet root directory on the host. Override on distributions that relocate it (see MicroK8s and custom kubelet directories)
serviceAccount.nameflexfs-csi-controllerServiceAccount name
serviceAccount.namespacekube-systemServiceAccount namespace

Run the following from the directory where you extracted the archive (so that ./flexfs-csi-driver resolves to the chart):

Terminal window
helm install flexfs-csi-driver ./flexfs-csi-driver \
--namespace kube-system

To customize values:

Terminal window
helm install flexfs-csi-driver ./flexfs-csi-driver \
--namespace kube-system \
--set deployment.replicas=3 \
--set driver.imagePullPolicy=IfNotPresent

Or use a values override file:

Terminal window
helm install flexfs-csi-driver ./flexfs-csi-driver \
--namespace kube-system \
-f my-values.yaml

The chart installs six Kubernetes resources:

ResourceKindName
CSI driver registrationCSIDrivercsi.flexfs.io
Service accountServiceAccountflexfs-csi-controller
Cluster roleClusterRoleflexfs-csi-controller
Cluster role bindingClusterRoleBindingflexfs-csi-controller
ControllerDeploymentflexfs-csi-controller
Node pluginDaemonSetflexfs-csi-node

The ClusterRole grants the controller the following access:

API groupResourcesVerbs
coordination.k8s.ioleasesget, list, watch, create, update, patch, delete
storage.k8s.iocsinodesget, list, watch
"" (core)eventscreate, list, patch, update, watch
"" (core)nodesget, list, watch
"" (core)podsget, list, watch
"" (core)persistentvolumeclaimsget, list, patch, update, watch
"" (core)persistentvolumeclaims/statuspatch, update
"" (core)persistentvolumescreate, delete, get, list, patch, update, watch
"" (core)secretsget, list
storage.k8s.iostorageclassesget, list, watch

The controller runs three containers:

  1. flexfs-csi-driver — the CSI driver process
  2. csi-provisioner (registry.k8s.io/sig-storage/csi-provisioner:v3.6.4) — the external provisioner that watches for PVCs and calls CreateVolume/DeleteVolume
  3. csi-resizer (registry.k8s.io/sig-storage/csi-resizer:v1.10.1) — performs PVC expansion by calling ControllerExpandVolume

The controller pods use the system-cluster-critical priority class and tolerate CriticalAddonsOnly. They are scheduled only on Linux nodes.

The node DaemonSet runs two containers on every node:

  1. flexfs-csi-driver — the CSI driver process, running in privileged mode
  2. csi-node-driver-registrar (registry.k8s.io/sig-storage/csi-node-driver-registrar:v2.10.1) — registers the CSI driver with kubelet

Key volume mounts on the node pods:

VolumeHost pathContainer pathPurpose
driver-dir{kubeletDir}/plugins/csi.flexfs.io/csiCSI socket
kubelet-dir{kubeletDir}{kubeletDir}Bidirectional mount propagation for FUSE
registration-dir{kubeletDir}/plugins_registry/registrationkubelet plugin registration

All of these paths, plus the --kubeletDir argument passed to the driver process, derive from the kubeletDir value (default: /var/lib/kubelet).

The DaemonSet uses OnDelete update strategy, system-node-critical priority class, and tolerates all taints.

Some Kubernetes distributions run kubelet with a non-standard --root-dir. The most common example is MicroK8s, which uses /var/snap/microk8s/common/var/lib/kubelet.

The kubeletDir value must match the node’s actual kubelet root directory. It controls three things that all have to agree:

  1. The DaemonSet host-path mounts and the csi-node-driver-registrar registration path.
  2. The kubelet-dir volume mountPath inside the node container (which carries Bidirectional mount propagation).
  3. The --kubeletDir argument passed to the driver process, which the driver uses to locate its FUSE base mounts under {kubeletDir}/flexfs.

If kubeletDir does not match the real kubelet root, the driver’s base FUSE mount can still appear on the host, but the per-pod bind mount is created at a path outside the propagated volume and never reaches the pod — so the pod’s mount point looks empty with no error in the logs.

For MicroK8s, install with:

Terminal window
helm install flexfs-csi-driver ./flexfs-csi-driver \
--namespace kube-system \
--set kubeletDir=/var/snap/microk8s/common/var/lib/kubelet

This procedure upgrades an installation of any v1.7, v1.8, or v1.9 release to the current v1.9 release. It has two phases:

  1. Upgrade the chart. This replaces the controller and updates the node DaemonSet definition. Running pods and their mounts are not affected.
  2. Restart the node plugin on each node. This is what puts the new driver into service on a node, and it interrupts the flexFS mounts on that node.

Upgrade the flexFS servers first. Bring every flexFS server to v1.9 (see Upgrades). The driver image contains the v1.9 mount client, and servers are upgraded before mount clients. The v1.9 servers keep serving volumes mounted by an earlier driver, so the cluster keeps working between that step and this one.

Make the v1.9 images available. If your nodes pull from a private registry or mirror, add the driver image and the three sidecar images named under What gets created before you start.

Find the Helm release. The examples use the release name flexfs-csi-driver in the kube-system namespace, and the chart’s default resource names. If yours differ, substitute them throughout:

Terminal window
helm list --all-namespaces

Look for the entry whose chart is flexfs-csi-driver-<version>. If there is none, the driver was installed from manifests: follow Upgrading a manifest installation for the chart step and return here for the rest.

Review your value overrides. List the values supplied when the release was installed:

Terminal window
helm get values flexfs-csi-driver --namespace kube-system

Save the ones you still want in a file such as my-values.yaml, adjusting them for the v1.9 chart:

OverrideAction
driver.imageRemove it to use the v1.9 image, or point it at your copy of the v1.9 image. Left unchanged, it keeps the earlier driver running.
statefulSet.*Rename to deployment.*. Charts earlier than v1.8.56 run the controller as a StatefulSet; the v1.9 chart runs it as a Deployment.
Edited kubelet pathsA chart with no kubeletDir value fixes the kubelet root at /var/lib/kubelet. If you changed those paths by hand, set kubeletDir instead (see MicroK8s and custom kubelet directories).

Check for pending claims. The v1.9 controller attempts to provision every claim of a flexFS StorageClass that is still Pending, with the claim’s requested size as an enforced quota. Delete any you no longer want:

Terminal window
kubectl get pvc --all-namespaces | grep Pending

Step 1: Keep the node plugin from restarting by itself

Section titled “Step 1: Keep the node plugin from restarting by itself”
Terminal window
kubectl -n kube-system patch daemonset flexfs-csi-node --type merge \
-p '{"spec":{"updateStrategy":{"type":"OnDelete","rollingUpdate":null}}}'

With the OnDelete strategy, a node plugin pod is replaced only when you delete it. Installations from v1.8.54 onward already use it. Earlier installations use a rolling update, which restarts every node plugin pod, one after another, as soon as the chart is upgraded. The command is safe to run in either case and does not restart anything.

Download and extract the v1.9 chart (see Download the chart), then:

Terminal window
helm upgrade flexfs-csi-driver ./flexfs-csi-driver \
--namespace kube-system \
--reset-values \
-f my-values.yaml

Omit -f my-values.yaml if you have no overrides. Do not use --reuse-values: it carries over the earlier chart’s defaults, which lack values that the v1.9 templates need.

The upgrade replaces the controller with a Deployment whose pods run three containers, and removes the controller StatefulSet of an earlier chart. Provisioning pauses for a few seconds while the controller pods are replaced. Confirm the result:

Terminal window
# The controller is rolled out
kubectl -n kube-system rollout status deployment/flexfs-csi-controller
# No controller StatefulSet remains ("NotFound" is the expected answer)
kubectl -n kube-system get statefulset flexfs-csi-controller
# The node plugin pods are untouched: their AGE predates the upgrade
kubectl -n kube-system get pods -l app=flexfs-csi-node -o wide

Step 3: Restart the node plugin on each node

Section titled “Step 3: Restart the node plugin on each node”

Repeat for every node, one node at a time:

Terminal window
# 1. Move workloads off the node
kubectl drain <node> --ignore-daemonsets --delete-emptydir-data
# 2. Delete the node plugin pod; the DaemonSet recreates it from the v1.9 image
kubectl -n kube-system delete pod -l app=flexfs-csi-node \
--field-selector spec.nodeName=<node>
# 3. Wait until the new pod shows 2/2 Running, then press Ctrl-C
kubectl -n kube-system get pods -l app=flexfs-csi-node \
--field-selector spec.nodeName=<node> --watch
# 4. Return the node to service
kubectl uncordon <node>

A node that has not been restarted keeps running the earlier driver, which works with the v1.9 controller and servers, so the nodes can be done over as long a period as you need.

If a node cannot be drained, delete its node plugin pod anyway, wait for the replacement to reach 2/2 Running, and then restart every pod on that node that uses a flexFS volume. The driver clears the dead mounts as those pods are removed.

Terminal window
# Every node plugin pod runs the v1.9 image and started after the upgrade
kubectl -n kube-system get pods -l app=flexfs-csi-node \
-o 'custom-columns=NODE:.spec.nodeName,IMAGE:.spec.containers[0].image,STARTED:.status.startTime'
# The driver reports its version
kubectl -n kube-system exec <flexfs-csi-node-pod> -c flexfs-csi-driver -- /sbin/csi.flexfs version

Finally, start a pod that mounts a flexFS volume on an upgraded node and confirm that it can read and write.

Behavior to review after upgrading from v1.7 or v1.8

Section titled “Behavior to review after upgrading from v1.7 or v1.8”

The v1.9 driver differs from v1.7 and v1.8 drivers in ways that can affect existing workloads:

  • A claim’s size is an enforced quota. v1.7 and v1.8 drivers ignore the requested size and create volumes without a limit. Volumes they created stay unlimited and cannot be expanded through their claim. Volumes created by v1.9 are limited to the size requested, so replace placeholder sizes in manifests and volumeClaimTemplates with real ones. See Storage quotas.
  • ReadOnlyMany volumes are mounted read-only. v1.7 and v1.8 drivers mount them read-write unless the pod sets readOnly: true. A workload that writes through such a volume needs ReadWriteMany. See Read-only mounting.
  • Several pods on one node can share a ReadWriteOnce volume. See Access modes.
  • Expanding a volume needs StorageClass settings that a StorageClass written for an earlier release does not have: allowVolumeExpansion: true and the controller-expand-secret parameters. StorageClass parameters cannot be edited, so delete and recreate the StorageClass. Only volumes provisioned afterward can be expanded. See StorageClass parameters.
  • The driver pods use the pod network. Charts through v1.8.50 run them on the host network. Confirm that pods in the driver’s namespace can resolve and reach the flexFS servers and object storage, and update any firewall rule or NetworkPolicy that admits traffic by node address.
  • A node mounts a given volume name for one account at a time. See Multiple volumes on the same node.
Terminal window
helm uninstall flexfs-csi-driver --namespace kube-system