Stakater Reloader in Cozystack#
Stakater Reloader is a Kubernetes controller that watches ConfigMaps and Secrets for changes and triggers rolling restarts of annotated workloads (Deployments, StatefulSets, DaemonSets). Cozystack uses it as the primary mechanism for reloading applications β in particular TLS-serving workloads β when cert-manager rotates a Secret.
The Critical Rule: Annotations Belong on Workload Metadata#
Reloader reads annotations on the workload object itself (metadata.annotations of the Deployment/StatefulSet/DaemonSet), not on the pod template (spec.template.metadata.annotations). Annotations placed on pod templates are silently ignored by Reloader.
Correct placement β annotate the workload object directly:
# Deployment / StatefulSet / DaemonSet
metadata:
annotations:
reloader.stakater.com/auto: "true"
# OR, for targeted secret reload:
secret.reloader.stakater.com/reload: "<secret-name>"
Incorrect placement β inside spec.template.metadata.annotations or a podAnnotations values key passed to an upstream chart renders the annotation onto the pod template, which Reloader ignores.
Annotation Variants#
| Annotation | Scope | Behaviour |
|---|---|---|
reloader.stakater.com/auto: "true" | Workload .metadata.annotations | Restarts on change to any mounted ConfigMap or Secret |
secret.reloader.stakater.com/reload: "<name>" | Workload .metadata.annotations | Restarts only when the named Secret changes |
configmap.reloader.stakater.com/reload: "<name>" | Workload .metadata.annotations | Restarts only when the named ConfigMap changes |
Correct Examples in Cozystack#
linstor-gui Deployment β uses reloader.stakater.com/auto: "true" at line 8 of packages/system/linstor-gui/templates/deployment.yaml. The annotation is on the Deployment's own metadata, which is the correct level.
LINSTOR satellite DaemonSet β because the DaemonSet is owned by the Piraeus operator, a LinstorSatelliteConfiguration resource uses a JSON Patch to inject reloader.stakater.com~1auto: "true" directly into /metadata/annotations of the DaemonSet. See satellites-reloader.yaml in packages/system/linstor/templates/.
Known Incorrect Example: qdrant#
packages/apps/qdrant/templates/qdrant.yaml passes the secret.reloader.stakater.com/reload annotation via qdrant.podAnnotations , which the upstream chart renders into the StatefulSet's pod template. Reloader never sees it, so cert-manager certificate rotation does not trigger pod restarts β qdrant silently continues serving the old certificate until the pod is restarted for some other reason.
The fix requires using whatever key the upstream qdrant chart exposes for StatefulSet-level annotations (e.g. statefulsetAnnotations), or extracting the annotation into a separate patch on the rendered StatefulSet. Existing tests at qdrant_test.yaml lines 297β338 currently assert the wrong path and must also be updated.
Related Gap: NATS Has No Reload Mechanism#
packages/apps/nats/templates/nats.yaml mounts a TLS Secret at lines 88β103 for both client-facing and cluster TLS β but carries no secret.reloader.stakater.com/reload annotation at any level. Certificate rotation by cert-manager will not restart NATS pods.
TLS Rotation and Broader Context#
The same class of issue exists for kubeovn-webhook, which loads its TLS certificate once at startup with no in-process reload or Reloader annotation. When cert-manager renews the secret, the webhook continues serving the expired cert until the pod restarts, eventually blocking all pod creation in tenant namespaces with failurePolicy: Fail.
For workloads that cannot tolerate rolling restarts on renewal, the preferred fix is in-process certificate reload (e.g. a tls.Config.GetCertificate callback or fsnotify watcher). Reloader is a valid stopgap but introduces brief downtime on each cert rotation.
Checklist for Adding Reloader Support to a New Package#
- Confirm the workload is a Deployment, StatefulSet, or DaemonSet (Reloader supports all three).
- Add the annotation to
.metadata.annotationson the workload manifest β not insidespec.template.metadata.annotationsor an upstream chart'spodAnnotationsvalues key. - Prefer
secret.reloader.stakater.com/reload: <secret-name>(targeted) overreloader.stakater.com/auto: "true"(broad) when only a specific secret needs to trigger restarts. - For operator-managed workloads (e.g. Piraeus), use a resource patch to inject the annotation at the workload level, as done in satellites-reloader.yaml.
- Add or update unit tests to assert the annotation appears in the workload's
metadata.annotations, not in the pod template.