Configuration

Configure PVPolicy Custom Resources and PVC annotations for storage capacity, IOPS, and throughput autoscaling.

📣

Early Access Feature

This feature is in early access. It may undergo changes based on user feedback and continued development. We recommend testing in non-production environments first and welcome your feedback to help us improve.

Overview

This page documents the PVPolicy Custom Resource fields, PVC annotations, and Helm values that control Storage Autoscaling behavior. For background on how the configuration layers interact, including the default PVPolicy and policy resolution, see How it works.

PVC annotations override the matched policy on a per-PVC basis.

PVPolicy Custom Resource

PVPolicy is a namespaced Custom Resource Definition in the storage.cast.ai/v1alpha1 API group.

AttributeValue
API versionstorage.cast.ai/v1alpha1
KindPVPolicy
Short namepvpol
ScopeNamespaced

Create PVPolicy CRs in the castai-agent namespace using kubectl apply.

PVPolicy spec

FieldTypeRequiredDefaultDescription
spec.priorityintegerYesPriority for conflict resolution. Higher values take precedence. Minimum 0.
spec.dryRunbooleanYesWhen true, planned actions are logged but no changes are made for PVCs matched by this policy.
spec.selectorobjectYesDefines which PVCs this policy applies to. See PVC selector.
spec.configobjectYesAutoscaling configuration. Omitted fields inherit global defaults from Helm values. See Policy configuration.

PVC selector

The spec.selector field determines which PVCs a policy applies to. It has two active subfields: namespaces and pvc.

Namespace filter

spec.selector.namespaces is a list of namespace names. When empty, all namespaces are eligible. When non-empty, only PVCs in the listed namespaces are considered.

PVC matcher

spec.selector.pvc defines which PVCs match by name, label, or StorageClass. An empty object (pvc: {}) matches all PVCs in the selected namespaces. When omitted entirely, no PVCs are matched through this selector.

FieldTypeDefaultDescription
namesarray[]List of PVC names. A PVC must be in this list to match. Empty matches any name.
labelsobjectKubernetes label selector. Use matchLabels for exact key-value pairs and matchExpressions for In/NotIn/Exists/DoesNotExist.
storageClassesarray[]List of StorageClass names. The PVC's spec.storageClassName must be in this list. Empty matches any StorageClass.

All non-empty fields are AND-ed: a PVC must satisfy every specified condition.

📘

Note

PVCs with no storageClassName set do not match any storageClasses filter. If you need to manage these PVCs, use the names or labels fields instead.

📘

Note

Workload-based matching (spec.selector.workload) is planned for a future release. If set, it is currently ignored.

Policy configuration

The spec.config field contains the autoscaling settings applied to matched PVCs. The dimensions block is required. The storage and performance sub-objects are optional. When you omit a field, it inherits the corresponding global default from Helm values.

Dimensions

spec.config.dimensions controls which autoscaling dimensions are enabled for matched PVCs.

FieldTypeDefaultDescription
storageEnabledbooleanEnable automatic capacity expansion for matched PVCs.
iopsEnabledbooleanEnable IOPS rightsizing for matched PVCs.
throughputEnabledbooleanEnable throughput rightsizing for matched PVCs.

Storage settings

spec.config.storage configures capacity expansion behavior.

FieldTypeDefaultDescription
thresholdPercentinteger80Storage usage percentage that triggers expansion (0–100).
thresholdPeriodstring"5m"How long the threshold must be exceeded before acting. Prevents temporary spikes from triggering unnecessary resizes.
growthPercentinteger20How much to grow the PVC by, as a percentage of the current size.
minGrowthStepGiBinteger5Minimum growth increment in GiB. Applied when the percentage-based increment would be smaller.
cooldownPeriodstring"30m"Minimum time between expansions on a single PVC. Keep at 10 minutes or more to allow time for filesystem resizing to complete.

Performance settings

spec.config.performance configures IOPS and throughput rightsizing behavior.

FieldTypeDefaultDescription
targetstring"max"Which observation to use for the target computation. "max" uses the peak value over the lookback window. Also accepts percentile strings such as "p50", "p95", or "p99.9".
overheadnumber0.2Buffer added on top of the observed value: target = observed × (1 + overhead). Valid range is 0.0–2.5.
lookbackPeriodstring"6h"How far back to look at cloud metrics when computing the target. Valid range is 1h–24h.
minWarmupWindowstring"30m"Minimum metric data that must accumulate before acting on a disk. Valid range is 15m–24h. Set to "0" to disable.
changeCooldownstring"15m"Minimum time between consecutive performance modifications on the same PVC per dimension. Stacks on top of cloud-enforced cooldowns. Set to "0" to rely only on cloud-enforced limits.

Helm values (global defaults)

Helm values provide global defaults that PVPolicy CRs inherit when their config fields are omitted. You can pass a values file with -f values.yaml or use --set for individual overrides.

PVPolicy fields mirror the storage and performance settings documented above. When you set these values in Helm, they serve as the baseline that policies inherit from. For tuning specific PVCs or namespaces, prefer creating PVPolicy CRs over overriding Helm values.

Controller settings

These settings are specific to Helm and do not appear in PVPolicy CRs.

KeyDescriptionDefault
config.dryRunSets the dryRun value of the default PVPolicy on first creation. After the policy exists, this value has no effect. Manage dryRun directly on the PVPolicy using kubectl patch.true
config.allowUnknownCloudProviderAllow the chart to run on clusters where the cloud provider cannot be detected (for example, kind or k3s). Capacity expansion works; IOPS rightsizing is disabled. For local development only.false
config.manageVACPVCPerformanceWhen false, PVCs referencing a VolumeAttributesClass are skipped for performance management. Enable only when you have confirmed no conflict with the VAC controller.false
config.storage.checkIntervalHow often disk usage metrics are polled."1m"
config.storage.cloudDiskSyncCooldownMinimum time between periodic cloud disk state refreshes. Set to "0" to disable periodic sync."15m"

Namespace and label filtering

These Helm-level filters apply globally. PVPolicy selectors are the preferred way to scope management.

KeyDescriptionDefault
config.namespaces.watchAllMonitor all namespaces. Set to false to scope to specific namespaces.true
config.namespaces.watchList of namespaces to watch when watchAll is false.[]
config.pvc.includeLabelsOnly manage PVCs with all of these labels.{}
config.pvc.excludeLabelsExclude PVCs with any of these labels.{}

Global PVC defaults

These values apply when a PVPolicy's dimension fields are omitted. They can also be overridden per-PVC via annotations.

KeyDescriptionDefault
config.pvcDefaults.storageEnabledEnable automatic capacity expansion by default for all PVCs.true
config.pvcDefaults.iopsEnabledEnable IOPS rightsizing by default for all PVCs.true
config.pvcDefaults.throughputEnabledEnable throughput rightsizing by default for all PVCs.true

PVPolicy examples

Example 1: Default policy (automatically created by Helm)

The default PVPolicy is created automatically on controller pod start, if it does not yet exist. It is not updated later by the controller, so any configuration changes diverging from the default profile should be done in the PVPolicy resource.

apiVersion: storage.cast.ai/v1alpha1
kind: PVPolicy
metadata:
  name: default
  namespace: castai-agent
spec:
  priority: 0
  dryRun: true
  selector:
    namespaces: []
    pvc: {}
  config:
    dimensions:
      storageEnabled: true
      iopsEnabled: true
      throughputEnabled: true
    storage:
      thresholdPercent: 80
      thresholdPeriod: "5m"
      growthPercent: 20
      minGrowthStepGiB: 5
      cooldownPeriod: "30m"
    performance:
      target: "max"
      overhead: 0.2
      lookbackPeriod: "6h"
      minWarmupWindow: "30m"
      changeCooldown: "15m"

Example 2: Scope to a specific namespace with custom thresholds

This policy matches PVCs in the production namespace, uses a 90% threshold and 25% growth, and runs in live mode. Because it has a higher priority than the default policy, it takes precedence for production PVCs.

apiVersion: storage.cast.ai/v1alpha1
kind: PVPolicy
metadata:
  name: production
  namespace: castai-agent
spec:
  priority: 10
  dryRun: false
  selector:
    namespaces:
      - production
    pvc: {}
  config:
    dimensions:
      storageEnabled: true
      iopsEnabled: true
      throughputEnabled: true
    storage:
      thresholdPercent: 90
      growthPercent: 25

Example 3: Match by label and StorageClass

This policy matches PVCs with the label app=database and the StorageClass gp3, and disables IOPS rightsizing for them.

apiVersion: storage.cast.ai/v1alpha1
kind: PVPolicy
metadata:
  name: database-gp3
  namespace: castai-agent
spec:
  priority: 20
  dryRun: false
  selector:
    namespaces: []
    pvc:
      labels:
        matchLabels:
          app: database
      storageClasses:
        - gp3
  config:
    dimensions:
      storageEnabled: true
      iopsEnabled: false
      throughputEnabled: true

PVC annotations

Overview

Annotations override the matched policy's settings on a per-PVC basis. The applicable PVPolicy is resolved first, and then annotation overrides are applied on top.

Set a *-enabled annotation to "true" only if you have disabled the feature in the matched policy and want to re-enable it for a specific PVC.

Annotations you set

AnnotationWhat it doesExample value
storage.cast.ai/storage-enabledEnable or disable capacity monitoring for this PVC."false"
storage.cast.ai/storage-threshold-percentOverride the policy threshold percent."90"
storage.cast.ai/storage-growth-percentOverride the policy growth percent."30"
storage.cast.ai/storage-size-maxMaximum capacity this PVC may be grown to."500Gi"
storage.cast.ai/storage-cooldownOverride the policy cooldownPeriod for this PVC."1h"
storage.cast.ai/desired-capacityExpand the PVC to at least this size."500Gi"
storage.cast.ai/iops-enabledEnable or disable IOPS management for this PVC."false"
storage.cast.ai/iops-maxCap the maximum IOPS that may be provisioned."80000"
storage.cast.ai/desired-iopsPin IOPS to a specific value, overriding automatic scaling."10000"
storage.cast.ai/throughput-enabledEnable or disable throughput management for this PVC."false"
storage.cast.ai/throughput-max-mibpsCap the maximum throughput that may be provisioned."1200"
storage.cast.ai/desired-throughput-mibpsPin throughput to a specific value, overriding automatic scaling."500"
storage.cast.ai/performance-cooldownOverride the policy changeCooldown for this PVC. Stacks on top of the cloud-enforced cooldown."30m"

Status annotations

Storage Autoscaling writes status annotations back to PVCs so you can inspect current state and troubleshoot issues.

AnnotationWhat it shows
storage.cast.ai/matched-pvpolicyName of the PVPolicy that matched this PVC.
storage.cast.ai/dry-runWhether the matched policy is in dry-run mode ("true" or "false").
storage.cast.ai/disk-typeDetected cloud disk type (for example, hyperdisk-balanced or gp3).
storage.cast.ai/current-iopsLast known provisioned IOPS from the cloud API.
storage.cast.ai/current-throughput-mibpsLast known provisioned throughput in MiB/s.
storage.cast.ai/current-capacity-bytesLast known provisioned capacity in bytes.
storage.cast.ai/target-iopsIOPS value currently being targeted.
storage.cast.ai/target-throughput-mibpsThroughput value currently being targeted.
storage.cast.ai/target-capacity-bytesCapacity value currently being targeted.
storage.cast.ai/operation-statusStatus of an in-flight operation: pending, running, done, or failed.
storage.cast.ai/last-capacity-modificationTimestamp of the last successful capacity change.
storage.cast.ai/last-iops-modificationTimestamp of the last successful IOPS change.
storage.cast.ai/last-throughput-modificationTimestamp of the last successful throughput change.
storage.cast.ai/modifications-history(AWS only) JSON array of recent ModifyVolume timestamps. Shows how many of the 4 operations in the rolling 24-hour window have been consumed.
storage.cast.ai/last-errorLast error message if an operation failed.

PVC annotation examples

GCP / Hyperdisk Balanced: opt out of IOPS/throughput tuning

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: my-database-pvc
  annotations:
    storage.cast.ai/storage-threshold-percent: "85"
    storage.cast.ai/storage-growth-percent: "25"
    storage.cast.ai/iops-enabled: "false"
    storage.cast.ai/throughput-enabled: "false"
spec:
  storageClassName: hyperdisk-balanced
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 100Gi

AWS / gp3: cap IOPS/throughput ceilings

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: my-database-pvc-aws
  annotations:
    storage.cast.ai/iops-max: "16000"
    storage.cast.ai/throughput-max-mibps: "500"
spec:
  storageClassName: gp3
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 100Gi

Related resources


What’s Next

Did this page help you?