How-to guide Platform capabilities
Configure storage classes and PVCs
Give a cluster the StorageClasses its claims use, and configure PVC instances that consume them.
Kix models storage in two layers. A cluster-level storageClasses provider
exports out.storageClassName, the class a claim gets when it names none, and
namespace-scoped persistent-volume-claim instances request volumes. Application
packages consume the claims through a storage dependency.
Decide whether the flavor is sufficient
Section titled “Decide whether the flavor is sufficient”The kind, k3s, GKE, GKE Autopilot, AKS, OVH, and Scaleway flavors import the
environment’s default StorageClass as a storageClasses provider. If that
class has the provisioner, binding mode, reclaim policy, and access modes you
need, use it directly and create only the PVC instance below.
The rke2, kubeadm, talos, openshift, and EKS flavors import no class. On those clusters, and on a cluster with no flavor, a claim that names no class fails the build until you add a provider or set the claim’s class.
Add StorageClasses
Section titled “Add StorageClasses”The storage-classes package creates StorageClasses for CSI drivers that
already run in the cluster and provides the storageClasses role:
# rancher.io/local-path exists only where local-path-provisioner is # installed; name your cluster's CSI driver here. storage-classes = { package = packages.storage-classes; config.classes.local-path = { provisioner = "rancher.io/local-path"; volumeBindingMode = "WaitForFirstConsumer"; }; };Each entry of config.classes is one StorageClass, keyed by its name. The
fields are the StorageClass v1 fields: provisioner, parameters,
reclaimPolicy, volumeBindingMode, allowVolumeExpansion,
mountOptions, allowedTopologies, labels, and annotations. Use the
values the installed driver supports. Creating a StorageClass does not install
its provisioner; rancher.io/local-path works only where
local-path-provisioner runs.
The apiserver refuses changes to provisioner, parameters,
reclaimPolicy, and volumeBindingMode. Changing one means deleting and
recreating the class.
On a flavor that imports a default class, the storage-classes instance
replaces the import for Kix consumers. The environment’s class stays the
cluster default for claims Kix does not create. See
Shadow a flavor-provided import with a managed package.
Choose the class consumers get
Section titled “Choose the class consumers get”out.storageClassName is the only class when the instance has one. With
several classes, it is the class annotated
storageclass.kubernetes.io/is-default-class = "true". With several classes
and no annotation, a consumer that names no class fails the build, and each
claim sets its own storageClassName.
The annotation also makes the class the cluster default, so Kix refuses it on a flavor whose environment already has a default class. Annotate at most one class: two classes annotated default in one build fail the build.
Use a CSI driver package’s classes
Section titled “Use a CSI driver package’s classes”A CSI driver package that Kix installs renders its own classes and does not
claim the role. Give its instance aliases = [ "storageClasses" ] to make it
the cluster’s provider, or wire one consumer with
deps.storageClasses = ref.<namespace>.<instance>.
Import a class Kix does not manage
Section titled “Import a class Kix does not manage”When the environment has a class and the flavor does not import it, declare the import yourself so claims can use it:
kube-system.platform-storage.package = kix.mkImport { kind = "StorageClass"; apiVersion = "storage.k8s.io/v1"; roles = [ "storageClasses" ]; out = { name = "local-path"; storageClassName = "local-path"; }; };kind, apiVersion, and out.name identify the imported StorageClass.
out.storageClassName is the class claims that name none get; set both to
the class’s name.
Configure a PVC
Section titled “Configure a PVC”Create a persistent-volume-claim instance in the application’s namespace:
instances.apps.data = { package = packages."persistent-volume-claim"; config = { size = "20Gi"; accessModes = [ "ReadWriteOnce" ]; # Omit storageClassName to use the storageClasses provider. }; };size is required. With storageClassName omitted, the package reads the
class from the storageClasses provider. Set config.storageClassName when
this claim should use another class. An explicit value takes precedence over
the dependency.
Select only access modes the provider supports. ReadWriteOnce is common for
block storage; ReadWriteMany requires a provider that supports shared
mounts, and Kix does not check that it does.
Check the rendered resources
Section titled “Check the rendered resources”Evaluate the cluster and inspect the StorageClass and claim together:
❱ kix check doc-how-tos❱ kix build doc-how-tos --output json | jq '.[] | select(.kind == "StorageClass" or .kind == "PersistentVolumeClaim") | {kind, name: .metadata.name, spec}' Changing a bound claim’s StorageClass is normally an immutable, stateful migration. Review the diff and the storage provider’s reclaim behavior before deploying that change.
See Provision persistent storage for mounting the resulting claim into an application package.