Roll a workload when its ConfigMap changes¶
Mounting a ConfigMap as a volume does not restart the Pod. The kubelet syncs the file within a minute or so, but a process that reads its configuration once at startup never notices. Until it restarts, it runs configuration nobody can tell is stale.
Opt a workload in and the mutate-configmap-autoreload Kyverno policy rolls it
whenever the ConfigMap changes.
When you need this¶
Only when the process cannot reload by itself. Check first:
- Does it watch its own config file? Then do nothing.
- Does it expose a reload endpoint? Prefer a
configmap-reloadsidecar, asblackbox-exporterdoes — it reloads in place without dropping the Pod. - Neither? Use this.
pint and github-receiver are both the third case: they read files at startup
and have no reload endpoint.
Steps¶
Add one annotation to the Deployment or StatefulSet's own metadata, naming the ConfigMap it reads:
apiVersion: apps/v1
kind: Deployment
metadata:
annotations:
# The ConfigMap must be in the same namespace as the workload.
autoreloader.thaum.xyz/configmap: pint-config
name: pint
spec:
template:
metadata:
# The policy writes autoreloader.thaum.xyz/version in here.
That is the whole change. On every apply the policy reads that ConfigMap's
resourceVersion and stamps it into spec.template.metadata.annotations, so a
changed ConfigMap changes the Pod template, and a changed Pod template rolls the
Pods.
It goes on the workload, not the Pod template
The policy matches object.metadata.annotations and writes into
spec.template.metadata.annotations. Putting the opt-in in the Pod template
means the policy never matches — and it fails silently, because
failurePolicy: Ignore means an unmatched or erroring policy just skips.
This has already happened once, in
#1300.
Verify it¶
Before merging, ask the API server what the webhook would produce:
kubectl -n <namespace> apply --server-side \
--field-manager=kustomize-controller --dry-run=server \
-o jsonpath='{.spec.template.metadata.annotations}' \
-f path/to/deployment.yaml
You want an autoreloader.thaum.xyz/version that matches the live ConfigMap:
If the version annotation is missing, the policy did not match — check the annotation is on the workload's metadata and that the ConfigMap name is right.
After merging, the same two values should agree on the live object:
Expect two reconciles, not one¶
Flux applies the workload before it writes the updated ConfigMap, so the first reconcile stamps the version that is still current at that moment and nothing changes. The next one picks up the new value and rolls the Pods.
With a 5m Kustomization interval that is up to ten minutes between merging a ConfigMap change and seeing new Pods — measured. To skip the wait, reconcile explicitly:
# Every namespace has its own source; refresh the one beside the Kustomization.
# An app: its own Kustomization, in its own namespace. A platform component: the
# platform-<domain> Kustomization, in the platform-<domain> namespace.
flux -n <kustomization namespace> reconcile source git ankhmorpork
# Twice: the first pass stamps the pre-update version, the second picks up the new one.
flux -n <kustomization namespace> reconcile kustomization <kustomization>
flux -n <kustomization namespace> reconcile kustomization <kustomization>
Limits¶
- ConfigMaps only. Secrets would need the Kyverno admission controller to hold read on every Secret in the cluster, which it does not. See the explanation.
- One ConfigMap per workload. The annotation takes a single name.
- Deployments and StatefulSets only. DaemonSets are not matched.
- A missing ConfigMap is silent.
failurePolicy: Ignoremeans a typo in the name skips the stamp rather than blocking the apply — deliberately, so a renamed ConfigMap cannot stop deploys.