Use Reloader with Flux#
Reloader and Flux can conflict when Reloader patches a workload and Flux's reconciliation loop reverts the change. This guide explains why this happens and how to configure both tools to work together reliably.
The Problem#
Reloader's default reload strategy (env-vars) injects an environment variable into the pod template when a ConfigMap or Secret changes:
# What Reloader injects into the live Deployment
spec:
template:
spec:
containers:
- env:
- name: STAKATER_DATABASE_SECRET
value: "a3f1c9b2..." # SHA1 hash of the secret data
This change is not in Git. When Flux reconciles on its next cycle, it compares the live cluster state against Git and reverts the env var — undoing Reloader's restart trigger:
Applied revision: main/abc1234
Deployment/my-app configured ← Flux just reverted Reloader's patch
The pod never picks up the rotated secret because the rolling restart is cancelled before it completes.
The Solution#
Switch Reloader to the annotations reload strategy. Flux v2 uses Kubernetes server-side apply (SSA), which tracks field ownership per manager. When Reloader writes the annotation using its own field manager, Flux does not own that field and will not remove it during reconciliation.
No additional Flux configuration is needed for this to work.
Step 1 — Switch Reloader to the annotations strategy#
Update your Reloader Helm values:
reloader:
reloadStrategy: annotations
If you manage Reloader with Flux, update the HelmRelease:
apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
name: reloader
namespace: reloader
spec:
chart:
spec:
chart: reloader
sourceRef:
kind: HelmRepository
name: stakater
values:
reloader:
reloadStrategy: annotations
With this strategy, Reloader adds reloader.stakater.com/last-reloaded-from to the pod template metadata instead of injecting an env var:
spec:
template:
metadata:
annotations:
reloader.stakater.com/last-reloaded-from: "database-secret"
Because this annotation is not in the Git manifest, Flux does not claim ownership of it via SSA. Reloader owns it, and Flux leaves it alone.
Step 2 — Annotate your workload#
Add the Reloader annotation to the Deployment in Git as normal:
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
annotations:
reloader.stakater.com/auto: "true"
spec:
...
Commit and push. Flux syncs it. Reloader watches it.
Step 3 — Verify it works#
Trigger a reload#
Update the Secret or ConfigMap that the workload references, then wait for the change to propagate.
Check Flux is not reverting the annotation#
Watch Flux's reconciliation output:
flux get kustomizations --watch
After a Reloader-triggered restart, the Kustomization should remain Ready and Applied with no further changes on the next reconcile.
Check Reloader's logs#
kubectl logs -n reloader -l app=reloader --tail=20
You should see:
Changes detected in 'database-secret' of type 'SECRET' in namespace: production
Updated 'my-app' of type 'Deployment' in namespace: production
Check pod age#
kubectl get pods -n production -l app=my-app
Pods should be recently restarted after a secret rotation, and Flux should not re-apply and revert them.
If you cannot use Flux v2 SSA#
If you are on an older Flux setup that uses client-side apply instead of SSA, the annotation will still be reverted. In that case, you can tell Flux to ignore specific fields using a Kustomize patch in your Kustomization.
Add a strategic merge patch that pre-declares the annotation with a placeholder value. Flux will then manage the field and Reloader can update it between reconciliations:
# kustomization.yaml (applied by Flux)
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- deployment.yaml
patches:
- patch: |
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
spec:
template:
metadata:
annotations:
reloader.stakater.com/last-reloaded-from: ""
target:
kind: Deployment
name: my-app
This approach has a tradeoff: Flux will reset the annotation to "" on every reconciliation, and Reloader will re-set it on the next reload. The pods will still restart correctly because the annotation value changing from "" to the secret name counts as a pod template diff.
For most teams, upgrading to Flux v2 with SSA is the cleaner path.
How SSA field ownership works#
For context, Kubernetes server-side apply tracks which manager last wrote each field. When Flux applies a Deployment manifest using SSA:
- Fields declared in the manifest are owned by
flux-kustomize-controller - Fields not declared in the manifest are not claimed by Flux
- Reloader patches the pod template annotation using a
PatchAPI call, claiming ownership of that field
On the next Flux reconciliation, Flux re-applies the manifest. Since Flux does not own reloader.stakater.com/last-reloaded-from (it was never in the Git manifest), SSA does not remove it.
This is why the annotations strategy works with Flux v2 without any additional configuration — and why the env-vars strategy is problematic: environment variable list entries are more likely to conflict with fields Flux does own.
Summary#
| Step | What to do |
|---|---|
| Reloader | Set reloadStrategy: annotations |
Flux HelmRelease |
Set values.reloader.reloadStrategy: annotations |
| Workload | Annotate with reloader.stakater.com/auto: "true" as normal |
| Flux v1 / no SSA | Add a Kustomize patch to pre-declare the annotation field |