# SEAWEEDFS - helm chart (2.x+) ### Add the helm repo ```bash helm repo add seaweedfs https://seaweedfs.github.io/seaweedfs/helm ``` ### Install the helm chart ```bash helm install seaweedfs seaweedfs/seaweedfs ``` ### (Recommended) Provide `values.yaml` ```bash helm install --values=values.yaml seaweedfs seaweedfs/seaweedfs ``` ## Info: * master/filer/volume are stateful sets with anti-affinity on the hostname, so your deployment will be spread/HA. * leveldb2 is the default filer backend; a mysql-compatible database (memsql, ...) enables HA (multiple filer instances) and the backup/HA it can provide. * with `filer.extraEnvironmentVars.WEED_MYSQL_ENABLED` set to `"true"`, mysql user/password are created in a k8s secret (default: `-seaweedfs-db-secret`) and injected to the filer with ENV. On any other store neither the secret nor the `WEED_MYSQL_*` env, plain or secret-backed, is rendered. * cert config exists and can be enabled, but not been tested, requires cert-manager to be installed. ## Prerequisites ### Database leveldb is the default database, this supports multiple filer replicas that will [sync automatically](https://github.com/seaweedfs/seaweedfs/wiki/Filer-Store-Replication), with some [limitations](https://github.com/seaweedfs/seaweedfs/wiki/Filer-Store-Replication#limitation). When the [limitations](https://github.com/seaweedfs/seaweedfs/wiki/Filer-Store-Replication#limitation) apply, or for a large number of filer replicas, an external datastore is recommended. Such as MySQL-compatible database, as specified in the `values.yaml` at `filer.extraEnvironmentVars`. This database should be pre-configured and initialized. If using the default `db-init-config`, the configmap name is now dynamic (e.g., `-seaweedfs-db-init-config`). You can override this name via `filer.dbInitConfigName`. To initialize manually: ```sql CREATE TABLE IF NOT EXISTS `filemeta` ( `dirhash` BIGINT NOT NULL COMMENT 'first 64 bits of MD5 hash value of directory field', `name` VARCHAR(766) NOT NULL COMMENT 'directory or file name', `directory` TEXT NOT NULL COMMENT 'full path to parent directory', `meta` LONGBLOB, PRIMARY KEY (`dirhash`, `name`) ) DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin; ``` Alternative database can also be configured (e.g. leveldb, postgres) following the instructions at `filer.extraEnvironmentVars`. #### RocksDB variant The `_large_disk_rocksdb` image tag ships with RocksDB pre-configured as the filer backend. To use this image with the Helm chart, override the image on all three components and disable the chart's default `WEED_LEVELDB2_ENABLED`, which would otherwise re-enable LevelDB2 and override the image's built-in RocksDB configuration: ```yaml # Replace with the desired seaweedfs version, e.g. 3.80_large_disk_rocksdb. master: imageOverride: chrislusf/seaweedfs:_large_disk_rocksdb volume: imageOverride: chrislusf/seaweedfs:_large_disk_rocksdb filer: enablePVC: true imageOverride: chrislusf/seaweedfs:_large_disk_rocksdb extraEnvironmentVars: WEED_LEVELDB2_ENABLED: "false" ``` Notes: * `master` and `volume` use the same image tag so that all components share a consistent SeaweedFS build; RocksDB itself is only used by the filer. * `filer.enablePVC: true` (or another form of persistent storage for the filer) is required so that the RocksDB metadata store survives pod restarts — otherwise metadata will be lost. ### Node Labels Kubernetes nodes can have labels which help to define which node(Host) will run which pod: Here is an example: * s3/filer/master needs the label **sw-backend=true** * volume need the label **sw-volume=true** to label a node to be able to run all pod types in k8s: ``` kubectl label node YOUR_NODE_NAME sw-volume=true sw-backend=true ``` on production k8s deployment you will want each pod to have a different host, especially the volume server and the masters, all pods (master/volume/filer) should have anti-affinity rules to disallow running multiple component pods on the same host. If you still want to run multiple pods of the same component (master/volume/filer) on the same host please set/update the corresponding affinity rule in values.yaml to an empty one: ```affinity: ""``` ## PVC - storage class ### On the volume stateful set added support for k8s PVC, currently example with the simple local-path-provisioner from Rancher (comes included with k3d / k3s) https://github.com/rancher/local-path-provisioner you can use ANY storage class you like, just update the correct storage-class for your deployment. ### Master data: hostPath vs a claim The master's `-mdir` holds its Raft log and snapshots, and with them the cluster's identity (its topology UUID). `master.data.type` defaults to `hostPath`, which does not follow a pod to another node: a master that is rescheduled comes back with an empty data directory and a brand new cluster UUID. With the chart's default of a single master replica there is no peer to recover the identity from either. Putting the master's data on a claim avoids that: ```yaml master: data: type: "persistentVolumeClaim" size: "1Gi" storageClass: "" # empty uses the cluster's default StorageClass ``` Raft state is small, so a modest claim is enough — sizing matters far more for volume and filer. The default is left at `hostPath` for backward compatibility: `volumeClaimTemplates` is immutable on a StatefulSet, so flipping the type on a release that already exists fails, whether the chart changes the default or you change it yourself: ```text StatefulSet.apps "-seaweedfs-master" is invalid: spec: Forbidden: updates to statefulset spec for fields other than 'replicas', ... are forbidden ``` New installs can set the claim from the start. To move an **existing** release onto a claim without losing the cluster UUID, use the migration below. The claim has to be seeded while the master is stopped: a running master rewrites its Raft state, so copying into a live pod is silently undone by the next restart. The steps below are for the chart's default of a single master (`master.replicas: 1`). With several master replicas, repeat steps 1, 3 and 4 for every ordinal, or migrate one at a time and let the remaining quorum re-replicate. Take the names from the cluster rather than assembling them — the release name, `nameOverride` and `fullnameOverride` all feed the chart's fullname helper, so `-seaweedfs` is not always right: ```bash NS=; REL= # scope by instance as well as component: several releases can share a namespace STS=$(kubectl -n $NS get sts \ -l app.kubernetes.io/instance=$REL,app.kubernetes.io/component=master \ -o jsonpath='{.items[0].metadata.name}') POD=$STS-0 # a StatefulSet names its claims