## What this PR does Exposes standard Helm `resources` values for the three core workloads in the `cozystack-engine` package, and makes `cozystack-controller` replicas configurable (was hardcoded to `1`). **Changes by component:** | Component | `resources` | `replicas` | |---|---|---| | `cozystack-api` | ✅ NEW (`cozystackAPI.resources`) | already configurable | | `cozystack-controller` | ✅ NEW (`cozystackController.resources`) | ✅ NEW (`cozystackController.replicas`, default `1`) | | `lineage-controller-webhook` | ✅ NEW (`lineageControllerWebhook.resources`) | already configurable | Each template uses `{{- with .Values.xxx.resources }}` so the `resources:` block is only rendered when values are provided. Default `resources: {}` produces no output, so resource requests/limits stay opt-in. **Leader election:** `cozystack-controller` now always runs with leader election — the chart passes `--leader-elect` unconditionally and ships a namespaced `Role`/`RoleBinding` for the Lease in `cozy-system` (where controller-runtime creates it). Raising `cozystackController.replicas` therefore adds standbys instead of a second active writer over the reconcilers that patch HelmReleases, Gateways, Certificates, ResourceQuotas and Secrets; this holds whatever `replicas` is. A restart can pause reconciliation for up to the Lease duration (15s by default), because `LeaderElectionReleaseOnCancel` is off. With `replicas: 1` the change for an existing install is the flag plus the two RBAC objects. **Why:** Without these values, operators cannot set QoS guarantees and must resort to `kubectl patch`, Flux Kustomize SSA patches, or Kyverno mutations — all fragile under Helm upgrades. Closes #2955 ### Release note ```release-note feat(api): add configurable `resources` (requests/limits) for cozystack-api, cozystack-controller, and lineage-controller-webhook. `cozystack-controller` replicas is now configurable via `cozystackController.replicas` (default: 1). The `cozystack-controller` Deployment now always runs with leader election and creates a Lease in `cozy-system`, so raising `replicas` adds standbys rather than a second active controller; a restart can pause reconciliation for up to the Lease duration (15s by default). An empty `resources: {}` renders no resources block, so requests and limits remain opt-in. ``` <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Container resource requests and limits can now be configured for the API, controller, and webhook services; defaults remain unchanged. * The controller replica count is configurable, and leader election is enabled for multi-replica operation. * Controller leader-election access is limited to the `cozy-system` namespace. * **Documentation** * Documented the webhook resource configuration option. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
lineage-controller-webhook
Cozystack system package for the lineage controller webhook — a mutating
admission webhook that stamps "lineage" labels onto tenant workloads, linking
each resource back to the Cozystack Application that ultimately owns it.
The webhook intercepts CREATE and UPDATE on pods, secrets, services,
persistentvolumeclaims, ingresses.networking.k8s.io, and
workloadmonitors.cozystack.io outside system namespaces. For each request it
walks the ownership graph upward (Kubernetes ownerReferences, then the
HelmRelease Flux installed the resource with, then the Cozystack
Application-derived CRD that produced the HelmRelease) and writes the
discovered application's group, kind and name as labels
(apps.cozystack.io/application.{group,kind,name}) on the incoming object.
Those labels let the aggregated API server, the Cozystack dashboard, and other
lineage-aware consumers reason about which application a resource belongs to.
The webhook serves TLS on port 9443 with a cert-manager issued certificate, and
runs with failurePolicy: Fail — every CREATE/UPDATE on the resources above
is gated on the webhook being reachable.
Topology
The chart ships a single shape, modelled on cozystack-api:
- Deployment with two replicas (override via
replicas). - Soft
nodeAffinitypreferringnode-role.kubernetes.io/control-plane(Exists, so it matches both Talos's empty value and k3s/kubeadm's"true"). Soft means: the pod lands on a control-plane node when one is reachable, and on any worker otherwise — no override needed for managed Kubernetes, Cozy-in-Cozy tenants, or any other cluster where control-plane nodes aren't visible. - Permissive
tolerations([{operator: Exists}]) so the pod can land on tainted control-plane nodes when the soft affinity is satisfiable. - Soft
podAntiAffinityonkubernetes.io/hostnameso replicas spread across nodes when possible (best-effort). PodDisruptionBudgetwithmaxUnavailable: 1, unconditional. Atreplicas: 1it's a useful no-op (allows full drain); atreplicas >= 2it caps disruption to one pod.Servicewithspec.trafficDistribution: PreferCloseso the apiserver prefers a webhook endpoint on its own node when one exists, and transparently falls over to a remote endpoint otherwise. Requires Kubernetes ≥ 1.31; on older clusters the field is silently ignored and traffic uses default cluster-wide distribution.
Parameters
All keys live under the top-level lineageControllerWebhook: map.
| Name | Description | Value |
|---|---|---|
image |
Container image (digest-pinned) | ghcr.io/cozystack/cozystack/lineage-controller-webhook:v1.3.0@sha256:e898…6fb0 |
debug |
Enable --zap-log-level=debug instead of info |
false |
replicas |
Deployment replica count | 2 |
resources |
Container requests/limits; {} renders no key |
{} |
localK8sAPIEndpoint.enabled |
Deprecated. See note below. | false |
localK8sAPIEndpoint.enabled (deprecated)
When enabled, this injects KUBERNETES_SERVICE_HOST=status.hostIP and
KUBERNETES_SERVICE_PORT=6443 so the webhook talks to the kube-apiserver on
its own node. It was originally added to avoid latency on the
webhook-to-apiserver path, but it is only valid when the pod is actually
scheduled on an apiserver-bearing node — which the chart's soft control-plane
affinity no longer guarantees. With this flag enabled and the pod scheduled
off a control-plane node, the controller will crash-loop dialing a non-
apiserver hostIP. Slated for removal once the latency motivation is addressed
in the webhook itself; leave disabled.