SeaweedFS CSI Driver

repository·master·Indexed 43 days ago

https://github.com/seaweedfs/seaweedfs-csi-driver

A Container Storage Interface (CSI) plugin that enables Kubernetes, Docker, and HashiCorp Nomad to provision and manage storage using SeaweedFS. It supports dynamic and static provisioning, volume expansion, DataLocality, and mount-time parameter updates via VolumeAttributesClass.

Tokens
9.5K
Snippets
26
Records
34
Agent score
54%

What's inside SeaweedFS CSI Driver

  1. Configure DataLocality for optimized Pod I/O

    master

    DataLocality allows you to instruct the driver which volume locations to prefer for Pod reads and writes, optimizing performance based on where the Pod is scheduled.

    Locality Hierarchy

    Settings follow a hierarchy where the more specific level overrides the more general one: Driver < StorageClass < PersistentVolume

    Configuration Levels

    1. Driver: Set via Helm values.yaml (dataLocality) or via DaemonSet arguments (--dataLocality=).
    2. StorageClass: Set via parameter.dataLocality.
    3. PersistentVolume: Set via spec.csi.volumeAttributes.dataLocality.

    Available Options

    • none (default): No locality preference applied.
    • write_preferLocalDc: Sets the DataCenter mount option to the current Node's DataCenter. This makes writes local to the node's DC and allows reads to occur wherever the data is stored.
  2. How the SeaweedFS CSI driver components work together

    master

    The SeaweedFS CSI driver uses a split architecture to manage storage in Nomad:

    • The Controller acts as the control plane. It is responsible for the high-level lifecycle of volumes. When a user executes nomad volume create or nomad volume delete, Nomad communicates with this component. It interacts directly with the SeaweedFS filer.
    • The Node Plugin acts as the data plane. It runs on every worker node in the cluster. Its job is to take a volume managed by the controller and make it available to specific Nomad allocations (tasks) by mounting it. It uses a seaweedfs-mount sidecar that communicates over a shared unix socket to perform the actual mounting operations.

    Both components must be running for a complete lifecycle. If only the node plugin is present, the driver can only register existing SeaweedFS paths rather than creating new ones.

  3. Configure Node Topology for SeaweedFS CSI

    master

    To ensure the Kubernetes scheduler places pods with SeaweedFS PVCs on nodes where the driver is actually running, you must configure topologyKeys. When configured, the driver reports the labels of the nodes it runs on as accessible topology. This populates CSINode.spec.drivers[].topologyKeys, which in turn adds nodeAffinity to provisioned Persistent Volumes (PVs).

    Configuration Options

    You can configure topology keys in two ways:

    1. Helm Chart: Set the topologyKeys field in values.yaml.
    2. CLI Arguments: Use the --topologyKeys= flag on the following containers:
      • csi-seaweedfs-plugin (running in a DaemonSet)
      • seaweedfs-csi-plugin (running in a Deployment)

    Best Practice: The CSI spec prefers a single key prefix across all topology keys. Use keys like topology.kubernetes.io/zone and topology.kubernetes.io/region together.

    Restricting Volume Provisioning via StorageClass

    Once topology keys are configured, you can use a StorageClass to restrict where volumes are provisioned using allowedTopologies.

    # Helm values.yaml example
    topologyKeys:
      - topology.kubernetes.io/zone
    
    # StorageClass example to restrict to a specific zone
    apiVersion: storage.k8s.io/v1
    kind: StorageClass
    metadata:
      name: seaweedfs-zone-a
    provisioner: seaweedfs.csi.seaweedfs.io
    allowedTopologies:
      - matchLabelExpressions:
          - key: topology.kubernetes.io/zone
            values:
              - zone-a
  4. Run a SeaweedFS cluster on Nomad

    master

    If you do not have an existing SeaweedFS cluster, you can deploy one using Nomad. This setup assumes:

    • A running Nomad cluster.
    • At least 3 nodes with static IP addresses.
    • Memory oversubscription enabled in Nomad.
    • A running PostgreSQL instance for the SeaweedFS filer.

    After deployment, the services are accessible via Consul:

    • Master: http://seaweedfs-master.service.consul:9333/
    • Filer: http://seaweedfs-filer.service.consul:8888/
    export NOMAD_ADDR=http://nomad.service.consul:4646
    
    nomad run seaweedfs.hcl
  5. Perform a safe update of the SeaweedFS CSI Driver

    master

    Updating the seaweedfs-csi-driver DaemonSet (DS) can break processes using FUSE mounts because newly created pods will not automatically remount the device.

    To perform a safe rollout, set node.updateStrategy.type: OnDelete for manual updates and follow these steps for each node:

    1. Delete DS pods on nodes that do not currently have a SeaweedFS PV.
    2. Cordon or taint the node.
    3. Evict or delete the pods using a SeaweedFS PV.
    4. Delete the DS pod on that node.
    5. Uncordon the node or remove the taint.
    6. Repeat for all nodes.
  6. Deploy SeaweedFS CSI driver on HashiCorp Nomad

    master

    To use SeaweedFS as a CSI provider in HashiCorp Nomad, you must deploy two distinct components that share the same csi_plugin ID (seaweedfs):

    1. Controller (seaweedfs-csi-controller.hcl): A single service job that manages the volume lifecycle (RPCs). It communicates with the SeaweedFS filer. You must run this to enable nomad volume create commands.
    2. Node (seaweedfs-csi.hcl): A system job that runs on every worker node. It handles staging and publishing volumes to allocations using a seaweedfs-mount sidecar via a shared unix socket.

    Note: If you do not run the controller, you cannot use nomad volume create. Instead, you must manually pre-create the bucket or directory in SeaweedFS and use nomad volume register to register the existing volume.

    export NOMAD_ADDR=http://nomad.service.consul:4646
    
    # Start CSI controller (one instance)
    nomad run seaweedfs-csi-controller.hcl
    
    # Start CSI node (one per worker)
    nomad run seaweedfs-csi.hcl
    
    # Verify plugin status
    nomad plugin status seaweedfs
    
    # Create a volume
    nomad volume create example-seaweedfs-volume.hcl
    
    # Run an application using the volume
    nomad run example-seaweed-app.hcl
  7. Test the SeaweedFS CSI Driver installation

    master

    Follow these steps to verify the driver is working correctly:

    1. Create a PVC: Apply a sample PVC (5GiB) using the seaweedfs-storage storage class:
      kubectl apply -f deploy/kubernetes/sample-seaweedfs-pvc.yaml
    2. Verify Binding: Check that the PVC status is Bound:
      kubectl get pvc
    3. Deploy a Workload: Once bound, mount the volume using a sample pod:
      kubectl apply -f deploy/kubernetes/sample-busybox-pod.yaml
    4. Verify Mount: Execute df -h inside the pod to confirm the storage is mounted:
      kubectl exec my-csi-app -- df -h
    kubectl apply -f deploy/kubernetes/sample-seaweedfs-pvc.yaml
    kubectl get pvc
    kubectl apply -f deploy/kubernetes/sample-busybox-pod.yaml
    kubectl exec my-csi-app -- df -h
  8. Configure Static and Dynamic Provisioning

    master

    The driver supports both dynamic and static provisioning.

    Dynamic Provisioning

    By default, the driver creates a separate folder (/buckets/<volume-id>) and a separate collection (volume-id) for every request. You can customize this by creating a StorageClass with specific parameters:

    kind: StorageClass
    apiVersion: storage.k8s.io/v1
    metadata:
      name: seaweedfs-special
    provisioner: seaweedfs-csi-driver
    parameters:
      collection: mycollection
      replication: "011"
      diskType: "ssd"

    Static Provisioning

    To access a specific folder from different pods with ReadWriteMany access, create a PersistentVolume (PV) manually and then bind a PersistentVolumeClaim (PVC) to it.

    Example PV:

    apiVersion: v1
    kind: PersistentVolume
    metadata:
      name: seaweedfs-static
    spec:
      accessModes:
      - ReadWriteMany
      capacity:
        storage: 1Gi
      csi:
        driver: seaweedfs-csi-driver
        volumeHandle: dfs-test
        volumeAttributes:
          collection: default
          replication: "011"
          path: /path/to/files
          diskType: "ssd"
        readOnly: true
      persistentVolumeReclaimPolicy: Retain
      volumeMode: Filesystem

    Example PVC:

    apiVersion: v1
    kind: PersistentVolumeClaim
    metadata:
      name: seaweedfs-static
    spec:
      storageClassName: ""
      volumeName: seaweedfs-static
      accessModes:
      - ReadWriteMany
      resources:
        requests:
          storage: 1Gi
    kind: StorageClass
    apiVersion: storage.k8s.io/v1
    metadata:
      name: seaweedfs-special
    provisioner: seaweedfs-csi-driver
    parameters:
      collection: mycollection
      replication: "011"
      diskType: "ssd"
  9. Build the SeaweedFS CSI-Driver Docker plugin

    master

    To build the plugin manually, you can use the following sequence of commands. This process builds a Docker image, exports its filesystem to a rootfs directory, and creates a Docker plugin from that directory.

    Note: The build script expects arguments for [PREFIX] [VERSION] [TAG] [PLUGIN_NAME] [ARCH].

    #!/bin/bash
    USAGE="Usage: ./build.sh [PREFIX] [VERSION] [TAG] [PLUGIN_NAME] [ARCH]"
    
    if [[ "$1" == "-h" ]]; then
      echo "$USAGE"
      exit 0
    fi
    
    VERSION=${2:-latest}
    ARCH=${5:-linux/amd64}
    PLUGIN_NAME=${4:-swarm-csi-swaweedfs}
    PLUGIN_TAG=${3:-v1.2.0}
    PREFIX=${1:-gradlon}
    
    docker build --platform ${ARCH} --build-arg BASE_IMAGE=chrislusf/seaweedfs-csi-driver:${VERSION} --build-arg ARCH=$ARCH -t seawadd-csi_tmp_img .
    mkdir -p ./plugin/rootfs
    cp config.json ./plugin/
    docker container create --name seawadd-csi_tmp seawadd-csi_tmp_img 
    docker container export seawadd-csi_tmp | tar -x -C ./plugin/rootfs
    docker container rm -vf seawadd-csi_tmp 
    docker image rm seawadd-csi_tmp_img 
    
    docker plugin disable ${PREFIX}/swarm-csi-swaweedfs:v1.2.0
    docker plugin rm ${PREFIX}/${PLUGIN_NAME}:${PLUGIN_TAG} 2> /dev/null || true
    docker plugin create ${PREFIX}/${PLUGIN_NAME}:${PLUGIN_TAG} ./plugin
    docker plugin push ${PREFIX}/${PLUGIN_NAME}:${PLUGIN_TAG}
    rm -rf ./plugin/
    #!/bin/bash
    USAGE="Usage: ./build.sh [PREFIX] [VERSION] [TAG] [PLUGIN_NAME] [ARCH]"
    
    if [[ "$1" == "-h" ]]; then
      echo "$USAGE"
      exit 0
    fi
    
    VERSION=${2:-latest}
    ARCH=${5:-linux/amd64}
    PLUGIN_NAME=${4:-swarm-csi-swaweedfs}
    PLUGIN_TAG=${3:-v1.2.0}
    PREFIX=${1:-gradlon}
    
    docker build --platform ${ARCH} --build-arg BASE_IMAGE=chrislusf/seaweedfs-csi-driver:${VERSION} --build-arg ARCH=$ARCH -t seawadd-csi_tmp_img .
    mkdir -p ./plugin/rootfs
    cp config.json ./plugin/
    docker container create --name seawadd-csi_tmp seawadd-csi_tmp_img 
    docker container export seawadd-csi_tmp | tar -x -C ./plugin/rootfs
    docker container rm -vf seawadd-csi_tmp 
    docker image rm seawadd-csi_tmp_img 
    
    docker plugin disable ${PREFIX}/swarm-csi-swaweedfs:v1.2.0
    docker plugin rm ${PREFIX}/${PLUGIN_NAME}:${PLUGIN_TAG} 2> /dev/null || true
    docker plugin create ${PREFIX}/${PLUGIN_NAME}:${PLUGIN_TAG} ./plugin
    docker plugin push ${PREFIX}/${PLUGIN_NAME}:${PLUGIN_TAG}
    rm -rf ./plugin/
  10. Configure DataCenter locality for Volume-Servers and CSI-Driver-Node

    master

    For correct operation, both Volume-Servers and the CSI-Driver-Node must have the DataCenter locality option correctly set. This ensures the driver can correctly identify data locality.

    Automatic injection in Kubernetes

    Because Kubernetes' DownwardAPI does not support mapping node labels (containing region/zone information) directly to environment variables, you must use a workaround if you want automatic injection.

    Using KubeMod: If KubeMod is installed in your cluster, you can automate this via the Helm chart configuration:

    1. Enable injection in values.yaml: node.injectTopologyInfoFromNodeLabel.enabled: true.
    2. Specify which labels to grab using node.injectTopologyInfoFromNodeLabel.labels.

    It is recommended to use well-known Kubernetes topology labels (e.g., topology.kubernetes.io/zone or topology.kubernetes.io/region) to avoid configuration errors.

  11. Install and configure the SeaweedFS CSI-Driver Docker Plugin

    master

    The SeaweedFS CSI-Driver Docker Plugin allows you to use SeaweedFS as a volume driver in Docker environments.

    Installation Steps

    1. Install the plugin: Use docker plugin install with the --disable flag to prevent immediate activation.
    2. Configure settings: Use docker plugin set to define environment variables like FILER endpoints.
    3. Enable the plugin: Activate the plugin using docker plugin enable.

    Example Workflow

    # Install the plugin
    docker plugin install --disable --alias seaweedfs-csi:swarm --grant-all-permissions gradlon/swarm-csi-swaweedfs:v1.2.0
    
    # Set the Filer endpoint(s)
    docker plugin set seaweedfs-csi:swarm FILER=<IP>:8888,<IP>:8888
    
    # Set cache size (in MB)
    docker plugin set seaweedfs-csi:swarm CACHE_SIZE=512
    
    # Enable the plugin
    docker plugin enable seaweedfs-csi:swarm
    docker plugin install --disable --alias seaweedfs-csi:swarm --grant-all-permissions gradlon/swarm-csi-swaweedfs:v1.2.0
    docker plugin set seaweedfs-csi:swarm FILER=<IP>:8888,<IP>:8888
    docker plugin set seaweedfs-csi:swarm CACHE_SIZE=512
    docker plugin enable seaweedfs-csi:swarm
  12. Install SeaweedFS CSI Driver via Helm

    master

    The recommended way to install the driver is using Helm.

    1. Add the repository:

      helm repo add seaweedfs-csi-driver https://seaweedfs.github.io/seaweedfs-csi-driver/helm
      helm repo update seaweedfs-csi-driver
    2. Install with a single Filer: Clone the project and install by setting the seaweedfsFiler value:

      git clone https://github.com/seaweedfs/seaweedfs-csi-driver.git
      helm install --set seaweedfsFiler=<filerHost:port> seaweedfs-csi-driver ./deploy/helm/seaweedfs-csi-driver
    3. Install with multiple Filers: To provide multiple filer addresses, use a comma-separated list (ensure you escape commas if using --set in some shells):

      helm install seaweedfs-csi-driver ./deploy/helm/seaweedfs-csi-driver/ \
        --namespace seaweedfs-csi-driver \
        --set seaweedfsFiler="<filerHost:port>\,<filerHost:port>\,<filerHost:port>"
    4. Uninstall:

      helm uninstall seaweedfs-csi-driver
    helm install --set seaweedfsFiler=<filerHost:port> seaweedfs-csi-driver ./deploy/helm/seaweedfs-csi-driver