The module lifecycle stage: Experimental
The module has requirements for installation
v0.0.5
- Fix: spec.placement (nodeSelector and tolerations) is now finally applied. The field has been in the API from the start and documented as affecting data plane pods, but it was never read — the API accepted it, but pods were scheduled as if nothing was specified. It now applies to all pods deployed by the module: masters, volume servers, and filers.
- Replicas of the same component are spread across different nodes. For masters and volume servers, the rule is strict: three volume servers on the same node cannot survive the failure of that node, and the replication code promised copies on other servers. A replica that does not get its own node remains in Pending — this is the visible form of an impossible promise. Filers prefer to spread out, but will still start even when they cannot: they sit in front of metadata, which resides elsewhere.
- The update will affect already deployed storage: masters and volume servers will be restarted, and on a cluster where there are fewer nodes than replicas, some pods will not come up until the number of replicas is reduced or nodes are added.
- A new field spec.postgresClassName has been added — the name of the PostgresClass from which the managed metadata database is deployed. This is the only way to influence the placement of its pods: the Postgres resource has no scheduling fields at all; tolerations and nodeSelector belong to the PostgresClass, so spec.placement does not reach the database. If empty, the default class is used.
v0.0.4
- Storage reports its capacity: status.capacity with total, used, free, and used fraction — on both backends. Until at least one node responds, the field is not populated: “unknown” and “empty” are different things
- Module metrics, alerting rules, and dashboard: storage readiness and its fill level. Alerts warn about fill above 85% and above 95%, and storage that is not Ready for half an hour is reported separately from storage that has simply stopped reporting
- Filer metadata can be kept in an external PostgreSQL: metadataStore External and a Secret with connection parameters (host, port, database, username, password, sslmode, ca.crt), including server verification with a custom CA. The connection is verified before filers start, and sslmode disable and values unknown to libpq are rejected — passwords and all object names travel over this connection
- Bucket lifecycle expiration rules: spec.lifecycle with expireAfterDays, expireNoncurrentAfterDays, and abortIncompleteUploadsAfterDays and an optional prefix; each rule requires a unique id. Rules are removed from a bucket when they are deleted from the Bucket. There is no storage tier transition: one of the engines does not perform it, and a field that silently does nothing is not introduced
- A bucket that already exists in the backend and is not owned by the module is no longer picked up by name: the module marks its own buckets and refuses to touch another’s, reporting this in the BucketNotOwnedByModule condition
- The documentation now includes a matrix of S3 operation support across backends, indicating the engine versions for which it is filled
- Fix: filers restart when the metadata database connection changes — previously, password rotation updated the configuration, but running filers continued to use the old credentials
- Fix: the Secret with filer configuration is no longer overwritten on every reconciliation cycle
- Internal changes: unit tests for reconcilers, e2e scenarios, and internal project documentation
v0.0.3
- The resource model has been redesigned and is incompatible with the previous version — the module no longer manages resources created under the old model; they must be recreated
- The System and Lightweight profiles have been removed along with the Garage backend. Two backends remain — SeaweedFS and Ceph RGW
- ObjectStore no longer deploys storage; instead, it describes a class modeled after StorageClass: it references a store via spec.storeRef, while the storage itself is described by the new SeaweedFSStore and SDSElasticStore resources
- BucketClaim is now called Bucket and remains in the namespace, while the previous cluster-wide Bucket is now called BucketContents. Data saved with reclaimPolicy Retain waits in the Released phase and is picked up by a newly created Bucket
- BucketClaimPolicy has been removed. Along with it, shared access to a single bucket from multiple namespaces and binding to an existing bucket via regex are gone
- Publishing the S3 endpoint externally: spec.publish on the store defines the hostname, Gateway, and TLS certificate; the module creates a listener and route and publishes the external address in status.endpoint.external. Publishing without TLS is prohibited
- The spec.endpointScope field in BucketAccess selects which address — internal or external — is placed in the Secret with credentials; when the endpoint changes, issued Secrets are reissued
- Setting PublicRead in the bucket’s spec.accessPolicy enables anonymous object reading on both backends. Listing bucket contents is not provided in this case
- Versioning and Object Lock on both backends: GOVERNANCE and COMPLIANCE modes, retention period, and legal hold. Deleting data under an unexpired retention is blocked, and the reason for failure is recorded in the status
- Data integrity report: status.integrity and condition IntegrityHealthy. On SeaweedFS, the module automatically runs scrubbing on a schedule (spec.integrity) and, with separate permission, replaces a damaged copy; on Ceph RGW, the scrub state is taken from the cluster
- Data copy accounting: status.redundancy and condition RedundancyHealthy report volumes that have fewer copies than requested by replication
- Metrics, alerts, and a Grafana dashboard for data integrity, copy shortage, and overdue scrubbing
- Stored data encryption: spec.encryption. On SeaweedFS — server-side encryption with a key from a Secret; key rotation is not applied silently but held for confirmation, otherwise already written objects would become unreadable. On Ceph RGW, keys are taken from Deckhouse Stronghold
- Data plane components are secured with network policies
- Fix: the RGW user identifier fits within Rook’s label length limit — previously, a bucket on Ceph RGW could not become Ready
- Fix: the bucket policy is assembled from the entire cluster state, not via incremental patches — eliminating races when multiple accesses target the same bucket
- Fix: the ‘data is held by retention’ failure is determined from the bucket itself, not its spec — previously, any access error looked the same and permanently held the finalizer
- Fix: deleting a Bucket wakes up its content controller, and a deleting Bucket is no longer considered a live owner — otherwise, a bucket could remain in the backend without a single reference to it
- Fix: the number of slots for SeaweedFS volumes is no longer calculated based on disk size; a volume grows one per bucket
- Fix: a store does not report readiness if it cannot accept a bucket
- Fix: scrubbing is performed outside the reconciliation loop — previously, it did not fit within its budget and did not complete; a pass that covers no volumes is not considered a check
- Unified logger and metrics server for the controller
- Internal changes to the module build
v0.0.2
- {‘Bugfix’: ’the data-plane images (Garage, SeaweedFS) are pulled with the module-scoped registry secret - previously the pull failed in clusters with a private registry’}
- CVE fixes
- lib-helm updated to 1.72.13
v0.0.1
- Initial release of the module in the Experimental stage. The module manages S3-compatible object storage through a set of ObjectStore, Bucket, BucketClaim, BucketAccess and BucketClaimPolicy resources
- {‘ObjectStore deploys and maintains the storage itself according to one of four profiles’: ‘System (Garage on control-plane nodes, local PVs), Lightweight (Garage on PVC), Full (SeaweedFS) and Heavy (Ceph RGW on an existing sds-elastic cluster)’}
- BucketClaim requests a bucket — either its own private one or a binding to a shared bucket allowed by a BucketClaimPolicy resource in the bucket owner’s namespace (deny by default)
- BucketAccess issues a separate access key and writes a Secret with standard connection variables; the key is rotated using the storage.deckhouse.io/rotate annotation
- Module resources publish status.conditions and status.observedGeneration