cozy-lib.resources.sanitize divides the CPU limit by cpuAllocationRatio and rendered the quotient as a bare float. When the ratio does not divide the value evenly the result is finer than a milli-CPU, and the VPA admission webhook rejects it outright: admission webhook "vpa.k8s.io" denied the request: minAllowed: CPU [62500u] must be a whole number of milli CPUs packages/extra/etcd routes its VPA minAllowed/maxAllowed through the helper, so 250m / 4 = 62.5m left the etcd HelmRelease looping UpgradeFailed -> RollbackFailed forever: the rollback target renders the same invalid value. Since v1.6.0 HelmReleases wait on each other, so that one stuck app also blocks tenant-root, cozystack-basics and kubevirt-cdi-operator, and without CDI the Talos worker rollover cannot import the worker OS image. Only the divisors of 250 worked as ratios, which is an artefact of one chart's hardcoded floor rather than a real constraint on the operator. The request is rounded up, never down, so it stays at or above the intended fraction of the limit. It is rounded only when it has to be: if the milli-CPU value equals its own ceiling, the float keeps its current rendering, so nothing changes on the default ratio of 10 or on any ratio that divides evenly; otherwise it renders as the ceiling in m. The comparison is exact, with no tolerance. sprig's divf and mulf run on shopspring/decimal rather than float64, so mulf (divf 0.25 10.0) 1000.0 renders exactly 25 and there is no binary-float noise on this codepath to absorb. A tolerance would reintroduce the bug: a value whole-milli only to within it, such as 100.0000004m at ratio 1, would read as exact and render "0.1000000004", rejected for the same reason 62.5m is. The same predicate covers sub-milli input, since ceil carries any positive request to at least 1m, and a zero request stays "0". Fixes #2917 Assisted-by: LLM Signed-off-by: Mattia Eleuteri <mattia@hidora.io>
Etcd-cluster
This chart renders an EtcdCluster (etcd-operator.cozystack.io/v1alpha2)
managed by the cozystack etcd-operator, plus the cert-manager CA chain and a
Kamaji DataStore. TLS uses secretRef mode: this chart's own cert-manager
Certificate resources issue the server, operator-client and peer certs from
the etcd-issuer / etcd-peer-issuer CA Issuers, and the EtcdCluster only
references the resulting Secrets via serverSecretRef /
operatorClientSecretRef / peer.secretRef (the operator itself mints
nothing). This is deliberate: spec.tls is immutable in v1alpha2 and
etcd-migrate adopts legacy clusters into exactly this secretRef shape, so the
chart must match it or every post-adoption reconcile is rejected. etcd runs
cert-only (--client-cert-auth, no password auth); consumers authenticate by
presenting a commonName=root client cert (etcd-client-tls) signed by the
same CA.
Backups
Backups are driven by the Cozystack BackupClass flow: a BackupJob /
RestoreJob against the Etcd strategy (strategy.backups.cozystack.io/v1alpha1).
See examples/backups/etcd/ for the end-to-end demo and
internal/backupcontroller/etcdstrategy_controller.go for the driver. The
driver materialises one EtcdSnapshot (etcd-operator.cozystack.io/v1alpha2)
per BackupJob; restore is in-place (the driver suspends this chart's
HelmRelease, deletes the live EtcdCluster, and re-creates it with
spec.bootstrap.restore.source.s3 populated from the Backup artefact's
coordinates).
The legacy
backup.*values block and theEtcdBackupScheduleCRD no longer exist under the v1alpha2 operator — scheduled backups are expressed as aBackupClass/Planinstead.
Parameters
Common parameters
| Name | Description | Type | Value |
|---|---|---|---|
version |
etcd version (X.Y.Z) to run, set on the EtcdCluster's spec.version; the operator pulls etcd from its own configured image. | string |
3.6.11 |
size |
Persistent Volume size. | quantity |
4Gi |
storageClass |
StorageClass used to store the data. | string |
"" |
replicas |
Number of etcd replicas. | int |
3 |
resources |
Resource configuration for etcd. | object |
{} |
resources.cpu |
Number of CPU cores allocated. | quantity |
1000m |
resources.memory |
Amount of memory allocated. | quantity |
512Mi |
affinity |
Affinity rules set verbatim on the EtcdCluster's spec.affinity, replacing the chart default. When left empty the chart applies a soft (preferred) podAntiAffinity that spreads members across nodes by kubernetes.io/hostname on a best-effort basis, so a single node failure is less likely to take out more than one member. The default is intentionally soft: a hard rule would leave a member Pending when there are fewer schedulable nodes than replicas, or when node-local storage pins a member to a node. Set a hard requiredDuringSchedulingIgnoredDuringExecution rule here to forbid co-location outright (only on clusters with enough nodes and non-node-pinned storage). Note that the operator applies affinity only when it creates or replaces a member Pod and does not reschedule running members, so on a cluster that already has co-located members the rule takes effect only as each member is replaced, not retroactively. | object |
{} |