Provision persistent storage
Provision storage as a persistent-volume-claim instance, then consume that
instance as a package dependency. This keeps the claim visible in the deploy
graph and lets Kix treat it as stateful during change planning.
Kix requires this pattern. Storage size, StorageClass, and lifecycle belong to
the cluster operator, so evaluation rejects application packages that create
their own PersistentVolumeClaims and directs them to use a storage
dependency. Packages that must create claims, such as the canonical
persistent-volume-claim package or a Helm chart with persistence enabled,
need an explicit meta.unsafe = [ "raw-pvc" ] grant. The scorecard reports
every such grant for review.
This guide assumes your target cluster flavor provides a default StorageClass, or that you know the StorageClass name to request.
Add the PVC and application instances
Section titled “Add the PVC and application instances”Create the PVC in the same namespace as the application:
instances.storage-example.storage = { package = packages."persistent-volume-claim"; config = { size = "5Gi"; accessModes = [ "ReadWriteOnce" ]; }; };
instances.storage-example.worker = { package = storageApp; };The PVC package advertises the storage alias. The application’s storage
build argument therefore resolves to the claim in the same namespace.
Set size to a Kubernetes storage quantity and choose access modes supported
by the storage provider. If the cluster does not provide a default through its
flavor, or the application needs another class, set
config.storageClassName = "<class-name>" on the PVC instance.
Create the package mount
Section titled “Create the package mount”Accept storage in the package’s build arguments, then create a PVC mount:
dataMount = kix.mount.pvc storage { mountPath = "/var/lib/app"; };The mount uses the resolved claim’s name and carries its dependency edge.
Apply the mount before sealing the workload:
deployment = { name = scope.instanceName; spec = { replicas = 1; selector.matchLabels = scope.selectorLabels; template.spec.containers = [ { name = "worker"; image = "docker.io/library/busybox:1.37"; command = [ "sh" "-c" "sleep infinity" ]; } ]; }; } |> kix.withMounts [ self.dataMount ] |> scope.mkDeployment;kix.withMounts adds the PVC volume and the matching container mount. Use
kix.withMountsOn when only one container in a multi-container pod should
receive it.
Check the result
Section titled “Check the result”Evaluate the cluster:
❱ kix check how-to-package-storage
TOOL RESULT DETAILS
eval pass 10 manifests evaluated
kubeconform pass skipped (this validation tool is not yet integrated with Kix)
pluto pass skipped (this validation tool is not yet integrated with Kix)
kyverno pass skipped (this validation tool is not yet integrated with Kix)
scorecard pass 0 errors, 9 warnings, 2 info Inspect the generated claim and workload volume:
❱ kix build how-to-package-storage --output json
[
{
"apiVersion": "apps/v1",
"kind": "Deployment",
"metadata": {
"name": "worker",
"namespace": "storage-example"
},
"podSpec": {
"containers": [
{
"name": "worker",
"volumeMounts": [
{
"mountPath": "/var/lib/app",
"name": "storage"
}
]
}
],
"volumes": [
{
"name": "storage",
"persistentVolumeClaim": {
"claimName": "storage"
}
}
]
}
},
{
"apiVersion": "v1",
"kind": "PersistentVolumeClaim",
"metadata": {
"name": "storage",
"namespace": "storage-example"
},
"spec": {
"accessModes": [
"ReadWriteOnce"
],
"resources": {
"requests": {
"storage": "5Gi"
}
},
"storageClassName": "standard"
}
}
] In this kind-based example, the flavor supplies the standard StorageClass.
The PVC requests 5 GiB, and the Deployment mounts it at /var/lib/app.
The kind StorageClass stores data inside the kind node. It is suitable for local testing, but deleting the kind cluster deletes that data. Check the reclaim policy and failure behavior of your real storage provider before using the same configuration for application data.