Simplyblock Operator Reference
The simplyblock Kubernetes operator provides a declarative, Kubernetes-native interface for managing simplyblock storage infrastructure. Instead of using the CLI, administrators can define storage clusters, storage nodes, pools, and logical volumes as Kubernetes Custom Resource Definitions (CRDs). The operator continuously reconciles the desired state with the actual state of the simplyblock cluster.
Overview
The operator manages the following Custom Resource Definitions (CRDs):
| CRD | Short Name | Description |
|---|---|---|
StorageCluster |
- | Creates and manages a simplyblock storage cluster |
StorageNode |
- | Manages storage nodes within a cluster |
Pool |
- | Creates and manages storage pools |
Lvol |
- | Manages logical volumes |
Device |
- | Manages NVMe devices on storage nodes |
Task |
- | Monitors cluster tasks and their status |
All CRDs use the API group storage.simplyblock.io/v1alpha1.
Storage Cluster
The StorageCluster resource creates and manages a simplyblock storage cluster.
apiVersion: storage.simplyblock.io/v1alpha1
kind: StorageCluster
metadata:
name: my-cluster
namespace: simplyblock
spec:
clusterName: production
mgmtIfname: eth0
haType: ha
stripe:
dataChunks: 2
parityChunks: 1
fabricType: tcp
warningThreshold:
capacity: 89
provisionedCapacity: 250
criticalThreshold:
capacity: 99
provisionedCapacity: 500
Spec Fields
| Field | Type | Description |
|---|---|---|
clusterName |
string | Human-readable cluster name. Required. |
mgmtIfname |
string | Management network interface (e.g., eth0). |
haType |
string | High availability type: single or ha. |
stripe.dataChunks |
int | Erasure coding data chunks per stripe. |
stripe.parityChunks |
int | Erasure coding parity chunks per stripe. |
fabricType |
string | NVMe-oF fabric type: tcp, rdma, or tcp,rdma. |
clientDataIfname |
string | Client-side data network interface name. |
enableNodeAffinity |
bool | Enable node affinity for data placement. |
strictNodeAntiAffinity |
bool | Enforce strict node anti-affinity for chunks. |
isSingleNode |
bool | Set to true for single-node clusters. |
blockSize |
int | Logical block size in bytes (512 or 4096). |
pageSizeInBlocks |
int | Page size expressed in blocks. |
qpairCount |
int | NVMe queue pair count per volume. |
maxQueueSize |
int | Maximum backend queue size. |
inflightIOThreshold |
int | Inflight I/O threshold before back-pressure is applied. |
maxFaultTolerance |
int | Maximum number of concurrent node faults tolerated. |
nvmfBasePort |
int | Base port for NVMe-oF services. Subsequent nodes increment from this value. |
rpcBasePort |
int | Base port for RPC services. |
snodeApiPort |
int | Storage node API port. |
warningThreshold.capacity |
int | Capacity warning threshold (percent). |
criticalThreshold.capacity |
int | Capacity critical threshold (percent). |
warningThreshold.provisionedCapacity |
int | Provisioned capacity warning threshold (percent). |
criticalThreshold.provisionedCapacity |
int | Provisioned capacity critical threshold (percent). |
action |
string | Lifecycle action: activate or expand. |
backup.credentialsSecretRef.name |
string | Name of the Secret (in the same namespace) holding access_key_id and secret_access_key. Required when backup is set. |
backup.localEndpoint |
string | S3-compatible endpoint URL for backup storage. |
backup.snapshotBackups |
bool | Enable snapshot-based backups. |
backup.withCompression |
bool | Enable compression for backup data. |
backup.secondaryTarget |
int | Secondary backup target identifier. |
backup.localTesting |
bool | Enable local testing mode for backup. |
Auto-Managed CSI Credentials
When a StorageCluster is created or becomes active, the operator automatically creates or updates the
simplyblock-csi-secret-v2 Secret in the operator's namespace with the cluster's credentials. This Secret is
consumed by the CSI driver and requires no manual management. When the cluster is deleted, the operator removes
the cluster's entry from the Secret automatically.
Status Fields
| Field | Type | Description |
|---|---|---|
uuid |
string | Cluster UUID assigned after creation. |
clusterName |
string | Cluster name. |
nqn |
string | Cluster NVMe Qualified Name. |
status |
string | Current cluster lifecycle status. |
rebalancing |
bool | Whether cluster rebalancing is currently active. |
erasureCodingScheme |
string | Active erasure coding layout, for example 2x1. |
secretName |
string | Name of the Kubernetes Secret holding cluster credentials. |
configured |
bool | Whether initial cluster setup has completed. |
actionStatus.action |
string | Most recently requested action name. |
actionStatus.state |
string | Action execution state. |
actionStatus.message |
string | Human-readable result or error message. |
actionStatus.updatedAt |
string | Timestamp of the last status transition. |
actionStatus.triggered |
bool | Whether the underlying backend action has been fired. |
actionStatus.observedGeneration |
int | Resource generation observed when this status was recorded. |
Storage Node
The StorageNode resource manages storage nodes within a cluster.
apiVersion: storage.simplyblock.io/v1alpha1
kind: StorageNode
metadata:
name: storage-nodes
namespace: simplyblock
spec:
clusterName: production
clusterImage: "public.ecr.aws/simply-block/simplyblock:26.1.2"
maxLogicalVolumeCount: 100
workerNodes:
- worker-1
- worker-2
partitions: 1
coreIsolation: true
Spec Fields
| Field | Type | Description |
|---|---|---|
clusterName |
string | Name of the cluster this node belongs to. Required. |
clusterImage |
string | Storage-node container image. Required when action is not specified. |
spdkImage |
string | SPDK service container image override. |
spdkProxyImage |
string | SPDK proxy service container image override. |
maxLogicalVolumeCount |
int | Maximum number of logical volumes per node. Required when action is not specified. |
maxSize |
string | Maximum allocatable huge pages memry (e.g., 16G). |
partitions |
int | Number of partitions per backend storage device. |
mgmtIfname |
string | Management network interface name used by storage nodes. |
dataIfname |
[]string | Data-plane network interface names. |
coreIsolation |
bool | Enable CPU core isolation mode. |
corePercentage |
int | Percentage of CPU cores to allocate to SPDK (0–99). |
reservedSystemCPU |
string | CPUs reserved for system workloads (e.g., 0,1 or 0-1). |
enableCpuTopology |
bool | Enable topology-aware CPU scheduling. |
socketsToUse |
[]string | NUMA sockets to deploy storage on (e.g., ["0","1"]). |
nodesPerSocket |
int | Number of storage nodes to create per NUMA socket. |
journalManager.count |
int | Number of journal managers to configure. |
journalManager.percentPerDevice |
int | Journal manager capacity as a percentage of each device. |
pcieAllowList |
[]string | PCIe addresses of NVMe devices to include. |
pcieDenyList |
[]string | PCIe addresses of NVMe devices to exclude. |
pcieModel |
string | Filter devices by PCI device model string. |
deviceNames |
[]string | Explicit NVMe namespace names to use (e.g., ["nvme0n1","nvme1n1"]). Alternative to PCIe-based filtering. |
driveSizeRange |
string | Filter devices by capacity range (e.g., 100G-2T). |
forceFormat4K |
bool | Force 4K block-size formatting on NVMe devices that support it. |
skipKubeletConfiguration |
bool | Skip kubelet configuration changes during node setup. |
openShiftCluster |
bool | Enable OpenShift-specific behavior (required on OpenShift). See OpenShift. |
ubuntuHost |
bool | Indicate the host OS is Ubuntu for OS-specific initialization. |
tolerations |
[]Toleration | Kubernetes pod tolerations applied to storage-node pods. |
workerNodes |
[]string | Kubernetes worker node names to deploy storage on. Required and must be non-empty when action is not specified. |
action |
string | Node lifecycle action: shutdown, restart, suspend, resume, remove. |
nodeUUID |
string | UUID of the target node. Required when action is specified. |
Status Fields
The status.nodes list reflects the observed state of each managed storage node.
| Field | Type | Description |
|---|---|---|
nodes[].uuid |
string | Backend node UUID. |
nodes[].hostname |
string | Kubernetes node hostname. |
nodes[].status |
string | Backend lifecycle state. |
nodes[].health |
bool | Whether health checks are currently passing. |
nodes[].cpu |
int | Reported CPU core count. |
nodes[].memory |
string | Reported memory value. |
nodes[].volumes |
int | Current logical volume count. |
nodes[].devices |
string | Backend device summary for this node. |
nodes[].mgmtIp |
string | Management IP address. |
nodes[].rpcPort |
int | Node RPC service port. |
nodes[].lvolPort |
int | Logical volume subsystem port. |
nodes[].nvmfPort |
int | NVMe-oF service port. |
nodes[].uptime |
string | Reported node uptime. |
actionStatus.action |
string | Most recently requested action name. |
actionStatus.nodeUUID |
string | Target node UUID for the action. |
actionStatus.state |
string | Action execution state: pending, running, success, or failed. |
actionStatus.message |
string | Human-readable result or error message. |
actionStatus.updatedAt |
string | Timestamp of the last status transition. |
actionStatus.triggered |
bool | Whether the underlying backend action has been fired. |
actionStatus.observedGeneration |
int | Resource generation observed when this status was recorded. |
drainCoordination[].hostname |
string | Kubernetes node name being drained. |
drainCoordination[].activeNodeUUID |
string | Backend UUID of the storage node being shut down or restarted. |
drainCoordination[].phase |
string | Drain phase: detected, shutdown_called, draining, restart_called, complete, or failed. |
drainCoordination[].message |
string | Additional status detail or error information. |
drainCoordination[].startedAt |
string | Timestamp when drain coordination began for this node. |
Node Operations
The StorageNode CR operates in two distinct modes depending on whether spec.action is set.
Triggering an Action
Set spec.action and spec.nodeUUID together. Both fields are required — the CRD validation will reject a CR that has action without nodeUUID.
apiVersion: storage.simplyblock.io/v1alpha1
kind: StorageNode
metadata:
name: storage-nodes
namespace: simplyblock
spec:
clusterName: production
action: suspend
nodeUUID: "d4e5f6a7-..."
To clear the action after it completes, remove spec.action and spec.nodeUUID from the CR. The operator does not clear these fields automatically.
Action Lifecycle
When an action is triggered, the operator transitions status.actionStatus.state through the following states:
(spec.action set) → running → success
↘ failed (retried after 10 s)
Storage Pool
The Pool resource creates and manages storage pools. When a pool becomes active, the operator automatically
creates a Kubernetes StorageClass named simplyblock-<clusterName>-<poolName>. The StorageClass is deleted
when the pool is deleted.
apiVersion: storage.simplyblock.io/v1alpha1
kind: Pool
metadata:
name: my-pool
namespace: simplyblock
spec:
name: production-pool
clusterName: production
capacityLimit: "10T"
qos:
iops: 100000
throughput:
readWrite: 2048
read: 1024
write: 1024
Spec Fields
| Field | Type | Description |
|---|---|---|
name |
string | Pool name. Required. |
clusterName |
string | Name of the cluster. Required. |
capacityLimit |
string | Maximum pool capacity (e.g., 10T). |
qos.iops |
int | Maximum IOPS for the pool. |
qos.throughput.readWrite |
int | Maximum combined read/write throughput (MiB/s). |
qos.throughput.read |
int | Maximum read throughput (MiB/s). |
qos.throughput.write |
int | Maximum write throughput (MiB/s). |
action |
string | Pool lifecycle action. |
storageClassParameters |
object | Default volume parameters baked into the auto-created StorageClass. See Quality of Service for available fields. |
Auto-Created StorageClass
When the pool reaches an active state, the operator creates a StorageClass with:
- Name:
simplyblock-<clusterName>-<poolName> - Provisioner:
csi.simplyblock.io - VolumeBindingMode:
WaitForFirstConsumer - ReclaimPolicy:
Delete - AllowVolumeExpansion:
true
The cluster_id and pool_name parameters are set automatically. Any fields specified in
spec.storageClassParameters are merged in as additional CSI driver parameters.
Because Kubernetes StorageClass parameters are immutable after creation, the StorageClass is created once and left unchanged if it already exists. To change parameters, delete the pool and recreate it with updated values.
The StorageClass is deleted when the pool is deleted.
Status Fields
| Field | Type | Description |
|---|---|---|
uuid |
string | Backend pool UUID assigned after creation. |
status |
string | Backend lifecycle status. |
qos.host |
string | Backend host responsible for enforcing pool QoS. |
qos.iops |
int | Currently configured IOPS limit. |
qos.throughput.readWrite |
int | Currently configured combined read/write throughput (MiB/s). |
qos.throughput.read |
int | Currently configured read throughput (MiB/s). |
qos.throughput.write |
int | Currently configured write throughput (MiB/s). |
Logical Volume
The Lvol resource manages logical volumes. It provides a read-only view of volumes in a cluster and pool.
apiVersion: storage.simplyblock.io/v1alpha1
kind: Lvol
metadata:
name: cluster-volumes
namespace: simplyblock
spec:
clusterName: production
poolName: production-pool
Status Fields
Each volume in the status.lvols list includes:
| Field | Type | Description |
|---|---|---|
uuid |
string | Volume UUID. |
lvolName |
string | Volume name. |
status |
string | Backend lifecycle status. |
size |
string | Volume size. |
ha |
bool | High availability enabled. |
health |
bool | Whether health checks are passing. |
encrypted |
bool | Whether the volume is encrypted. See Volume Encryption. |
erasureCodingScheme |
string | Active erasure coding layout for this volume (e.g., 2x1). |
nqn |
string | NVMe Qualified Name for the volume. |
subsysPort |
int | NVMe subsystem listener port. |
namespaceID |
int | NVMe namespace identifier. |
poolName |
string | Storage pool name. |
poolUUID |
string | Storage pool UUID. |
nodeUUID |
[]string | Node UUIDs associated with this volume. |
hostname |
string | Node hostname associated with the volume. |
pvcName |
string | Bound Kubernetes PVC name, if applicable. |
fabricType |
string | Storage fabric/protocol in use (tcp or rdma). |
clonedFromSnapshot |
string | Source snapshot ID if this volume was cloned from a snapshot. |
sourceSnapshotName |
string | Source snapshot name if this volume was cloned from a snapshot. |
qos.class |
int | Assigned QoS class identifier. |
qos.iops |
int | IOPS limit for this volume. |
qos.throughput.read |
int | Read throughput limit (MiB/s). |
qos.throughput.write |
int | Write throughput limit (MiB/s). |
qos.throughput.readWrite |
int | Combined read/write throughput limit (MiB/s). |
blobID |
int | Backend blob identifier. |
maxNamespacesPerSubsystem |
int | Maximum number of NVMe namespaces per subsystem. |
Snapshot Cloning
When a volume is cloned from a snapshot, the clonedFromSnapshot and sourceSnapshotName fields in its status entry identify the origin. These fields are read-only and set by the backend at creation time — they cannot be specified in the Lvol spec.
To see which volumes in a pool are snapshot clones:
kubectl get simplyblocklvol cluster-volumes -n simplyblock -o jsonpath='{.status.lvols[?(@.clonedFromSnapshot!="")].lvolName}'
Device
The Device resource manages NVMe devices on storage nodes.
apiVersion: storage.simplyblock.io/v1alpha1
kind: Device
metadata:
name: cluster-devices
namespace: simplyblock
spec:
clusterName: production
Actions
To perform actions on a specific device, set the action, nodeUUID, and deviceID fields:
| Action | Description |
|---|---|
remove |
Remove a device from a node |
restart |
Restart a device on a node |
Status Fields
| Field | Type | Description |
|---|---|---|
nodes[].nodeUUID |
string | Backend UUID of the storage node. |
nodes[].devices[].uuid |
string | Backend device UUID. |
nodes[].devices[].status |
string | Backend lifecycle status of the device. |
nodes[].devices[].health |
string | Backend health indicator for the device. |
nodes[].devices[].model |
string | Reported device model. |
nodes[].devices[].size |
string | Formatted device capacity. |
actionStatus.action |
string | Most recently requested action name. |
actionStatus.nodeUUID |
string | Target node UUID for the action. |
actionStatus.state |
string | Action execution state. |
actionStatus.message |
string | Human-readable result or error message. |
actionStatus.updatedAt |
string | Timestamp of the last status transition. |
actionStatus.triggered |
bool | Whether the underlying backend action has been fired. |
actionStatus.observedGeneration |
int | Resource generation observed when this status was recorded. |
Task
The Task resource provides visibility into cluster tasks (migrations, rebalancing, etc.).
apiVersion: storage.simplyblock.io/v1alpha1
kind: Task
metadata:
name: cluster-tasks
namespace: simplyblock
spec:
clusterName: production
taskID: "abc123" # optional: filter to a specific task
Spec Fields
| Field | Type | Description |
|---|---|---|
clusterName |
string | Target storage cluster name. Required. |
taskID |
string | Filter results to a specific backend task UUID. |
Status Fields
| Field | Type | Description |
|---|---|---|
tasks[].uuid |
string | Backend task UUID. |
tasks[].taskType |
string | Backend task function or type name. |
tasks[].taskStatus |
string | Backend lifecycle status for the task. |
tasks[].taskResult |
string | Backend result payload or message. |
tasks[].retried |
int | Number of retry attempts made for the task. |
tasks[].canceled |
bool | Whether the task was canceled. |