This is the generic Kubernetes path — static access key/secret key credentials, any supported vendor (S3/AWS, GCS, Azure, Wasabi, Aliyun, Cloudflare, Oracle, S3-compatible), on any Kubernetes cluster.

On AWS EKS and you want an AWS Marketplace-compliant install (IRSA, no static AWS credentials), use the EKS quick start instead — EKS is just another Kubernetes cluster from the driver's point of view unless you specifically opt into IRSA.


Prerequisites

  • A Kubernetes cluster with kubectl and helm (v3+) configured against it
  • A valid mapfs license (email + token, from https://mapfs.cloud/)
  • Access credentials for your target cloud storage (access_key/secret_key, or an Azure connectionString)
  • An existing bucket / container — this guide uses my-mapfs-bucket in us-east-1 as the running example; substitute your own

Step 1: Download the Manifests

$ wget https://mapfs.cloud/dist/mapfs-csi-manifests-kubernetes-1.1.3.tar.gz
$ tar xzf mapfs-csi-manifests-kubernetes-1.1.3.tar.gz && cd mapfs-csi-manifests-kubernetes-1.1.3

Step 2: Deploy the ChannelServer

One per cluster, not per-volume. Every mount-daemon pod connects to this for cache-invalidation fan-out.

$ kubectl apply -f channel-server.yaml
$ kubectl -n kube-system get pod -l app=mapfs-channel     # wait for Running

Step 3: Install the mapfs-csi Driver

This is a one-time, per-cluster step. It doesn't need any cloud/bucket information — just your mapfs license.

$ helm install mapfs-csi oci://registry-1.docker.io/wyflow/mapfs-csi-chart --version 1.1.3 \
  --set license.email=you@example.com \
  --set license.token=<token-from-mapfs-portal> \
  --set channelServer.address=mapfs-channel.kube-system.svc.cluster.local:7777

channelServer.address is required — without it, mount-daemon pods fail to start.

On Graviton (arm64) nodes, also add:

--set nodeSelector."kubernetes\.io/arch"=arm64

— though this only matters for a cluster with a mix of amd64 and arm64 nodes; a homogeneous arm64 cluster works fine without it (images are published multi-arch, so kubelet already pulls the matching-arch image per node with no scheduling hint needed).

Check status — both should reach Running before continuing:

$ kubectl -n kube-system get pod -l app=mapfs-csi-controller
$ kubectl -n kube-system get pod -l app=mapfs-csi-node

To upgrade to a newer version later:

$ helm upgrade mapfs-csi oci://registry-1.docker.io/wyflow/mapfs-csi-chart --version <new-version>

Step 4: Configure a Storage Backend

Repeat this step for every bucket/cloud you want to expose to the cluster — it's independent of Step 3, and doesn't require reinstalling or upgrading the driver.

Create the credentials Secret (real access_key/secret_key for your bucket, not the placeholders below):

$ kubectl create secret generic mapfs-cloud-creds -n kube-system \
  --from-literal=access_key=<AccessKeyID> \
  --from-literal=secret_key=<SecretAccessKey>

For Azure Blob Storage, use connectionString instead of the two fields above — see the comments in cloud-secret.yaml.

Edit storageclass.yaml: fill in at least cloud and bucket (some clouds also need region/endpoint/accountId/ociNamespace — see the comments in the file for details). Continuing the running example:

--- storageclass.yaml (template)
+++ storageclass.yaml
@@
   cloud: "s3"
-  bucket: "my-bucket-name"
+  bucket: "my-mapfs-bucket"
@@
-  # region: "us-east-1"     # required: s3/aws, gcs, wasabi, aliyun, oracle
+  region: "us-east-1"

Then apply it:

$ kubectl apply -f storageclass.yaml
$ kubectl get storageclass mapfs-s3

Step 5: Create a PVC and Mount a Volume

With storageclass.yaml applied, csi-provisioner creates the PV automatically the moment a matching PVC is created — no manual PV needed. Save this as my-pvc.yaml:

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: my-pvc
spec:
  accessModes: ["ReadWriteMany"]
  resources:
    requests:
      storage: 1Ti
  storageClassName: mapfs-s3   # must match metadata.name in storageclass.yaml

And this as my-app.yaml:

apiVersion: v1
kind: Pod
metadata:
  name: my-app
spec:
  containers:
    - name: app
      image: ubuntu:22.04
      command: ["sleep", "infinity"]
      volumeMounts:
        - name: cloud-data
          mountPath: /data
  volumes:
    - name: cloud-data
      persistentVolumeClaim:
        claimName: my-pvc

Apply both and wait for the pod to start:

$ kubectl apply -f my-pvc.yaml -f my-app.yaml
$ kubectl get pv,pvc
$ kubectl get pod my-app -w        # wait for Running

Verify from inside the application pod — a non-local filesystem type (not overlay/tmpfs) confirms the mount succeeded:

$ kubectl exec my-app -- df -h /data

For independent confirmation straight from the mount-daemon pod itself (proves the CSI node plugin → mapfs mount → ChannelServer path end to end, not just that something got mounted into /data), look it up by the PV's volume handle, which the driver labels the pod with:

$ VOLNAME=$(kubectl get pv -o jsonpath='{.items[?(@.spec.claimRef.name=="my-pvc")].spec.csi.volumeHandle}')
$ kubectl -n kube-system get pod -l mapfs.cloud/volume=$VOLNAME
NAME                                          READY   STATUS    RESTARTS   AGE
ip-10-0-1-23.ec2.internal-pvc-a1b2c3d4         1/1     Running   0          2m

$ kubectl -n kube-system exec ip-10-0-1-23.ec2.internal-pvc-a1b2c3d4 -- sh -c "ls /var/lib/mapfs/mounts/$VOLNAME"
$ kubectl -n kube-system exec ip-10-0-1-23.ec2.internal-pvc-a1b2c3d4 -- mapfs stat

/var/lib/mapfs/mounts/<volume-name> is where the daemon actually mounts the bucket inside its own pod — listing it should show the same files as /data did from my-app. stat (with no arguments) prints the daemon's own request/cache counters for this mount; see /docs/k8s/commands.html for the other helper commands it accepts.

Static provisioning (pointing at an existing bucket/volume by hand instead of a PVC-driven one), Azure Blob Storage, and self-hosted MinIO all follow the same shape but start from different template files — see the concrete before/after examples for each in /docs/k8s/k8s_deploy.html.


Uninstalling

Removing what this guide created, in order:

$ kubectl delete -f my-app.yaml -f my-pvc.yaml
$ kubectl delete -f storageclass.yaml
$ kubectl -n kube-system delete secret mapfs-cloud-creds

A StorageClass/PV with reclaimPolicy: Retain never deletes data in the cloud bucket — deleting the PV only removes the Kubernetes record.

Uninstalling the driver (only once no storage backend depends on it anymore):

$ helm uninstall mapfs-csi
$ kubectl delete -f channel-server.yaml

Full Documentation

For directory layout, upgrades, and concrete examples for every YAML template (static provisioning, Azure, MinIO), see:
/docs/k8s/k8s_deploy.html
On AWS EKS and want IRSA / AWS Marketplace compliance instead of static credentials, see:
/docs/k8s/eks_quickstart.html
For helper commands (load/stat/help/version), see:
/docs/k8s/commands.html


Support

support@mapfs.cloud