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
storageClassLabelIgnoredPrefixesare again not copied from aReplicatedStorageClassto 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_maskwith 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-mdfailed 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 rancreate-md --forceover it. On nodes rebooted one after another this rewrote the metadata of replicas that held data. Now the agent reports the error in theConfiguredcondition of theDRBDResourceand 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-granularityequal 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 randrbdsetup disk-optionsabout 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
ReplicatedStorageClasswhose keys matchstorageClassLabelIgnoredPrefixes(by defaultargocd.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.volumeCleanupwipes 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
ReplicatedStorageClasscan be changed after creation, and degraded classes and pools are reported by the newDegradedphase, 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:viewandd8:system-capability:sds-replicated-volume:editgrant read-only and full access toReplicatedStorageClass,ReplicatedStoragePool,ReplicatedVolume,ReplicatedVolumeReplica,ReplicatedVolumeAttachment,DRBDResource,DRBDResourceOperation,DRBDNodeOperationandDRBDMapper. Below 1.78 the module keeps thed8:manage:permission:module:sds-replicated-volume:viewand:editroles. - New alerts of the new control plane:
D8ReplicatedStoragePoolNotReadyfires when aReplicatedStoragePoolhas not beenReadyfor 5 minutes (a missing LVMVolumeGroup or thin pool, an invalid node selector), andD8ReplicatedStorageClassNotReadywhen aReplicatedStorageClasshas not beenReadyfor 5 minutes. A class whose storage pool is notReadyis 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 metricssds_rsp_condition_problem_timestamp_secondsandsds_rsc_condition_problem_timestamp_secondsfor them. - The
SDS Replicated VolumeGrafana 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 againstallocationLimit, and a table per node and LVMVolumeGroup. Thin pools are counted by their allocation limit: free space is the thin pool size multiplied byallocationLimitminus the space already allocated. For this, the controller exports the new metricssds_rsp_lvg_info(the LVMVolumeGroups and thin pools of aReplicatedStoragePool) andsds_rsc_replicas(the number of replicas and the storage pool of aReplicatedStorageClass), which join the capacity metrics of sds-node-configurator to storage classes. - In the new control plane, a
ReplicatedStorageClasscan wipe the data of its volumes before their space is released:spec.volumeCleanuptakes the methods of sds-node-configurator,RandomFillSinglePass,RandomFillThreePassorDiscard(thick volumes only,storage.type: LVM). The method is fixed for a volume when it is created (it is recorded inspec.volumeCleanupof theReplicatedVolume), 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,
ReplicatedStorageClassandReplicatedStoragePoolnow record a Kubernetes Event when theirReadycondition changes status or reason: aWarningwhen it turnsFalse, aNormalone when it turnsTrueagain. The reason of the Event is the reason of the condition, for exampleWaitingForStoragePool,DegradedorLVMVolumeGroupNotFound, sokubectl describeshows 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 thedefaultnamespace, and the controller is granted the right to create them there.
Improvements
This release improves:
- New alert
D8DrbdResourceIOSuspendedfires 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, ordrbdsetup 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.thinPoolsof 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-extenderno longer recordsFailedSchedulingEvents 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.zonesandspec.eligibleNodesPolicyof aReplicatedStorageClasscan 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
ReplicatedStorageClasswhose storage pool or eligible nodes degraded after its configuration was accepted is reported in the newDegradedphase with theDegradedreason ofReady: the accepted configuration stays in effect, but replicas can be placed only on the nodes the pool still offers. TheTerminatingphase names the number of volumes it waits for, andVolumesSatisfyEligibleNodesnames 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 theReplicatedStorageClassgoes to theInvalidConfigurationphase withReady=False, reasonStorageClassConflict, 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
ReplicatedStorageClasswhose name is held by a StorageClass of another provisioner now goes to theInvalidConfigurationphase 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. DeleteVolumerefused 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 byControllerUnpublishVolume, which the external-attacher never calls again once the VolumeAttachment is gone, and the PersistentVolume stayedReleased.DeleteVolumenow releases such attachments first, unless their device is still in use.- In the new control plane, the StorageClass of a
ReplicatedStorageClassnow has the annotationstorage.deckhouse.io/volumesnapshotclass: sds-replicated-volume, as in the LINSTOR control plane. Without it, storage-foundation did not fill involumeSnapshotClassNameof 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,
lvcreateandlvremovefrom both sides ran without excluding each other and could corrupt the thin pool metadata. - A
ReplicatedStorageClassorReplicatedStoragePoolbeing deleted can lose its finalizer again. The webhook checked that update too, so a class that stopped passing validation after creation, for example anIgnoredtopology once the nodes got zone labels, hung in deletion for good. - The webhook now rejects a
ReplicatedStorageClasswhen 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
eligibleNodesPolicyno 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
Degradedphase now switch toAutoinstead of waiting until the migration step gives up.
Security updates
Security updates in this release:
golang.org/x/netv0.62.0 (CVE-2026-78661, CVE-2026-97045), and the ALT Linux packages ofspaas,drbd-reactor,metadata-backupandlinstor-serverare 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:viewand:editClusterRoles 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:viewand:editClusterRoles are replaced byd8:system-capability:sds-replicated-volume:viewand: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
allocationLimitof the thin pool in LVMVolumeGroup has no effect on the module’s volumes. - The description of the
dataNodes.nodeSelectorparameter and the FAQ now say what the parameter does: nodes that match it get thestorage.deckhouse.io/sds-replicated-volume-nodelabel and module components run on them, and a custom value replaces the defaultkubernetes.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
ReplicatedStorageClassfromAvailabilitytoConsistencyAndAvailabilityturns 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,D8ReplicatedVolumeNotResilientandD8SdsReplicatedVolumeCurrentMetricsUnavailablealerts 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
SecurityPolicyExceptionfor every workload that needs more than therestrictedprofile, 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 aReplicatedVolumehas not beenReadyfor 5 minutes,D8ReplicatedVolumeNotResilient(severity 6) when it has not beenResilientfor 30 minutes while stillReady, andD8SdsReplicatedVolumeCurrentMetricsUnavailable(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.D8ReplicatedVolumeNotResilientalso 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_countandsds_rv_condition_problem_timestamp_secondsfor the conditions ofReplicatedVolumes,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 theconfiguration_modelabel (AutoorManual) ofsds_rv_count. The agent exportssds_drbd_module_infowith 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, notResilient, 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 neitherUpToDatenorDiskless. D8ReplicatedVolumeLayoutDegradedno longer fires for a volume underspec.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
restrictedprofile get aSecurityPolicyExceptionthat describes each privilege, and their Pods carry thesecurity.deckhouse.io/security-policy-exceptionlabel pointing to it:agent, thecontrol-plane-migratorJob and the CSI node in the new control plane,linstor-node,linstor-controllerand the CSI node in the LINSTOR control plane. The objects are rendered only when theSecurityPolicyExceptionresource is available in the cluster (theadmission-policy-engine-crdmodule is enabled).
Fixes
This release fixes:
- In the new control plane, raising a
ReplicatedStorageClassfromAvailabilitytoConsistencyAndAvailabilityon 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; otherwiseMembershipLayoutConvergedreportsCannotConverge. 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
UpToDatecopy until all three areUpToDate. Before, the third copy joining raised this minimum to two while only two copies wereUpToDate, so a single failure during the resynchronization suspended I/O. - In the new control plane, DRBD metrics of a node are scraped while the
agentPod 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
DRBDResourcedeletion is observed once (before, about a third of them were),sds_rvr_backing_volume_duration_secondsandsds_drbdr_configured_duration_secondsno 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_secondscounts only the first attach, and volumes without aReplicatedStorageClassare reported asstorage_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 (
CHOWNandFOWNERfor the init container ofcontrol-plane-migrator); for the privilegedagentandlinstor-satellitecontainers this changes only the manifest. Thekube-rbac-proxycontainers ofagentrun as thedeckhouseuser 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, andurllib3in 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
SecurityPolicyExceptionresource 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_secondsand thesds:rvr_degraded_countrecording rule are removed (usesds_rv_condition_problem_timestamp_seconds, the_countofsds_rv_datamesh_transition_duration_secondsandsds_rvr_ready_lost_totalinstead), 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
ReplicatedStorageClasscreated withoutspec.replicationis handled asConsistencyAndAvailabilityby 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 the6.12flavour), the DRBD NodeGroupConfiguration installs the headers of the running flavour, so DRBD is built instead of failing on a missingkernel-headers-modules-std-defpackage. - The
resyncSlotsPerNodemodule 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
logLevelinstead of always logging at debug level. With the defaultInfo, the migrator logs atinfoand 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
ReplicatedStorageClassfromAvailabilitytoConsistencyAndAvailabilitycompletes by itself: after the third diskful copy isUpToDate, the surplus tie-breaker is deleted automatically, and the volume no longer stops atTransitionUnsupportedwaiting for it to be deleted by hand.
Fixes
This release fixes:
- The legacy webhook applies the three-zone
TransZonalcheck to aReplicatedStorageClasswithoutspec.replication, so the mistake is rejected on apply instead of surfacing later asInvalidConfiguration. The legacy webhook and the CRD validation also rejectreplication: Consistencyon the legacy control plane, which has no StorageClass layout for it. Existing StorageClasses already labeled non-operational because of the emptyreplicationlose the label. - The CSI node of the new control plane serves
/metrics,/healthz,/readyzand/healthon its loopback metrics address only. It no longer listens on port 8081 on all interfaces, where it conflicted withcapdvp-controller-manageron 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, reasonQuorumLost). The agent raises the quorum only after the new peer counts as a vote, the controller raises it only after the joining replica isConnectedto every member, and a voter seenConnectedby 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
UpToDatecopies 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
ReplicatedVolumeReplicaonly 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,
TransZonalvalidation of aReplicatedStorageClassrequires a non-emptyzoneslist 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
resyncSlotsPerNodemodule 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,
failuresToTolerateandguaranteedMinimumDataRedundancyof aReplicatedStorageClassand ofspec.manualConfigurationof aReplicatedVolumeaccept 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.resyncSlotsPerNodefrom thesds-replicated-volumeModuleConfig 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
ReplicatedStorageClassandReplicatedStoragePoolphase isReadyrather thanCreatedorCompleted,specof these resources cannot be changed after creation, and expanding aReplicatedStoragePoolto 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
ReplicatedStorageClassandReplicatedStoragePoolmarks the fields used only by the new control plane, describes the shared fields identically in English and Russian, and marksreplicationandstoragePoolas deprecated only in the new control plane. - The
ReplicatedStorageClassexamples are fixed: the HA class example in the Russian usage guide hadnameoutsidemetadata, and the FAQ example no longer containsmetadata.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 aReplicatedStorageClasscreated by an earlier version, or one whosestorage.deckhouse.io/ext4-reserved-percentannotation changes, no longer ends up in theInvalidConfigurationphase. - 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
ReplicatedStorageClassandReplicatedVolume.
Fixes
This release fixes:
- Since v0.9.8 the legacy controller always writes
replicated.csi.storage.deckhouse.io/fsOptsinto 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 itsReplicatedStorageClasswent to theInvalidConfigurationphase after the upgrade; changing thestorage.deckhouse.io/ext4-reserved-percentannotation was refused the same way. The StorageClass is now recreated instead.fsOptsis 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-waitandlinstor-migrator:golang.org/x/netv0.56.0 → v0.58.0,golang.org/x/sysv0.46.0 → v0.47.0,golang.org/x/textv0.39.0 → v0.41.0, and, in the controller and the webhooks,go.opentelemetry.io/otelv1.37.0 → v1.41.0 andgithub.com/google/cel-gov0.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,DRBDResourceandReplicatedVolume, mostDRBDResourcefields, and the node and volume names, sizes, addresses and conditions of theReplicatedVolume*resources. The Russian description ofstatus.activeConfiguration.nonVotingofDRBDResourceis corrected: the field istruewhen 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,kindand the condition fields, and the translations ofstatus.reasonofReplicatedStorageClassandReplicatedStoragePoolmove tostatus.message, the field the schema actually has. - The description of
specofReplicatedStorageClassno longer opens with about thirty lines of CEL validation notes,specofReplicatedVolumegets the description “Desired state of the replicated volume” instead of CEL rule labels, andsystemNetworkNamesandlvmVolumeGroupsno 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
ReplicatedVolumeby itself instead of stopping atTransitionUnsupportedand waiting for a replica to be created by hand. resyncSlotsPerNodeis on by default (4), so a node going away does not start every resync of the volumes it held at once.spec.maintenance: NoResourceReconciliationon aReplicatedVolumepauses reconciliation of that volume, its replicas and its DRBD resources while every other volume keeps reconciling.
New features
This release adds:
ReplicatedVolumehasspec.maintenance. WithNoResourceReconciliation, 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,ResilientandAttachedReadykeep being published, the rest of the status freezes, and the pause is reported by theUnderMaintenancecondition and theMaintenancecolumn ofkubectl get replicatedvolume -o wide. A paused volume does not finish deleting: it and its PVC stayTerminatinguntil the field is cleared.- A
ReplicatedVolumewhose 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 reportsCannotConvergewith the scheduler’s reason.
Improvements
This release improves:
- The
resyncSlotsPerNodedefault 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-nodewas set only on nodes already eligible for aReplicatedStoragePool. That label is what brings up thesds-node-configuratoragent, which creates theBlockDeviceresources anLVMVolumeGroupis built from, so no pool could get eligible nodes in the first place. Nodes matchingdataNodes.nodeSelectornow get the label directly.
Security updates
Security updates in this release:
google.golang.org/grpcis raised from v1.82.1 to v1.83.2 in the CSI driver,linstor-csi,linstor-affinity-controllerandlinstor-scheduler-extender, closing CVE-2026-84303, CVE-2026-84304 and CVE-2026-84445.golang.org/x/cryptois raised from v0.53.0 to v0.57.0 in the module’s hooks (go-hooks) andlinstor-scheduler-extender, closing CVE-2026-56854 (authentication bypass by source address inx/crypto/ssh), CVE-2026-56855 and CVE-2026-78662.
Breaking changes
Changes that affect backward compatibility:
evict.shandreplicas_manager.share installed in/var/lib/deckhouse/sbininstead 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.shandreplicas_manager.shto/var/lib/deckhouse/sbin; update any runbook that calls/opt/deckhouse/sbin/evict.sh. - If
resyncSlotsPerNodewas 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, setresyncSlotsPerNode: 0.
Docs
Documentation changes:
- The usage guide describes recovering a lost replica, which no longer needs a manual step, and the
D8ReplicatedVolumeLayoutDegradedalert 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
ReplicatedVolumereports its placement: theScheduledandSatisfyEligibleNodesconditions are set for the first time, andstatus.eligibleNodesViolationsnames the replicas placed on nodes their storage pool does not allow, with the reason for each. kubectl get replicatedvolume -o wideshowsCONVERGEDandCONFIGURATIONREADY, so a volume whose layout is stuck or whose configuration is invalid is visible in the list instead of only inside the object.- Switching
resyncSlotsPerNodeon 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:
Scheduledreports whether every replica of a volume has landed on a node, aggregated over the non-deleting replicas the scheduler places —Accessreplicas, which follow their consumer, are excluded. It is orthogonal to availability and does not enterReady: a volume with a misplaced replica keeps serving I/O.SatisfyEligibleNodesreports whether the placement agrees with the storage pool’s eligible nodes, andstatus.eligibleNodesViolationslists the offending replicas with their node and a reason. Beyond the per-replica verdict it checks what only the member set can show: underTransZonala node carrying no zone, a zone the pool has no eligible nodes in, and all voters collapsed into a single zone; underZonalevery voter outside the home zone.- A
ReplicatedStorageClasscounts those volumes instatus.volumes.inConflictWithEligibleNodesand sets itsVolumesSatisfyEligibleNodescondition 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
ReplicatedVolumelist:CONVERGED(theMembershipLayoutConvergedcondition, the only list-level view of a membership that will not move without a human) andCONFIGURATIONREADY(whether the configuration itself is valid and current against the storage class, the halfCONFIGUREDdoes 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
ReplicatedVolumeand everyReplicatedVolumeReplica, 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-proxysidecars authorise every scrape through aTokenReviewand aSubjectAccessReview, and thecsiServiceAccount was bound to neither, so the proxy answered 401 while the pods stayedReady— the only symptom wasup == 0on both jobs and aTargetDownthat never cleared. - The same binding was missing for the legacy control plane’s controller: its metrics proxy is rendered, the
ServiceMonitorselects 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
Readyfor the first time after the update — forPartiallyAlignedunder theManualresolution strategy, forRollingOutwhere conflict resolution is enabled. The placement was already wrong; it is now reported. Which replicas are meant is instatus.eligibleNodesViolationsof 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
LAYOUTand, 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.
D8LinstorCertificateExpiringIn30dno 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 bysecret-copier.- The controller serves metrics behind a
kube-rbac-proxy, with aServiceMonitorfor Prometheus.
New features
This release adds:
- The controller publishes metrics: it binds them on
127.0.0.1and akube-rbac-proxyin the same pod serves them over TLS, so reaching them takesgetondeployments/prometheus-metricsand the grant goes to the Prometheus scraper alone. AServiceMonitoris created where the kind exists, and the ports are settable through theoldControllerMetricsPortandoldControllerMetricsProxyPortmodule 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
D8LinstorCertificateExpiringIn30devery few weeks. - The
linstor-scheduler-admission-certsSecret, 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 webhookcaBundleeach 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