# Storage Requirements for Self-Deployment

> The ReadWriteMany and ReadWriteOnce storage that Sisense needs, the StorageClasses each installation method creates or expects, platform-specific behavior, and how to verify storage before you install.

*Source: https://docs.sisense.com/main/SisenseLinux/self-deployment-storage-requirements.htm*

---

Last updated: October 21, 2026

|  |  |
| --- | --- |
| [Tier](https://www.sisense.com/pricing/#pricing) | [Deployment](https://docs.sisense.com/main/SisenseLinux/introduction-to-sisense-cloud-managed-services.md#ComparisonofManagedCloudandSelfHosted) |
| Enterprise | On-Prem |

This page describes the storage that Sisense needs, the StorageClasses that each installation method creates or expects, platform-specific behavior that can prevent Sisense from starting, and how to verify your storage before you install.

To compare the installation methods, see [Choosing an Installation Method](https://docs.sisense.com/main/SisenseLinux/choosing-an-installation-method.md).

## What Sisense Needs

In cluster mode (multiple nodes, or any cloud-managed or shared cluster), Sisense needs one ReadWriteMany (RWX) volume that all Sisense services share, and ReadWriteOnce (RWO) volumes for its stateful components. In single-node mode, all of these are hostPath directories on the node (see [Single-Node (hostPath) Mode](#SingleNode)).

| Volume | Access Mode | Default Size | Notes |
| --- | --- | --- | --- |
| Shared application storage (PersistentVolumeClaim `storage`) | ReadWriteMany | 70 Gi  On Azure: 1200 Gi | Mounted at */opt/sisense/storage* by most Sisense services at the same time, across nodes.  Size: `sisense-utils.sisenseDiskSize` (Helm), `sisense_disk_size` (*sisense.sh*), `persistence.sisenseDiskSize` (Provisioner). When `global.kubernetesCloudProvider` is `azure`, the chart requests the larger of `sisense-utils.sisenseDiskSize` and `sisense-utils.azureDefaultDiskSize` (default 1200). |
| MongoDB data | ReadWriteOnce | 20 Gi per replica | Three replicas with high availability (`mongodb.replicaCount`, default 3). Size: `mongodb.persistence.size` (Helm), `mongodb_disk_size` (*sisense.sh*), `persistence.mongodbDiskSize` (Provisioner). |
| ZooKeeper data | ReadWriteOnce | Helm: 8 Gi per replica  *sisense.sh* and Provisioner: 2 Gi per replica | Size: `zookeeper.persistence.size` (Helm), `zookeeper_disk_size` (*sisense.sh*), `persistence.zookeeperDiskSize` (Provisioner). |
| Dgraph data | ReadWriteOnce | 3 Gi each for Dgraph alpha and Dgraph zero | Size: `dgraph-ha.alpha.persistence.size` and `dgraph-ha.zero.persistence.size`. |
| Grafana data | ReadWriteOnce | 3 Gi | Grafana is deployed by default. Size: `grafana.persistence.size`. |
| MongoDB Search index (`mongot`, public preview) | ReadWriteOnce | 10 Gi | Cluster mode only, when `mongot.persistence.enabled` is `true` (the default). On a single node, `mongot` uses an `emptyDir` volume. |
| RabbitMQ | None | - | The Sisense chart disables RabbitMQ persistence. |

### Ownership: UID and GID 1000

Sisense services run with UID 1000, GID 1000, and `fsGroup` 1000 (`global.securityContext` in Helm; `run_as_user`, `run_as_group`, and `fs_group` in *sisense.sh*), with `fsGroupChangePolicy: OnRootMismatch`. The shared RWX volume must be writable by UID and GID 1000:

- On first start, an init container creates the directory tree on the shared volume with owner 1000:1000.
- After installation and before every upgrade, the `storage-manager` Job changes the owner of files on the shared volume that are not owned by the configured UID and GID.

Some storage backends do not let a pod change file ownership (for example, Azure Files over SMB, or an NFS export that maps users). With these backends, ownership must come from the StorageClass mount options or from the export settings. Otherwise, Sisense pods fail to start with permission errors on */opt/sisense/storage*. If you run Sisense with a different UID or GID, change the ownership settings of your storage to match.

## StorageClasses by Installation Method

### Helm

You provide both StorageClasses. These values control them:

- **`global.clusterMode.enabled`**: Set to `true` to use StorageClasses instead of hostPath volumes.
- **`global.storageClass`** (RWO): The default, `manual`, is the class of the hostPath PersistentVolumes that the chart creates in single-node mode. In cluster mode, MongoDB, ZooKeeper, Dgraph, and `mongot` use this value in their volume claim templates. If you leave it as `manual`, their PersistentVolumeClaims stay `Pending`. Set it to your RWO class (for example, `gp3` on EKS, `managed-csi` on AKS, or `standard-rwo` on GKE). Grafana does not use this value: it uses `grafana.persistence.storageClassName`, or the cluster's default class when that is not set.
- **`sisense-utils.rwxScName`** (RWX): The StorageClass of the shared `storage` volume. Setting it explicitly is the simplest option.
- **`global.storageType`**: Set it to a value that describes your RWX backend: `efs`, `fsx`, `nfs`, `azurefile`, `rook-ceph`, or `custom-rwx`. If you leave it empty, Sisense services treat the storage as hostPath. Only `fsx` changes how Sisense runs (see [Amazon FSx for Lustre](#FSx)).

The chart chooses the StorageClass of the shared `storage` volume in this order:

1. `sisense-utils.rwxScName`, if set.
2. By `global.storageType`: `efs` uses `aws-efs`; `fsx` uses `aws-fsx`; `nfs` uses `nfs-csi` (or `nfs-client` when `global.storageClass` is `nfs-client`); `rook-ceph` uses `rook-cephfs-r3`.
3. On OpenShift (`global.isOpenshift: true`): `sisense-utils.rwxScName`, so you must set it.
4. When `global.kubernetesCloudProvider` is `azure`: `sisense-azurefile-premium`, or `sisense-azurefile-csi-premium` when `sisense-utils.azureCsi.enabled` is `true`.
5. Otherwise, no StorageClass is set, and the cluster's default class is used. This works only if the default class supports ReadWriteMany.

The chart does not create any of the StorageClasses named in steps 2 and 4. When you install with Helm, either create them, or set `sisense-utils.rwxScName` to a class that already exists.

### Provisioner

Set `persistence.enabled: true` for cluster mode. When it is `false` (the default), Sisense uses hostPath storage under */opt/sisense* on a single node. With `persistence.enabled: true`, set exactly one of these:

- `persistence.storageType`, so that the Provisioner installs the storage driver and StorageClasses for you, or
- Both `persistence.rwxScName` and `persistence.rwoScName`, to use StorageClasses that already exist.

If you set `persistence.storageType` together with both class names, or set neither, the Provisioner stops with an error. See [Installing Sisense using Provisioner and Helm](https://docs.sisense.com/main/SisenseLinux/installing-sisense-using-provisioner-and-helm.md).

### *sisense.sh*

In the configuration file, `storage_type` determines what the installer installs. When neither `storage_type` nor `rwx_sc_name` is set, Sisense is installed in single-node mode.

| storage\_type | What the Installer Installs | RWX StorageClass | RWO StorageClass |
| --- | --- | --- | --- |
| Empty (single node) | The `manual` StorageClass. Data is stored in hostPath directories. | - | `manual` |
| `rook-ceph` | The Rook operator in the `rook-ceph` namespace, a Ceph cluster, a block pool, and a CephFS file system. Your own Linux servers only. | `rook-cephfs-r3` | `rook-ceph-block` |
| `fsx` | On AWS: the EBS CSI driver (if it is not already installed) and a `gp3` StorageClass, the FSx for Lustre CSI driver, and the `aws-fsx` StorageClass. Requires `fsx_dns_name` and `fsx_mount_name`. | `aws-fsx` | `gp3` |
| `efs` | On AWS: the EBS CSI driver (if it is not already installed) and a `gp3` StorageClass, and the EFS provisioner. Requires `efs_file_system_id` and `efs_aws_region`. | `aws-efs` | `gp3` |
| `nfs` | The NFS CSI driver with the `nfs-csi` StorageClass (skipped if an `nfs-client` StorageClass already exists). On AWS, also the EBS CSI driver (if it is not already installed) and a `gp3` StorageClass. Requires `nfs_server` and `nfs_path`. | `nfs-csi` | `gp3` on EKS, `standard` on GKE, `default` on AKS, otherwise `nfs-csi` |
| `azurefile` | An Azure Files Premium StorageClass with the mount options shown in [Azure Files](#Azure). With `azure_csi.enabled: true`, the installer creates the CSI-based class and stops if the AKS CSI storage drivers are not enabled. | `sisense-azurefile-premium`, or `sisense-azurefile-csi-premium` with `azure_csi.enabled: true` | `default` |
| Any value, or empty, with `rwx_sc_name` and `rwo_sc_name` | For `nfs-server`, `cephfs`, `trident`, and `portworx`, and when `storage_type` is empty, the installer installs no storage driver. It checks that the StorageClasses you name exist. | The value of `rwx_sc_name` | The value of `rwo_sc_name` |

**Note:**

- On AWS, when the installer creates the `gp3` StorageClass, it marks it as the cluster's default StorageClass. If you manage the EBS CSI driver and your StorageClasses yourself, set `rwx_sc_name` and `rwo_sc_name` instead.
- The installer installs storage drivers only when `cluster_visibility` is `true` (the default).

## Platform-Specific Behavior

### Azure Files

Azure Files over SMB does not support changing file ownership or permissions. Every file appears with the `uid`, `gid`, `file_mode`, and `dir_mode` set in the StorageClass mount options. If they do not match the UID and GID that Sisense runs as (1000 by default), Sisense pods that use the shared volume fail to start.

This is the CSI-based StorageClass that *sisense.sh* creates. When you install with Helm, create an equivalent class and set `sisense-utils.rwxScName` to its name:

[Copy](javascript:void(0);)

```
apiVersion: storage.k8s.io/v1  
kind: StorageClass  
metadata:  
  name: sisense-azurefile-csi-premium  
provisioner: file.csi.azure.com  
allowVolumeExpansion: true  
parameters:  
  skuName: Premium_LRS  
reclaimPolicy: Delete  
volumeBindingMode: Immediate  
mountOptions:  
  - dir_mode=0777  
  - file_mode=0777  
  - uid=1000          # must match the UID that Sisense runs as  
  - gid=1000          # must match the GID that Sisense runs as  
  - mfsymlinks  
  - cache=strict  
  - nosharesock  
  - actimeo=30
```

The non-CSI class that *sisense.sh* creates when `azure_csi.enabled` is `false` (`sisense-azurefile-premium`, provisioner `kubernetes.io/azure-file`) uses the first six of these mount options.

Size: on Azure, the shared volume requests the larger of `sisense-utils.sisenseDiskSize` and `sisense-utils.azureDefaultDiskSize` (default 1200 Gi; `azure_default_disk_size` for *sisense.sh*). Azure Files Premium performance scales with the provisioned share size. If you lower this value, do so deliberately.

See also [Deploying Sisense on Azure Kubernetes Service](https://docs.sisense.com/main/SisenseLinux/deploying-sisense-on-azure-kubernetes-service.md) and [Deploying Sisense on AKS with Azure Files Premium](https://docs.sisense.com/main/SisenseLinux/deploying-sisense-on-aks-with-azure-files-premium-csi-drivers.md).

### Amazon EFS

With Helm, the chart expects a StorageClass named `aws-efs` when `global.storageType` is `efs`, unless you set `sisense-utils.rwxScName`. Make sure that UID and GID 1000 can write to the directory that Sisense mounts, for example by using an EFS access point that sets the owner to 1000:1000. See [Installing Sisense on a Multi-Node Cluster with EFS as the Shared Storage](https://docs.sisense.com/main/SisenseLinux/installing-sisense-on-multinode-cluster-with-efs.md).

### Amazon FSx for Lustre

With `global.storageType: fsx`, the chart creates a static PersistentVolume for the shared volume, with StorageClass `aws-fsx` and the mount option `flock`. Set `sisense-utils.fsxDnsName` and `sisense-utils.fsxMountName` (`fsx_dns_name` and `fsx_mount_name` for *sisense.sh*). The FSx for Lustre CSI driver (`fsx.csi.aws.com`) must be installed in the cluster; *sisense.sh* installs it for you.

If the mount name ends with a slash (`/`), each Sisense namespace uses its own sub-directory of the file system. This lets several Sisense deployments share one FSx file system. See [Deploying Sisense on EC2 with Amazon FSx for Lustre](https://docs.sisense.com/main/SisenseLinux/deploying-sisense-on-ec2-with-amazon-fsx-for-lustre.md).

### NFS

The `nfs-csi` StorageClass that *sisense.sh* creates uses the mount option `nolock`, reclaim policy `Retain`, and volume binding mode `Immediate`. If you bring your own NFS StorageClass, make sure that the export allows UID and GID 1000 to create and write files.

### Rook-Ceph (Your Own Linux Servers)

With `storage_type: rook-ceph`, each server needs an unpartitioned, unmounted block device, set in `disk_volume_device` for that server in *cluster\_config.yaml*. Server names must be in lowercase letters. The installer checks that each device is at least this size (in GB):

`mongodb_disk_size × 3 + zookeeper_disk_size × 3 + sisense_disk_size + 3`

**Important:**

When you uninstall the cluster with `storage_type: rook-ceph`, the installer erases the block device on every server. All data on these devices is lost.

### Single-Node (hostPath) Mode

Single-node mode applies when `global.clusterMode.enabled` is `false` (Helm), when neither `storage_type` nor `rwx_sc_name` is set (*sisense.sh*), or when `persistence.enabled` is `false` (Provisioner). Sisense then stores its data in hostPath directories on the node:

- */opt/sisense/storage* (shared application storage)
- */opt/sisense/mongodb* (20 Gi PersistentVolume)
- */opt/<namespace>/zookeeper* (5 Gi PersistentVolume)
- */opt/sisense/dgraph-io* (3 Gi PersistentVolume)
- */opt/sisense/grafana/grafana-<namespace>* (3 Gi PersistentVolume)

This mode needs the `privileged` Pod Security level (see [Privileges and Permissions for Self-Deployment](https://docs.sisense.com/main/SisenseLinux/self-deployment-privileges-and-permissions.md)) and is not suitable for shared or cloud-managed clusters. For a single-node installation, *sisense.sh* requires a dedicated mount point at */opt* or */opt/sisense* of at least 50 GB.

## Verifying Storage Before You Install

Before you install Sisense in cluster mode, check that your RWX StorageClass can provision a volume and that UID 1000 can write to it.

1. List the StorageClasses and CSI drivers in the cluster:

   [Copy](javascript:void(0);)

   ```
   kubectl get storageclass  
   kubectl get csidriver
   ```
2. Create the Sisense namespace if it does not exist, and save this manifest as *rwx-test.yaml*. Replace `<your-rwx-class>` with the name of your RWX StorageClass.

   [Copy](javascript:void(0);)

   ```
   apiVersion: v1  
   kind: PersistentVolumeClaim  
   metadata:  
     name: rwx-test  
   spec:  
     accessModes:  
       - ReadWriteMany  
     storageClassName: <your-rwx-class>  
     resources:  
       requests:  
         storage: 1Gi  
   ---  
   apiVersion: v1  
   kind: Pod  
   metadata:  
     name: rwx-test  
   spec:  
     restartPolicy: Never  
     securityContext:  
       runAsUser: 1000  
       runAsGroup: 1000  
       fsGroup: 1000  
     containers:  
       - name: test  
         image: busybox  
         command: ["sh", "-c", "touch /data/ok && ls -ln /data"]  
         volumeMounts:  
           - name: data  
             mountPath: /data  
     volumes:  
       - name: data  
         persistentVolumeClaim:  
           claimName: rwx-test
   ```
3. Apply the manifest and check the result:

   [Copy](javascript:void(0);)

   ```
   kubectl create namespace <namespace> --dry-run=client -o yaml | kubectl apply -f -  
   kubectl -n <namespace> apply -f rwx-test.yaml  
   kubectl -n <namespace> get pvc rwx-test  
   kubectl -n <namespace> get pod rwx-test  
   kubectl -n <namespace> logs rwx-test
   ```

   The PersistentVolumeClaim must be `Bound`, and the pod must reach `Completed`. In the log, the file *ok* must be listed with owner `1000 1000`. If the pod fails with a permission error, or the owner is not 1000, fix the StorageClass (for example, its mount options) before you install Sisense.
4. Delete the test resources:

   [Copy](javascript:void(0);)

   ```
   kubectl -n <namespace> delete -f rwx-test.yaml
   ```

To test your RWO StorageClass, repeat the procedure with `ReadWriteOnce` and the name of your RWO class. In an air-gapped environment, replace `busybox` with any small image from your private registry that includes a shell.
