Skip to content

Configure storage classes and PVCs

This content is for the v0.1 version. Switch to the latest version for up-to-date documentation.

Kix models storage in two layers. A cluster-level provider exports the default StorageClass name, and namespace-scoped persistent-volume-claim instances request volumes from that class. Application packages consume the claims through a storage dependency.

Provider flavors such as GKE, EKS, and kind expose their platform default as a storageClasses import. 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.

Add a managed provider when the cluster must create its own StorageClass or use a different default.

Create a package that renders the StorageClass, claims the storageClasses role, and exports out.storageClassName:

clusters/test-doc-how-tos.nix (L7–L34)
storageProvider =
{ scope, ... }:
{
meta = {
version = "1.0.0";
description = "Default StorageClass for the documentation example";
roles = [ "storageClasses" ];
};
build =
{ self, ... }:
{
storageClass = scope.mkClusterResource {
apiVersion = "storage.k8s.io/v1";
kind = "StorageClass";
name = "example-local";
extra = {
provisioner = "kubernetes.io/no-provisioner";
volumeBindingMode = "WaitForFirstConsumer";
};
};
root = {
resource = self.storageClass;
out.storageClassName = self.storageClass.out.name;
};
};
};

View source on GitHub ↗

Choose the provisioner, parameters, reclaimPolicy, volumeBindingMode, and allowVolumeExpansion values supported by the CSI driver installed in the target cluster. Creating a StorageClass does not install its provisioner.

The example uses kubernetes.io/no-provisioner only to demonstrate the Kix contract. A claim using it needs a matching statically provisioned volume.

Add one managed provider to the cluster:

clusters/test-doc-how-tos.nix (L87–L89)
instances.storage-system.storage = {
package = storageProvider;
};

View source on GitHub ↗

Because the package claims the storageClasses role, consumers resolve it by that name. On a flavor with a shadowable platform storage import, the managed provider takes precedence.

Kix rejects multiple managed providers for the same role. To offer several classes, render them from one provider and choose which name it exports as the default.

Create a persistent-volume-claim instance in the application’s namespace:

clusters/test-doc-how-tos.nix (L93–L100)
instances.apps.data = {
package = packages."persistent-volume-claim";
config = {
size = "20Gi";
accessModes = [ "ReadWriteOnce" ];
# Omit storageClassName to use the storageClasses provider.
};
};

View source on GitHub ↗

With storageClassName omitted, the package reads the name exported by the storageClasses provider. Set config.storageClassName when this particular claim should use a non-default class. An explicit value takes precedence over the dependency.

Select only access modes supported by the provider. ReadWriteOnce is common for block storage; ReadWriteMany requires a provider that supports shared mounts.

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.