Skip to main content

Storage classes and the capability contract (operator guide)

Kube-DC decides which StorageClass may serve which volume from what the class can do, never from its name. This page is for cluster operators: how Kube-DC reads a class, how to declare one explicitly, and how to check what tenants are offered. For the tenant view see Block storage; for VM tiers and live migration see VM storage tiers.

The same rules are applied by the console pickers, the backend create guards, the managed-cluster worker disk (k8-manager) and the database storage default (db-manager).

Classes without labels​

A class without the storage.kube-dc.com/tier label is classified from its provisioner, so a cluster works before any class is labelled:

ProvisionerKindCapabilities
contains bucket (Rook object store)objectnone: buckets only, never volumes
kubernetes.io/no-provisionerblock, node-localnone, and no dynamic provisioning: never offered
rancher.io/local-path, OpenEBS local, TopoLVM, host-path driversblock, node-localexpansion if the class allows it
contains rbd (ceph-csi RBD)blockBlock volume mode, RWX Block, clone, live migration, expansion if allowed
contains cephfs or nfsfileRWX Filesystem, clone, expansion if allowed
csi.cloudsigma.comblockRWO only, expansion if allowed; never snapshots, shared access or live migration, whatever is declared
anything elseblockRWO Filesystem, expansion if allowed

A class also gets snapshots when its driver has a VolumeSnapshotClass with deletionPolicy: Delete. Kube-DC uses the driver's default VolumeSnapshotClass, else the first by name. A Retain class is never used for tenant snapshots, even when it is the default: deleting the snapshot would leave its data behind.

Declaring a class​

Add the storage.kube-dc.com/tier label to take over from the provisioner rules. Then these labels and annotations apply:

KeyTypeMeaning
storage.kube-dc.com/tier (label)local, local-snap, capacity, balanced, performance, scratchPerformance tier. scratch is internal, not host-redundant, and never offered for tenant volumes
storage.kube-dc.com/kind (label)block, file, objectWhat the class provisions. Defaults to what the provisioner implies; a bucket provisioner is always object
storage.kube-dc.com/deprecated (label)"true"An alias kept for existing volumes: hidden from new volumes, still accepted (StatefulSet scale-up, replica replacement, clones)
storage.kube-dc.com/user-visible (label)"true" / "false"Whether tenants are offered the class. Defaults to visible unless deprecated, scratch or without dynamic provisioning
storage.kube-dc.com/capabilitiescomma list: snapshot, clone, expand, block-mode, rwx-block, rwx-file, live-migrationWhat the class can do. expand counts only when allowVolumeExpansion: true
storage.kube-dc.com/snapshot-classnameVolumeSnapshotClass for this class's snapshots
storage.kube-dc.com/node-local"true" / "false"Whether volumes are pinned to one node. Defaults to true for the local and local-snap tiers
storage.kube-dc.com/rolescomma listPlatform roles this class fills (below)
storage.kube-dc.com/pool<cluster>/<pool>Storage pool identity, only when the driver's parameters do not say (ceph-csi's clusterID with pool or fsName do)
storage.kube-dc.com/display-nametextName shown in pickers

Example: a replicated RBD class tenants see as "Balanced (replicated SSD)":

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: balanced
labels:
storage.kube-dc.com/tier: balanced
storage.kube-dc.com/kind: block
annotations:
storage.kube-dc.com/display-name: Balanced (replicated SSD)
storage.kube-dc.com/capabilities: snapshot,clone,expand,block-mode,rwx-block,live-migration
storage.kube-dc.com/snapshot-class: block-snapshot
storage.kube-dc.com/roles: database
provisioner: rook-ceph.rbd.csi.ceph.com
allowVolumeExpansion: true
parameters:
clusterID: rook-ceph
pool: rbd-pool
# ...the usual ceph-csi parameters

StorageClasses are immutable, so a new tier is a new class. Keep the old class as a deprecated alias while volumes still use it.

Purposes​

Each create path asks whether a class may be offered in its picker and whether a request naming it is accepted. Deprecated aliases and classes hidden from tenants are accepted but not offered.

PurposeUsed byAccepts
vm-root, vm-dataVM boot and data disksblock classes
vm-migratabledisks of a live-migratable VMblock, not node-local, with rwx-block and live-migration
volumePersistentVolumeClaimsblock and file classes
restoresnapshot restores and CSI clonesblock and file classes on the source's driver and pool
k8s-worker-rootmanaged-cluster worker disksblock classes
k8s-etcdmanaged-cluster etcdblock, not the capacity tier
k8s-tenant-volumesvolumes inside managed clustersblock; node-local only where the plan allows it
databaseKdcDatabase, managed servicesblock; node-local where the caller allows it (KdcDatabase does); not capacity for production plans. expand is not required, but a database grows only on a class that has it
backup-bucketbackup bucketsobject classes

Object, scratch and no-provisioner classes are refused for every volume purpose. Any volume restored or cloned from another one must stay on the source's driver and, when both pools are known, its pool.

Roles and defaults​

  • database: a KdcDatabase created without a storage class goes to the class with this role, if the contract accepts it for a database; otherwise to local-path. An existing database always keeps the class it already uses. Several classes with the role are a configuration error, and the platform falls back to local-path.
  • vm-root-default: the class a VM root disk gets by default; without a declaration, the cluster default class.
  • Cluster default class: the newest class annotated as default (GA or beta annotation), then the first by name. This is the class Kubernetes gives a claim that names none, and the class the guards check for it.

Check what tenants are offered​

The backend lists the classes for a purpose, as the tenant's own token sees them:

curl -s -H "Authorization: Bearer $TOKEN" \
"https://console.example.com/api/create-vm/<org>-<project>/storageclasses?purpose=vm-data" | jq

Each entry carries tier, kind, nodeLocal, features, modes (access and volume mode pairs), snapshotClass and pool. Add allowNodeLocal=true or production=true for the plan options, and sourceClass=<class> for a restore or clone.