The module lifecycle stage: Preview

The module has requirements for installation

v0.9.15

Release date: 2026-11-06

The DRBD kernel module of the new control plane compiles again, the node agent no longer rewrites the DRBD metadata of a replica when it fails to read it, and labels of the LINSTOR control plane are filtered again.

Highlights

Changes in this release:

  • DRBD of the new control plane moves to 9.2.19-flant.22: 9.2.19-flant.21, which v0.9.14 sets by default, does not compile.
  • In the new control plane, the node agent no longer writes new DRBD metadata over a replica whose on-node state it failed to read, so a slow or saturated disk no longer costs a replica its data.
  • In the LINSTOR control plane, the labels listed in storageClassLabelIgnoredPrefixes are again not copied from a ReplicatedStorageClass to its StorageClass, so Argo CD no longer shows the StorageClass as an extra resource of the application.

Fixes

This release fixes:

  • In the new control plane, the DRBD kernel module of version 9.2.19-flant.21, which v0.9.14 sets by default, does not compile: two functions named node_id_to_mask with different arguments clash. Version 9.2.19-flant.22 renames one of them and carries the same fixes otherwise. The LINSTOR control plane uses its own DRBD version and is not affected.
  • In the new control plane, the node agent no longer acts on a replica whose on-node DRBD state it could not read. When drbdmeta dump-md failed for a reason other than missing metadata, for example when it was stopped by its 10-second timeout on a saturated disk, the agent treated the backing volume as having no metadata and ran create-md --force over it. On nodes rebooted one after another this rewrote the metadata of replicas that held data. Now the agent reports the error in the Configured condition of the DRBDResource and retries on the next reconcile.
  • In the new control plane, the node agent no longer applies the disk options of DRBD resources on thin pools again and again. It asked DRBD for rs-discard-granularity equal to the discard granularity of the backing device, while DRBD caps the value at 1 MiB and at the largest discard of the device. On thin pools with chunks larger than 1 MiB the agent saw a difference on every pass and ran drbdsetup disk-options about 200 times a minute per node, each run pausing writes. The agent now asks for the value DRBD keeps.
  • In the LINSTOR control plane, labels of a ReplicatedStorageClass whose keys match storageClassLabelIgnoredPrefixes (by default argocd.argoproj.io/, kustomize.toolkit.fluxcd.io/, helm.toolkit.fluxcd.io/, fleet.cattle.io/) or the system list (app.kubernetes.io/managed-by, app.kubernetes.io/instance) are again not copied to its StorageClass. Since v0.9.5 the list did not reach the controller of the LINSTOR control plane, so it copied every label, and the StorageClass inherited the tracking label of Argo CD and was shown as an extra resource of the application. After the update the controller removes such labels from existing StorageClasses without recreating them.

Docs

Documentation changes:

  • The FAQ explains what happens to snapshots and restored volumes when one of them is deleted: snapshots are taken on every replica of an LVMThin volume, any order of deletion is allowed, a restored volume depends neither on its snapshot nor on the source, and the free space LINSTOR reports for an LVMThin pool already includes the space snapshots take.

Dependencies

Dependency updates:

  • DRBD: 9.2.19-flant.21 → 9.2.19-flant.22
    • New control plane only. Fixes the build of the kernel module.

v0.9.14

Release date: 2026-11-05

The new control plane can wipe the data of deleted volumes, lets the storage settings of a class change after creation, reports degraded classes and pools with alerts, Events and a capacity dashboard, and both control planes ship DRBD 9.2.19 and the fix for concurrent LVM operations on shared volume groups.

Highlights

Changes in this release:

  • In the new control plane, ReplicatedStorageClass.spec.volumeCleanup wipes the data of a volume’s replicas before their space is released (Enterprise Edition and Certified Security Edition Pro).
  • In the new control plane, the storage settings of a ReplicatedStorageClass can be changed after creation, and degraded classes and pools are reported by the new Degraded phase, alerts and Kubernetes Events.
  • The LINSTOR satellite and the sds-node-configurator agent now lock shared LVM volume groups against each other, so concurrent volume operations of sds-local-volume and sds-replicated-volume no longer corrupt a shared thin pool.

New features

This release adds:

  • On DKP 1.78 and later, the module’s access roles follow the capability/scope RBAC scheme: the ClusterRoles d8:system-capability:sds-replicated-volume:view and d8:system-capability:sds-replicated-volume:edit grant read-only and full access to ReplicatedStorageClass, ReplicatedStoragePool, ReplicatedVolume, ReplicatedVolumeReplica, ReplicatedVolumeAttachment, DRBDResource, DRBDResourceOperation, DRBDNodeOperation and DRBDMapper. Below 1.78 the module keeps the d8:manage:permission:module:sds-replicated-volume:view and :edit roles.
  • New alerts of the new control plane: D8ReplicatedStoragePoolNotReady fires when a ReplicatedStoragePool has not been Ready for 5 minutes (a missing LVMVolumeGroup or thin pool, an invalid node selector), and D8ReplicatedStorageClassNotReady when a ReplicatedStorageClass has not been Ready for 5 minutes. A class whose storage pool is not Ready is reported only by the pool alert. Both have severity 4 and their descriptions name the reasons and what to check. Before, such pools and classes were visible only in their status. The controller exports the new metrics sds_rsp_condition_problem_timestamp_seconds and sds_rsc_condition_problem_timestamp_seconds for them.
  • The SDS Replicated Volume Grafana dashboard of the new control plane has a new row, Capacity by ReplicatedStorageClass. For each selected class it shows the capacity and free space of its storage pool both before replication and divided by the number of replicas of the class, the allocation of thin pools against allocationLimit, and a table per node and LVMVolumeGroup. Thin pools are counted by their allocation limit: free space is the thin pool size multiplied by allocationLimit minus the space already allocated. For this, the controller exports the new metrics sds_rsp_lvg_info (the LVMVolumeGroups and thin pools of a ReplicatedStoragePool) and sds_rsc_replicas (the number of replicas and the storage pool of a ReplicatedStorageClass), which join the capacity metrics of sds-node-configurator to storage classes.
  • In the new control plane, a ReplicatedStorageClass can wipe the data of its volumes before their space is released: spec.volumeCleanup takes the methods of sds-node-configurator, RandomFillSinglePass, RandomFillThreePass or Discard (thick volumes only, storage.type: LVM). The method is fixed for a volume when it is created (it is recorded in spec.volumeCleanup of the ReplicatedVolume), covers the logical volumes of all its replicas, including replicas created later, and is applied whenever such a logical volume is removed: when the volume is deleted and when a replica moves or loses its disk. Changing the field of the class recreates the StorageClass and affects only volumes created afterwards. Overwriting takes time proportional to the size of the volume, and a deleted volume is gone only after the wipe. Available in the Enterprise Edition and the Certified Security Edition Pro; in the other editions the webhook rejects the field.
  • In the new control plane, ReplicatedStorageClass and ReplicatedStoragePool now record a Kubernetes Event when their Ready condition changes status or reason: a Warning when it turns False, a Normal one when it turns True again. The reason of the Event is the reason of the condition, for example WaitingForStoragePool, Degraded or LVMVolumeGroupNotFound, so kubectl describe shows when a class or a pool broke and when it recovered. A reconcile pass that changes nothing, or changes only the message, records no Event. Both kinds are cluster-scoped, so their Events are in the default namespace, and the controller is granted the right to create them there.

Improvements

This release improves:

  • New alert D8DrbdResourceIOSuspended fires when a DRBD resource has had its I/O suspended for 5 minutes for a reason other than a lost quorum (no up-to-date replica reachable, fencing, or drbdsetup suspend-io). I/O to such a volume hangs instead of failing, and before only the loss of quorum raised an alert. The alert description shows how to find the reason and what to do.
  • Removing a thin pool from spec.thinPools of an LVMVolumeGroup is now rejected while a ReplicatedStoragePool or a ReplicatedStorageClass uses that thin pool. sds-node-configurator removes a thin pool dropped from the spec once it is empty, and replicas would then be placed in a thin pool that is gone. The check does not block LVMVolumeGroup updates while the module’s webhook is unavailable.
  • During scheduling simulations of the Deckhouse kube-scheduler (filter and prioritize requests with dryRun: true), linstor-scheduler-extender no longer records FailedScheduling Events on the simulated Pod, so descheduler checks no longer leave false scheduling errors on running VM Pods.
  • In the new control plane, spec.storage, spec.nodeLabelSelector, spec.zones and spec.eligibleNodesPolicy of a ReplicatedStorageClass can be changed after creation: a change moves the class to a new automatically created storage pool, and new volumes get the new configuration. The restrictions stay only for classes of the LINSTOR control plane.
  • In the new control plane, a ReplicatedStorageClass whose storage pool or eligible nodes degraded after its configuration was accepted is reported in the new Degraded phase with the Degraded reason of Ready: the accepted configuration stays in effect, but replicas can be placed only on the nodes the pool still offers. The Terminating phase names the number of volumes it waits for, and VolumesSatisfyEligibleNodes names the number of conflicting volumes.

Fixes

This release fixes:

  • In the new control plane, the controller no longer deletes a StorageClass of another provisioner that has the name of a ReplicatedStorageClass. It used to remove such a StorageClass and create its own in its place. Now it leaves the StorageClass alone, and the ReplicatedStorageClass goes to the InvalidConfiguration phase with Ready=False, reason StorageClassConflict, and a message naming the StorageClass and its provisioner. Once the name is free, the class gets its StorageClass within a minute.
  • In the LINSTOR control plane, a ReplicatedStorageClass whose name is held by a StorageClass of another provisioner now goes to the InvalidConfiguration phase with a message naming the StorageClass and its provisioner. Before, the conflict was only written to the controller log and the status did not change.
  • DeleteVolume refused a volume for good when a ReplicatedVolumeAttachment of it outlived the VolumeAttachment of its node: the CSI controller finalizer on the attachment is removed only by ControllerUnpublishVolume, which the external-attacher never calls again once the VolumeAttachment is gone, and the PersistentVolume stayed Released. DeleteVolume now releases such attachments first, unless their device is still in use.
  • In the new control plane, the StorageClass of a ReplicatedStorageClass now has the annotation storage.deckhouse.io/volumesnapshotclass: sds-replicated-volume, as in the LINSTOR control plane. Without it, storage-foundation did not fill in volumeSnapshotClassName of a VolumeSnapshot of a volume of the class, and a VolumeCaptureRequest of such a volume failed with a message about the missing annotation. Existing StorageClasses get the annotation at the next reconciliation without being recreated; a different value set by hand is replaced.
  • The LINSTOR satellite now locks LVM volume groups through the host lock directory, the one the sds-node-configurator agent uses. When sds-local-volume and sds-replicated-volume share a volume group, lvcreate and lvremove from both sides ran without excluding each other and could corrupt the thin pool metadata.
  • A ReplicatedStorageClass or ReplicatedStoragePool being deleted can lose its finalizer again. The webhook checked that update too, so a class that stopped passing validation after creation, for example an Ignored topology once the nodes got zone labels, hung in deletion for good.
  • The webhook now rejects a ReplicatedStorageClass when it cannot read the StorageClass of the same name; only a missing StorageClass lets the class through. Before, any read error admitted the class the check exists to stop.
  • In the new control plane, classes with different eligibleNodesPolicy no longer share a storage pool and silently run with another class’s policy. Existing classes keep their pools after the update and move to the new pool name on their first spec change.
  • During the migration from LINSTOR, the volumes of a storage class in the Degraded phase now switch to Auto instead of waiting until the migration step gives up.

Security updates

Security updates in this release:

  • golang.org/x/net v0.62.0 (CVE-2026-78661, CVE-2026-97045), and the ALT Linux packages of spaas, drbd-reactor, metadata-backup and linstor-server are taken from the 2026/10/31 snapshot (curl 8.23.0, libbrotli 1.2.1, cups 2.4.20, freetype 2.14.3).

Breaking changes

Changes that affect backward compatibility:

  • On DKP 1.78 and later, the d8:manage:permission:module:sds-replicated-volume:view and :edit ClusterRoles are no longer created; bindings that reference them by name stop granting access.

Upgrade notes

Before upgrading, note the following:

  • On DKP 1.78 and later, the d8:manage:permission:module:sds-replicated-volume:view and :edit ClusterRoles are replaced by d8:system-capability:sds-replicated-volume:view and :edit. Bindings that reference the old role names directly have to be switched to the new ones.

Docs

Documentation changes:

  • The FAQ now says that overprovisioning of LVMThin pools is limited by LINSTOR and that allocationLimit of the thin pool in LVMVolumeGroup has no effect on the module’s volumes.
  • The description of the dataNodes.nodeSelector parameter and the FAQ now say what the parameter does: nodes that match it get the storage.deckhouse.io/sds-replicated-volume-node label and module components run on them, and a custom value replaces the default kubernetes.io/os: linux. Changing the selector later, including disabling the module and enabling it again with a different one, does not remove the labels from nodes that have already been selected and does not move data; the description links to the FAQ procedure for removing the module from such a node.
  • The documentation describes how the replication mode affects latency and IOPS and how to disable the module.

Dependencies

Dependency updates:

  • DRBD: 9.2.18-flant.10 → 9.2.19-flant.21

v0.9.13

Release date: 2026-10-26

The new control plane grows a volume from r2 to r3 by turning its tie-breaker into the third copy in place, alerts on volumes that are not Ready or not Resilient and gets a reworked Grafana dashboard, both control planes ship the SecurityPolicyExceptions that DKP 1.79 requires for system Pods, and the module images no longer carry the reported dependency vulnerabilities.

Highlights

Changes in this release:

  • In the new control plane, raising a ReplicatedStorageClass from Availability to ConsistencyAndAvailability turns the tie-breaker of each volume into its third diskful copy on the same node, so the growth also completes on exactly three storage nodes, where it never converged before.
  • In the new control plane, the D8ReplicatedVolumeNotReady, D8ReplicatedVolumeNotResilient and D8SdsReplicatedVolumeCurrentMetricsUnavailable alerts report volumes that do not serve I/O, volumes that would not survive the next failure, and the loss of the metrics these alerts are built on; the “SDS Replicated Volume” dashboard opens with the health of the volumes and a list of the problem ones.
  • The module ships a SecurityPolicyException for every workload that needs more than the restricted profile, in both control planes, so its Pods keep starting once DKP 1.79 switches the Pod Security Standards of system namespaces from warning to denial.

New features

This release adds:

  • New alerts of the new control plane: D8ReplicatedVolumeNotReady (severity 4) fires when a ReplicatedVolume has not been Ready for 5 minutes, D8ReplicatedVolumeNotResilient (severity 6) when it has not been Resilient for 30 minutes while still Ready, and D8SdsReplicatedVolumeCurrentMetricsUnavailable (severity 6) when the leader controller has not exported current metrics for 5 minutes, so that the alerts built on them cannot fire. Volumes that are still being created are not reported. D8ReplicatedVolumeNotResilient also fires while a volume grows to a higher redundancy and the new copy takes longer than 30 minutes to synchronize.
  • New metrics of the new control plane controller: sds_rv_condition_count and sds_rv_condition_problem_timestamp_seconds for the conditions of ReplicatedVolumes, sds_rv_created_total, sds_rvr_ready_lost_total, sds_metrics_collector_up, the age of the oldest stuck objects (sds_deleting_oldest_timestamp_seconds, sds_rv_deleting_timestamp_seconds, sds_rv_datamesh_transition_oldest_timestamp_seconds, sds_rvr_not_ready_oldest_timestamp_seconds) and the configuration_mode label (Auto or Manual) of sds_rv_count. The agent exports sds_drbd_module_info with the full version of the loaded DRBD kernel module, including its build suffix.

Improvements

This release improves:

  • The “SDS Replicated Volume” Grafana dashboard of the new control plane is reworked. It opens with the Volume Health and Problem Volumes sections, which show the volumes that are not Ready, not Resilient, under maintenance or being deleted, with the time their condition last changed status and how long ago that was. The Control Plane Throughput, Replicas & Attachments, Lifecycle Latency, Datamesh Transitions, DRBD Runtime State and Debug / Metrics Collection sections are collapsed and run their queries only when expanded. DRBD Runtime State takes over the DRBD panels of the LINSTOR dashboard and adds resources with suspended I/O and devices whose disk is neither UpToDate nor Diskless.
  • D8ReplicatedVolumeLayoutDegraded no longer fires for a volume under spec.maintenance, whose layout convergence is frozen, and no longer resolves and starts its 15-minute wait again on a controller restart or a leader change.
  • The workloads that need more than the restricted profile get a SecurityPolicyException that describes each privilege, and their Pods carry the security.deckhouse.io/security-policy-exception label pointing to it: agent, the control-plane-migrator Job and the CSI node in the new control plane, linstor-node, linstor-controller and the CSI node in the LINSTOR control plane. The objects are rendered only when the SecurityPolicyException resource is available in the cluster (the admission-policy-engine-crd module is enabled).

Fixes

This release fixes:

  • In the new control plane, raising a ReplicatedStorageClass from Availability to ConsistencyAndAvailability on exactly three storage nodes never converged: a fourth diskful replica was created, had no node to go to and held the rollout slot of the class forever. A healthy volume with two diskful copies and a tie-breaker now keeps the tie-breaker replica, its node and DRBD node ID, and the replica gets a disk on that node and becomes the third copy; no fourth replica is created. The tie-breaker node must have storage of the class pool; otherwise MembershipLayoutConverged reports CannotConverge. A volume that already has a third diskful replica on its way still finishes by removing the tie-breaker.
  • In the new control plane, while a volume grows to three diskful copies, including the repair of a copy lost during the growth, it keeps serving I/O at one UpToDate copy until all three are UpToDate. Before, the third copy joining raised this minimum to two while only two copies were UpToDate, so a single failure during the resynchronization suspended I/O.
  • In the new control plane, DRBD metrics of a node are scraped while the agent Pod is not ready. Before, every agent restart dropped them, and the DRBD alerts of the node resolved exactly when something was wrong on it.
  • The lifecycle metrics of the new control plane are counted correctly: each DRBDResource deletion is observed once (before, about a third of them were), sds_rvr_backing_volume_duration_seconds and sds_drbdr_configured_duration_seconds no longer record the age of an old object that returns to ready, datamesh transitions and their steps are observed exactly once and cancelled ones are skipped, sds_rva_ready_duration_seconds counts only the first attach, and volumes without a ReplicatedStorageClass are reported as storage_class="unknown" in every metric. The in-memory trackers behind these metrics no longer keep entries of objects removed by someone else until a restart.

Security updates

Security updates in this release:

  • Every container of the module drops all capabilities, adding back only what it needs (CHOWN and FOWNER for the init container of control-plane-migrator); for the privileged agent and linstor-satellite containers this changes only the manifest. The kube-rbac-proxy containers of agent run as the deckhouse user instead of root.
  • Go dependencies of the module binaries, of the patched LINSTOR components (linstor-csi, linstor-affinity-controller, linstor-scheduler-extender, k8s-await-election) and of the hooks, and urllib3 in the metadata backup image are updated, which clears CVE-2026-78669, CVE-2026-78659, CVE-2026-78660, CVE-2026-78663, CVE-2026-97032, CVE-2026-56851, CVE-2026-63209, CVE-2026-85747, CVE-2026-97687, CVE-2026-97688 and CVE-2026-97689 from scans of the module images.

Upgrade notes

Before upgrading, note the following:

  • Nothing has to be done by hand. The Pods of the module restart once to pick up the new security contexts and, where the SecurityPolicyException resource is available, the new label.
  • Grafana dashboards follow the control plane in use: with the LINSTOR control plane only “SDS-REPLICATED-VOLUME / DRBD” is installed, with the new control plane only “SDS Replicated Volume” and “SDS Replicated Volume - Controller Runtime”.
  • If custom alerts or dashboards use the metrics of the new control plane, update them: sds_rv_membership_layout_converged, sds_rv_datamesh_transitions_completed_total, sds_rvr_ready_transition_duration_seconds and the sds:rvr_degraded_count recording rule are removed (use sds_rv_condition_problem_timestamp_seconds, the _count of sds_rv_datamesh_transition_duration_seconds and sds_rvr_ready_lost_total instead), and the buckets of the lifecycle histograms now reach one hour.

v0.9.12

Release date: 2026-10-14

The legacy control plane stops raising the StorageClass alert for a ReplicatedStorageClass without spec.replication, DRBD is built again on ALT Linux nodes whose kernel flavour is not std-def, the migrator and spaas follow the module log level, and the new control plane keeps quorum while a diskful replica joins and finishes the r2 → r3 upsize by itself.

Highlights

Changes in this release:

  • A ReplicatedStorageClass created without spec.replication is handled as ConsistencyAndAvailability by the legacy controller as well: its StorageClass is no longer labeled non-operational and no longer fires the StorageClass alert.
  • On ALT Linux nodes that run a kernel flavour other than std-def (for example ALT p11 with the 6.12 flavour), the DRBD NodeGroupConfiguration installs the headers of the running flavour, so DRBD is built instead of failing on a missing kernel-headers-modules-std-def package.
  • The resyncSlotsPerNode module setting, which applies only to the new control plane, is removed; the resync limit is fixed at 4 per node. Remove the setting from the ModuleConfig before the update if it is set there.

Improvements

This release improves:

  • The control-plane migrator and spaas take their log level from the module logLevel instead of always logging at debug level. With the default Info, the migrator logs at info and spaas runs without --debug.
  • In the new control plane, current-state metrics of the controller are exported only by the leader replica, so standby replicas no longer publish duplicate cluster-wide series.
  • In the new control plane, raising a ReplicatedStorageClass from Availability to ConsistencyAndAvailability completes by itself: after the third diskful copy is UpToDate, the surplus tie-breaker is deleted automatically, and the volume no longer stops at TransitionUnsupported waiting for it to be deleted by hand.

Fixes

This release fixes:

  • The legacy webhook applies the three-zone TransZonal check to a ReplicatedStorageClass without spec.replication, so the mistake is rejected on apply instead of surfacing later as InvalidConfiguration. The legacy webhook and the CRD validation also reject replication: Consistency on the legacy control plane, which has no StorageClass layout for it. Existing StorageClasses already labeled non-operational because of the empty replication lose the label.
  • The CSI node of the new control plane serves /metrics, /healthz, /readyz and /health on its loopback metrics address only. It no longer listens on port 8081 on all interfaces, where it conflicted with capdvp-controller-manager on the masters of clusters on DVP: whichever started second crash-looped, and such clusters could not be deleted.
  • In the new control plane, a diskful replica joining a volume no longer makes the volume lose quorum and briefly suspend I/O (Ready=False, reason QuorumLost). The agent raises the quorum only after the new peer counts as a vote, the controller raises it only after the joining replica is Connected to every member, and a voter seen Connected by a peer with quorum is counted as reachable.
  • In the new control plane, adding a diskful replica no longer raises the minimum data redundancy above the number of UpToDate copies while the new copy is still resyncing, which suspended I/O on every replica until the resync finished.
  • In the new control plane, the controller deletes a ReplicatedVolumeReplica only if it is still the same object, so a replica that reused the name of a removed one is never deleted by mistake.
  • In the new control plane, TransZonal validation of a ReplicatedStorageClass requires a non-empty zones list with the exact number of zones for the chosen redundancy, and the zone requirements are checked separately from the legacy rules.

Breaking changes

Changes that affect backward compatibility:

  • The resyncSlotsPerNode module setting, which applies only to the new control plane, is removed from the module configuration schema. A ModuleConfig that still sets it fails validation after the update.
  • In the new control plane, failuresToTolerate and guaranteedMinimumDataRedundancy of a ReplicatedStorageClass and of spec.manualConfiguration of a ReplicatedVolume accept values up to 1. Layouts above that (4D, 4D+1TB, 5D) are not admitted; an existing resource with a higher value reports a validation error.

Upgrade notes

Before upgrading, note the following:

  • Before the update, remove settings.resyncSlotsPerNode from the sds-replicated-volume ModuleConfig if it is set. The setting applies only to the new control plane: after the update, the new control plane limits resyncs to 4 per node in every cluster, and the limit cannot be changed or switched off.
  • On ALT Linux nodes that previously failed to build DRBD, nothing has to be done by hand: bashible installs the right headers and builds the module on its next run.

Docs

Documentation changes:

  • The module documentation describes the released (LINSTOR-based) control plane: the ReplicatedStorageClass and ReplicatedStoragePool phase is Ready rather than Created or Completed, spec of these resources cannot be changed after creation, and expanding a ReplicatedStoragePool to new nodes is done by recreating it. The new control plane documentation and CRDs are no longer shown in the module docs.
  • The CRD reference of ReplicatedStorageClass and ReplicatedStoragePool marks the fields used only by the new control plane, describes the shared fields identically in English and Russian, and marks replication and storagePool as deprecated only in the new control plane.
  • The ReplicatedStorageClass examples are fixed: the HA class example in the Russian usage guide had name outside metadata, and the FAQ example no longer contains metadata.generation.

v0.9.11

Release date: 2026-10-01

A ReplicatedStorageClass created before v0.9.8 no longer goes to InvalidConfiguration after the upgrade, nodes that already run the right DRBD version stop installing kernel headers on every bashible run, and the API reference is described in full in both languages.

Highlights

Changes in this release:

  • The legacy controller recreates a StorageClass whose only difference from the desired one is replicated.csi.storage.deckhouse.io/fsOpts, so a ReplicatedStorageClass created by an earlier version, or one whose storage.deckhouse.io/ext4-reserved-percent annotation changes, no longer ends up in the InvalidConfiguration phase.
  • The DRBD NodeGroupConfiguration installs kernel headers only when it is about to build DRBD; on ALT Linux it no longer updates the kernel and requests a reboot of a node whose DRBD is already up to date.
  • Every field of the module’s CRDs has an English description in the reference, the Russian reference is complete, and developer notes no longer show up in the descriptions of ReplicatedStorageClass and ReplicatedVolume.

Fixes

This release fixes:

  • Since v0.9.8 the legacy controller always writes replicated.csi.storage.deckhouse.io/fsOpts into the StorageClass it generates, but did not count it among the parameters a recreate may change. Every StorageClass created by an earlier version therefore compared as a non-recreatable difference, and its ReplicatedStorageClass went to the InvalidConfiguration phase after the upgrade; changing the storage.deckhouse.io/ext4-reserved-percent annotation was refused the same way. The StorageClass is now recreated instead. fsOpts is read only when a volume is formatted, so existing volumes are not affected. Applies to the legacy (LINSTOR) control plane.
  • The DRBD NodeGroupConfiguration (Debian-, CentOS- and ALT Linux-like distributions) installed the headers of the running kernel, and removed the others, before checking whether the desired DRBD version was already loaded. Every bashible run on such a node asked the distribution repositories for a package it did not need and failed on a node without access to them; on ALT Linux, headers newer than the running kernel made it update the kernel and request a reboot. The headers are now installed only on a node that is about to build DRBD.

Security updates

Security updates in this release:

  • Go dependencies flagged by the vulnerability scan are raised in the agent, the controller, the legacy controller, the webhooks, linstor-drbd-wait and linstor-migrator: golang.org/x/net v0.56.0 → v0.58.0, golang.org/x/sys v0.46.0 → v0.47.0, golang.org/x/text v0.39.0 → v0.41.0, and, in the controller and the webhooks, go.opentelemetry.io/otel v1.37.0 → v1.41.0 and github.com/google/cel-go v0.26.0 → v0.29.0.

Docs

Documentation changes:

  • Sixty CRD fields that had no English description in the reference now have one: the top level of DRBDMapper, DRBDNodeOperation, DRBDResourceOperation, DRBDResource and ReplicatedVolume, most DRBDResource fields, and the node and volume names, sizes, addresses and conditions of the ReplicatedVolume* resources. The Russian description of status.activeConfiguration.nonVoting of DRBDResource is corrected: the field is true when the disk does not take part in the quorum vote.
  • The Russian reference covers all CRDs of the module: 147 descriptions are added, including apiVersion, kind and the condition fields, and the translations of status.reason of ReplicatedStorageClass and ReplicatedStoragePool move to status.message, the field the schema actually has.
  • The description of spec of ReplicatedStorageClass no longer opens with about thirty lines of CEL validation notes, spec of ReplicatedVolume gets the description “Desired state of the replicated volume” instead of CEL rule labels, and systemNetworkNames and lvmVolumeGroups no longer end with internal TODO notes. Only the descriptions change; the schema is the same.

v0.9.10

Release date: 2026-09-24

A volume that loses a diskful copy now heals by itself under a resync limit that is on by default, a single volume can be paused without stopping the controller, and the Go binaries are rebuilt against patched grpc and x/crypto.

Highlights

Changes in this release:

  • Layout convergence re-creates a lost diskful copy of a ReplicatedVolume by itself instead of stopping at TransitionUnsupported and waiting for a replica to be created by hand.
  • resyncSlotsPerNode is on by default (4), so a node going away does not start every resync of the volumes it held at once.
  • spec.maintenance: NoResourceReconciliation on a ReplicatedVolume pauses reconciliation of that volume, its replicas and its DRBD resources while every other volume keeps reconciling.

New features

This release adds:

  • ReplicatedVolume has spec.maintenance. With NoResourceReconciliation, the controller takes no action on the volume: no membership or layout decision, no replica or attachment change, no configuration derivation and no deletion handling. The pause cascades to the volume’s replicas and their DRBD resources; a DRBD resource paused by hand is left as it is. Ready, Resilient and AttachedReady keep being published, the rest of the status freezes, and the pause is reported by the UnderMaintenance condition and the Maintenance column of kubectl get replicatedvolume -o wide. A paused volume does not finish deleting: it and its PVC stay Terminating until the field is cleared.
  • A ReplicatedVolume whose layout has fewer diskful copies than intended gets the missing copy created and resynced automatically, for example r1 → r2, r1 → r3, or a copy lost with its node. Changes that need a replica removed are still not made automatically: shrinking the copy count, replacing a copy whose member is alive, and r2 → r3 while a surplus tie-breaker is present — delete the tie-breaker, and the copy is then healed. When the copy cannot be placed, the volume reports CannotConverge with the scheduler’s reason.

Improvements

This release improves:

  • The resyncSlotsPerNode default changes from 0 (no limit) to 4, so the healing load after a node failure is bounded. A value set explicitly in the module config is kept; 0 still switches the limit off.
  • The controller’s health probe and loopback metrics move from ports 4271 and 4272 to 8081 and 127.0.0.1:8082, and the CSI controller’s livenessprobe no longer uses port 4261. These ports belong to the 4200–4299 range reserved for modules that listen on the host network, and neither Pod runs there. The Pods are restarted by the update.

Fixes

This release fixes:

  • With the resync limiter on, several volumes could choose the same node to receive or send a resync at once, because a placement stayed invisible to other workers until it came back through the watch; the limit per node was exceeded at the start of every wave. Both ends of a transfer are now reserved before the placement is written and released as soon as the replica stops owing data.
  • On a new cluster, the node label storage.deckhouse.io/sds-replicated-volume-node was set only on nodes already eligible for a ReplicatedStoragePool. That label is what brings up the sds-node-configurator agent, which creates the BlockDevice resources an LVMVolumeGroup is built from, so no pool could get eligible nodes in the first place. Nodes matching dataNodes.nodeSelector now get the label directly.

Security updates

Security updates in this release:

  • google.golang.org/grpc is raised from v1.82.1 to v1.83.2 in the CSI driver, linstor-csi, linstor-affinity-controller and linstor-scheduler-extender, closing CVE-2026-84303, CVE-2026-84304 and CVE-2026-84445.
  • golang.org/x/crypto is raised from v0.53.0 to v0.57.0 in the module’s hooks (go-hooks) and linstor-scheduler-extender, closing CVE-2026-56854 (authentication bypass by source address in x/crypto/ssh), CVE-2026-56855 and CVE-2026-78662.

Breaking changes

Changes that affect backward compatibility:

  • evict.sh and replicas_manager.sh are installed in /var/lib/deckhouse/sbin instead of /opt/deckhouse/sbin, and the old copies are removed from nodes. Runbooks and scripts that call them by the old path have to use the new one.

Upgrade notes

Before upgrading, note the following:

  • Nothing has to be done by hand. After the update, the node configuration moves evict.sh and replicas_manager.sh to /var/lib/deckhouse/sbin; update any runbook that calls /opt/deckhouse/sbin/evict.sh.
  • If resyncSlotsPerNode was not set, the limit of 4 applies after the update, and volumes that were short of a diskful copy start healing within that limit. To keep resyncs unlimited, set resyncSlotsPerNode: 0.

Docs

Documentation changes:

  • The usage guide describes recovering a lost replica, which no longer needs a manual step, and the D8ReplicatedVolumeLayoutDegraded alert no longer walks through creating a replica by hand.

v0.9.9

Release date: 2026-09-21

A ReplicatedVolume now reports where its replicas sit, -o wide gained the two columns the configuration and layout pictures were missing, and switching the resync limiter on no longer drives the controller into its memory ceiling.

Highlights

Changes in this release:

  • A ReplicatedVolume reports its placement: the Scheduled and SatisfyEligibleNodes conditions are set for the first time, and status.eligibleNodesViolations names the replicas placed on nodes their storage pool does not allow, with the reason for each.
  • kubectl get replicatedvolume -o wide shows CONVERGED and CONFIGURATIONREADY, so a volume whose layout is stuck or whose configuration is invalid is visible in the list instead of only inside the object.
  • Switching resyncSlotsPerNode on no longer costs the controller the whole cluster in memory: a cluster of thousands of volumes used to push it into its pod limit.

New features

This release adds:

  • Scheduled reports whether every replica of a volume has landed on a node, aggregated over the non-deleting replicas the scheduler places — Access replicas, which follow their consumer, are excluded. It is orthogonal to availability and does not enter Ready: a volume with a misplaced replica keeps serving I/O.
  • SatisfyEligibleNodes reports whether the placement agrees with the storage pool’s eligible nodes, and status.eligibleNodesViolations lists the offending replicas with their node and a reason. Beyond the per-replica verdict it checks what only the member set can show: under TransZonal a node carrying no zone, a zone the pool has no eligible nodes in, and all voters collapsed into a single zone; under Zonal every voter outside the home zone.
  • A ReplicatedStorageClass counts those volumes in status.volumes.inConflictWithEligibleNodes and sets its VolumesSatisfyEligibleNodes condition accordingly — the counter was structurally pinned at zero while the volume condition was never written.

Improvements

This release improves:

  • Two wide print columns are back in the ReplicatedVolume list: CONVERGED (the MembershipLayoutConverged condition, the only list-level view of a membership that will not move without a human) and CONFIGURATIONREADY (whether the configuration itself is valid and current against the storage class, the half CONFIGURED does not answer). Both are wide-only, so the default output is unchanged.

Fixes

This release fixes:

  • The resync limiter no longer reads the whole cluster for every decision. Each budget decision used to materialise every ReplicatedVolume and every ReplicatedVolumeReplica, and ten workers doing that at once exceeded the controller pod’s memory allowance; the listings are now narrowed by field indexes and the queue is built one claim at a time, so a candidate costs a few hundred bytes rather than its replicas. The decisions themselves are unchanged.
  • Metrics of the CSI controller and the CSI node driver are scraped again. Their kube-rbac-proxy sidecars authorise every scrape through a TokenReview and a SubjectAccessReview, and the csi ServiceAccount was bound to neither, so the proxy answered 401 while the pods stayed Ready — the only symptom was up == 0 on both jobs and a TargetDown that never cleared.
  • The same binding was missing for the legacy control plane’s controller: its metrics proxy is rendered, the ServiceMonitor selects the Service, and every scrape was refused by the API server.

Upgrade notes

Before upgrading, note the following:

  • Nothing has to be done by hand, and no volume is moved: the two placement conditions only report what is already there.
  • A storage class whose volumes have replicas on non-eligible nodes can leave Ready for the first time after the update — for PartiallyAligned under the Manual resolution strategy, for RollingOut where conflict resolution is enabled. The placement was already wrong; it is now reported. Which replicas are meant is in status.eligibleNodesViolations of the volumes the class counts.

Docs

Documentation changes:

  • The Replication r3 → r2 migration guide names the print columns that exist: progress per volume is watched through LAYOUT and, in -o wide, CONVERGED.

v0.9.8

Release date: 2026-09-14

The module’s certificates are now renewed and rolled out on their own, the false expiry alert is gone, and the controller publishes metrics behind a kube-rbac-proxy.

Highlights

Changes in this release:

  • Module certificates are re-signed 45 days before they expire and the workloads using them are restarted automatically. Until now nothing renewed a certificate at all: it was regenerated only when its Secret went missing or empty.
  • D8LinstorCertificateExpiringIn30d no longer fires for certificates that are not the module’s own. The hook labelled every Secret in the module namespace, including the Let’s Encrypt ones copied there by secret-copier.
  • The controller serves metrics behind a kube-rbac-proxy, with a ServiceMonitor for Prometheus.

New features

This release adds:

  • The controller publishes metrics: it binds them on 127.0.0.1 and a kube-rbac-proxy in the same pod serves them over TLS, so reaching them takes get on deployments/prometheus-metrics and the grant goes to the Prometheus scraper alone. A ServiceMonitor is created where the kind exists, and the ports are settable through the oldControllerMetricsPort and oldControllerMetricsProxyPort module values.

Improvements

This release improves:

  • The controller logs through the shared logger in the structured format the rest of the fleet uses, instead of its own copy of an older logging package.

Fixes

This release fixes:

  • Certificates are renewed without manual intervention. Every certificate group now keeps its CA, certificate and private key in its own Secret, and a certificate is re-signed by the same CA 45 days before it expires; the CA lives ten years and is replaced only once it can no longer cover a full certificate lifespan. Renewal takes effect on a restart, and a new hook restarts the workloads that reference a renewed certificate Secret.
  • The expiring-certificate hook now looks only at the module’s own Secrets, strips its label from the rest and no longer panics on a Secret without labels. Before this, every Secret in the module namespace was labelled, so certificates copied in by other modules tripped D8LinstorCertificateExpiringIn30d every few weeks.
  • The linstor-scheduler-admission-certs Secret, left over from a component removed earlier, no longer forces the webhook certificate group to be re-issued on every hook run — which re-minted the CA and rewrote the webhook caBundle each time. It is dropped from the group and from the openapi schema, and a hook deletes the leftover Secret.
  • A volume whose filesystem the CSI driver creates itself after a failed mount is formatted with mkfs.ext4 -m0, so it no longer hands 5% of its space to the superuser.

Upgrade notes

Before upgrading, note the following:

  • Nothing has to be done by hand, and the update rotates nothing: certificate groups issued by earlier versions, whose CA key is unknown, are left untouched until their certificates go outdated.
  • Workloads that need a renewed certificate are restarted by a hook on the convergence that follows the renewal. Renewing 45 days ahead leaves the previous certificate valid in the meantime.

v0.9.7

  • Bugfix: the controller is granted patch on events instead of list - a repeated event write is no longer denied by RBAC
  • Bugfix: the VPA is switched from the deprecated Auto update mode to InPlaceOrRecreate
  • Optional resources are enabled based on the presence of the CRD in the API, not on the list of enabled modules - the checks are routed through helm_lib_api_version_exists
  • Base images updated to v2.1.2 and Go to 1.26.6
  • Internal build changes: CI updated, crds, docs and openapi are shipped in the release image

v0.9.6

  • Correction: the CSI module service account is no longer blocked by the validating webhook when creating an RWX PersistentVolumeClaim
  • Fixed links in documentation
  • Updating base images and lib-helm to 1.72.13

v0.9.5

  • Dependency on snapshot-controller module made optional: VolumeSnapshotClass is created only if the snapshot.storage.k8s.io group CRD is present, the rest of the functionality works without it
  • Correction: only the credentials of the active image source remain in the deckhouse-registry secret
  • Correction: LINSTOR no longer requests a list of all cluster CRDs when determining the database version
  • Correction: LINSTOR ignores unknown object properties when working with Kubernetes API
  • Correction: installing DRBD on nodes reinstalls the package if the sources are outdated and more strictly checks the version of the loaded module
  • Re-issuance of certificates has been switched to a manual procedure described in the FAQ; manualcertrenewal-trigger trigger hook removed
  • Updating base images, container-base and lib-helm to 1.72.12
  • Fixed vulnerabilities found when scanning module images
  • Internal changes in module assembly

v0.9.4

  • When forwarding labels from ReplicatedStorageClass to StorageClass, labels with specified ignored prefixes are now excluded
  • Updating base images and lib-helm to 1.72.0

v0.9.3

  • Labels from ReplicatedStorageClass are now forwarded to the Kubernetes managed StorageClass
  • Update base images, Go 1.25.10 and lib-helm 1.71.12

v0.9.2

  • Added x-config-version marker to the OpenAPI schema config-values ​​for versioning module parameters

v0.9.1

  • Documentation - clarifications in the FAQ about SSDs
  • Internal changes in module structure and assembly

v0.9.0

  • Update DRBD version to 9.2.16. Important: nodes will need to be rebooted
  • Internal changes in the module

v0.8.19

  • Update base images, Go 1.25.10 and lib-helm 1.71.11
  • Internal changes to the module assembly

v0.8.18

  • Corrections to the module structure

v0.8.17

  • CI changes: DistroPackagesProxy and env proxy in werf, improvements to CVE scans (role_name, checkout)
  • Added user-authz cluster roles in templates

v0.8.16

  • Added missing mount points in webhooks distroless image
  • Update base images, Go and lib-helm (CVE fix)
  • Clarifications in the documentation

v0.8.15

  • Added a hook for clearing resources when the module is turned off
  • Removed the enableThinProvisioning setting, we assume that thin provisioning is always enabled
  • Module-sdk update for CVE fix, golang update

v0.8.14

  • Corrections in documentation
  • Reworking manifestos
  • Added a ban on ordering RWX volumes for all except the virtualization module

v0.8.13

  • Switch from yum to dnf for package installation on CentOS-like distributions
  • Fix CVE
  • Updated documentation
  • Increased liveness probe timeout for linstor-controller to 60 seconds

v0.8.12

  • Documentation fixes
  • Fix HA-mode, now it works correctly
  • Removed scheduler functionality, remaining for compatibility with old Deckhouse versions

v0.8.11

  • Updated base images versions

v0.8.10

  • Updated Go version to 1.24.9
  • Updated lib-helm to deckhouse_lib_helm-1.64.1

v0.8.9

  • Fixed satellite bind address to avoid potential external access to the cluster

v0.8.8

  • Update base images to v0.5.34
  • Add pull secrets to CSI controller and node

v0.8.7

  • Fixed error with not created FS when creating volumes
  • Documentation fixes

v0.8.6

  • Added release notes
  • Hooks switched from python to golang
  • Docs improved

v0.8.5

  • Added additional mountings for containerd v2 support

v0.8.4

  • Added information about the need for snapshot-controller for module operation

v0.8.3

  • Documentation fixes
  • Added dependency on snapshot-controller

v0.8.2

  • Certificate update hook fixes
  • Removal of obsolete migration hooks

v0.8.1

  • Documentation fixes (added instruction for expanding ReplicatedStoragePool to a new cluster node)

v0.8.0

  • Module refactoring
  • Documentation fixes
  • Fixes for volume snapshot support

v0.7.4

  • If topology allows, controller removes annotation for StorageClass that prohibits ordering RWX volumes

v0.7.3

  • Module refactoring
  • Fixed podAntiAffinity for sds-replicated-volume-controller

v0.7.2

  • Changes in hooks for correct manual certificate update process
  • Fixed D8NodeHighUnknownMemoryUsage alert grouping

v0.7.1

  • Added CSI patch for full support of topologies specified in ReplicatedStorageClass (could be ignored)
  • Added D8NodeHighUnknownMemoryUsage alert for detecting DRBD memory leak cases (report issues to team storage)

v0.6.0

  • Updated DRBD to version v9.2.12, solving a number of problems (particularly improving DRBD diskless replica stability)

v0.5.1

  • Fixed alert for incorrect number of resource replicas
  • Fixed schedule job for Linstor database backup

v0.5.0

  • Multiple minor fixes in templates, monitoring alerts and documentation
  • Transition from linstor scheduler-extender to internal Deckhouse mechanisms (KubeSchedulerWebhookConfiguration)
  • Migration of images to distroless
  • Fixed and enhanced script for outputting drbd resources from node

v0.4.3

  • Technical release. Fixes and additions to evict.sh script for resource eviction from node, fixes in templates and documentation

v0.4.1

  • In evict.sh script for cleaning node from DRBD resources, AutoplaceTarget parameter is now taken into account, moved replicas will not be moved to nodes with AutoplaceTarget value equal to false

v0.4.0

  • Updated golang API libraries for sds-node-configurator v0.4.0 support
  • Multiple fixes in controllers and documentation

v0.3.5

  • Multiple fixes and improvements in evict.sh and replicas_managers.sh (also, they are now automatically installed in /opt/deckhouse/sbin)
  • DRBD now correctly builds on ALT Linux and with Linux kernel 6.5+
  • Added anti-affinity rules for controller pods
  • Multiple fixes in dashboard and alerts
  • isDefault parameter removed; use standard k8s annotation instead
  • Added liveness and readiness checks for controllers
  • Backup switched to dedicated CR instead of using secrets in module namespace
  • Prohibited creation of pools on ephemeral nodes
  • Multiple documentation fixes
  • CSI endpoint migrates from linstor.csi.linbit.com to replicated.csi.deckhouse.io

v0.2.9

  • Add DRBD ports range settings
  • Fix path in liveness-satellite
  • Actual typo lvmVolumeGroups and thinPoolName in examples
  • Add a check for a Linstor node’s AutoplaceTarget property
  • Changed lvmvolumegroups to lvmVolumeGroups in russian docs
  • Fix linstor satellite VPA

v0.2.8

  • Add check if /etc/modules file exists
  • Add liveness probe for linstor-node
  • Add age field
  • Prevent Node Reboots on Volume Deletion

v0.1.11

  • Fix enabled script, module will not be disabled if sds-node-configurator module disappears from cluster