Repository navigation
docs: add the Blockstor storage backend and its migration guide - #667
Andrei Kvapil (kvaps) wants to merge 9 commits into
Conversation
✅ Deploy Preview for cozystack ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
|
Important
This repository does not receive automatic reviews because it has fewer than 10 stars.
|
Aleksei Sviridkin (lexfrei)
left a comment
There was a problem hiding this comment.
Andrei Kvapil (@kvaps) NOT LGTM. This should wait: it documents a platform switch that is not in main yet, and a migration that no released Blockstor can finish.
The pages describe cozystack/cozystack#2942, which is still open with changes requested. The storage.backend key in step 2.3 matches that branch, but main's platform chart has no storage key and no values schema, so backend: blockstor set on a current build is silently ignored. Because next/ is published from main, a reader who follows the page today gets LINSTOR while believing they picked Blockstor. The opposite failure is also possible: if #2942 changes the key or its behaviour before it merges, these pages drift without anything noticing. Merging this right after #2942, and re-checking it against what actually merged, avoids both.
The migration guide moves live volumes, but by its own text adoption fails on every release up to and including v0.1.17. That is still the latest Blockstor release (2026-07-04). The PR description says adoption was never completed in the test run, so the second half of the procedure, the part that writes resources for volumes holding data, has not run end to end anywhere. I'd hold the guide until a release with the storage-pool fix exists and the whole procedure has been run on it, and then name that release as the minimum version instead of the last broken one.
All eight commits end with Assisted-By: Claude. The trailer takes only LLM, and this repo keeps branch commits as they are on merge.
One non-blocking note on the tab sync. The choice is stored in localStorage for the whole site, so a reader who clicked Blockstor once will see the experimental backend preselected on the install page on every later visit, not the default.
Cozystack is gaining a second storage control plane, so the platform install page now presents the choice as tabs rather than assuming LINSTOR. LINSTOR stays the default and is the first tab; Blockstor carries an experimental warning. Adds a migration guide for moving an existing cluster across. It is written from a run against a live cluster, so it leads with the parts that are easy to get wrong: the adoption happens after the switch, not before, because the resources have nowhere to live until the CRDs exist; the controller has to be stopped while the converted resources are applied, or it auto-places replicas on freshly allocated ports and the real ones are then refused; the live DRBD ports have to be read from the kernel because LINSTOR does not keep them in its custom resources; and a cluster coming from LINSTOR hits a Service ownership collision a fresh install never sees. The guide also states the version requirement plainly: a Blockstor build that cannot read a pool name from StorDriver/StorPoolName adopts nothing, which is every release up to and including v0.1.17. Assisted-by: LLM Signed-off-by: Andrei Kvapil <kvapss@gmail.com>
linstor-csi keeps reconciling while the control plane is being replaced, and a volume it cannot find is a volume it re-provisions: it creates a fresh resource definition through the LINSTOR-compatible API, carrying newly allocated DRBD minors and ports and a different node ID, for a volume that already exists and holds data. Those definitions also lack spec.initialized, so the satellite treats them as new. Observed on a live migration, where two already-migrated volumes were re-provisioned this way during the switch window. Assisted-by: LLM Signed-off-by: Andrei Kvapil <kvapss@gmail.com>
Two things claim space during adoption, and both surfaced on a live migration only after the switch had started. Blockstor's thick provider reserves the full size of every volume it adopts. LINSTOR allows a pool declared thick to hold sparse volumes via StorDriver/ZfscreateOptions, so a comfortably oversubscribed pool can fill up mid-migration and leave the last volumes unadoptable. Blockstor also reconciles replica count against the resource group's placeCount continuously, where LINSTOR only places on request, so every under-replicated volume is topped up as soon as the controller starts. Assisted-by: LLM Signed-off-by: Andrei Kvapil <kvapss@gmail.com>
The runbook stopped only the CSI provisioner, and only at the switch. Two writers were left running through the backup and the dump. piraeus-operator owns the linstor-controller Deployment and the satellite DaemonSets, so scaling the controller down while the operator runs achieves nothing — it puts it straight back. And the controller itself keeps writing to its database, so a backup taken underneath it does not match the dump taken a moment later, and the converted manifest then describes a cluster that no longer exists. The stop moves to its own first step, in dependency order, ahead of the backup. The CSI scale-down moves there with it; step 6 now explains the window rather than repeating the command. Two prerequisites corrected while here. The Blockstor version is not the operator's to choose — it arrives pinned inside the Cozystack release, so the check is a Cozystack version check and the remedy is an upgrade, not an image swap. And the thick-pool capacity warning is gone: the converter now carries a sparse ZFS pool over as thin, so adoption no longer reserves the full size of volumes LINSTOR created sparse. What remains of that prerequisite is the placeCount top-up, which is real. Assisted-by: LLM Signed-off-by: Andrei Kvapil <kvapss@gmail.com>
A {{% %}} shortcode renders its body as Markdown, so an alert nested
inside a tab runs its body through twice: the inner shortcode receives
the HTML the outer already produced, and escapes it. The notice came out
as a literal <strong> inside a code block.
It lives outside the tabs now, which also means the reader sees it
whichever tab is open.
Assisted-by: LLM
Signed-off-by: Andrei Kvapil <kvapss@gmail.com>
Step 2.3 lets the operator choose Blockstor, and then step 3 walked them into commands that cannot work there. Every command in 3.1 and 3.2 runs through `kubectl exec deploy/linstor-controller`, and on backend: blockstor the control plane runs in external mode — that Deployment is never created, so each one fails with NotFound. 3.1 and 3.2 now say which backend they are for, and 3.4 covers the same ground for Blockstor: list the nodes, create the ZFS pool through the satellite (which carries the tooling), register it as a StoragePool custom resource, check the result. It is kubectl throughout, because Blockstor keeps its state in custom resources rather than behind a controller pod — there is nothing to exec into. Storage classes are backend-independent, so 3.3 is shared and both paths lead into it. Assisted-by: LLM Signed-off-by: Andrei Kvapil <kvapss@gmail.com>
The first version of 3.4 configured storage by applying custom resources by hand, on the reasoning that Blockstor keeps its state in CRDs. That missed the point: Blockstor ships a client that speaks the same command grammar as LINSTOR, short forms included, so the steps mirror 3.1 and 3.2 one for one and an operator moving between backends types almost the same thing. What actually differs is the client. `blockstor` is a standalone binary that talks to the Kubernetes API directly — no controller pod to exec into, no alias to set, it reads the kubeconfig the way kubectl does. Assisted-by: LLM Signed-off-by: Andrei Kvapil <kvapss@gmail.com>
The backend choice was a tab set in 2.3, and the steps that act on it were a separate section further down. An operator picking Blockstor had to remember that and navigate to a different heading. The `tabs` shortcode gains an opt-in `sync` group. Tab sets sharing a group switch together and the choice is remembered, so picking a backend anywhere on the page switches every command that follows. Tab sets without the parameter behave exactly as before — nothing else on the site changes. Storage now reads as one flow: 3.1 and 3.2 are backend tabs in that group, and the separate Blockstor section is gone. ZFS/LVM inside 3.2 became plain headings rather than an inner tab set: the shortcode collects tabs through a page Scratch, so a nested set absorbs content from beyond its own boundary — the inner tabs came out carrying labels lifted from later paragraphs. Assisted-by: LLM Signed-off-by: Andrei Kvapil <kvapss@gmail.com>
Blockstor v0.2.0 reads the pool name LINSTOR stores, so it is the release the migration needs; name it instead of the last one that could not. The platform now refuses to change the backend of a running cluster unless storage.acknowledgeBackendChange names the new one, so the switch and the rollback set it. The API group is blockstor.org, and the chart no longer renders the compatibility Service that collided with piraeus-operator's. The converter's step names what it skips and the LUKS key slot it needs, and points at Blockstor's own runbook. Assisted-by: LLM Signed-off-by: Andrei Kvapil <kvapss@gmail.com>
49cecf1 to
451434c
Compare
✅ Deploy Preview for cozystack ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
Documents Blockstor as a second, selectable storage control plane, and how to move an existing cluster onto it.
Goes to
content/en/docs/next/because Blockstor is unreleased.What changes
The platform install page presented LINSTOR as the only option. It now presents the choice as tabs under a new 2.3. Choose a Storage Backend: LINSTOR first and marked as the default, Blockstor second and marked experimental. Subsequent sections are renumbered.
The storage section index said these guides describe "the LINSTOR storage system"; it now names both backends, links to the choice and the migration, and states that unless a page says otherwise it describes LINSTOR.
Adds Migrating from LINSTOR to Blockstor.
About the migration guide
It is written from an actual run against a live cluster rather than from the design, so it leads with the parts that are easy to get wrong and that only a real migration surfaces:
drbdsetup showincantation, including the detail that the port sits inside the connection'spathblock rather than on anaddressline.storage.acknowledgeBackendChangenames the new one, so the switch and the rollback both set it.StorDriver/StorPoolName, logunknown storage pooland adopt nothing.Status of the procedure
The steps up to and including the backend switch were executed against a live 3-node cluster with 41 volumes: the control plane was replaced with no data loss and no service disruption, DRBD kept serving throughout, and all peers stayed UpToDate.
That run used a Blockstor that could not register the pools, so adoption was not completed. Blockstor v0.2.0 has the fix and is what cozystack/cozystack#2942 now pins, but the whole procedure, adoption included, has not been run on it yet. This PR merges after cozystack/cozystack#2942, and is re-checked against what that PR merges with.
Testing
Rebased on main.
hugo --gc --environment developmentbuilds clean. The tabs render as real tab controls with both labels, the migration page renders, and the cross-link anchor#23-choose-a-storage-backendexists on the target page.