In a Flux ImageUpdateAutomation, how does the controller know which lines of a YAML manifest to rewrite when a new image tag is selected?
answer
- the manifest opts in, not the controller
- an inline YAML comment on the value line
- names a policy as namespace:name
- selectors split name from tag
- no marker means a silent no-op
basics
~20 sYou mark the target lines yourself. Flux's Setters strategy only rewrites a YAML value carrying an inline comment that names an ImagePolicy, such as # {"$imagepolicy": "flux-system:app"}. Unmarked files under the update path are left untouched.
solid answer
~50 sFlux does not guess. With `spec.update.strategy: Setters`, image-automation-controller walks every YAML file under `spec.update.path` and only changes values that carry a setter marker — an inline comment of the form `# {"$imagepolicy": "<namespace>:<policy-name>"}` on the same line as the value. The bare form replaces the whole image reference including the tag. Adding a field selector, `"...:tag"` or `"...:name"`, sets only that part, which is what you need in a `kustomization.yaml` `images:` block where `newName` and `newTag` are separate keys. Two consequences matter in practice: a manifest with no marker is silently skipped, so the automation runs green and commits nothing; and the marker must live in a file that is actually committed to the repository, so output generated at apply time — Helm chart templates rendered by helm-controller, for instance — cannot be marked. Scoping `spec.update.path` to one cluster directory is how you keep automation out of production.
code
yaml · 17 linesapiVersion: apps/v1
kind: Deployment
metadata:
name: app
spec:
replicas: 2
selector:
matchLabels:
app: app
template:
metadata:
labels:
app: app
spec:
containers:
- name: app
image: ghcr.io/org/app:1.2.3 # {"$imagepolicy": "flux-system:app"}go deeper
Know that the manifest must opt in with an inline comment naming an ImagePolicy, and that Flux will not find image references on its own. Be able to point at the marker in an example and read it.
Explain the :name and :tag selectors and when a split marker is required, and describe how spec.update.path bounds which files an automation may rewrite.
Diagnose the silent no-op: a healthy policy, a green automation, and no commit. Walk the marker, its namespace-qualified policy name, the update path, and whether the value exists in a committed file at all.
Decide the repository conventions that keep this maintainable at scale — where marked values live, one automation per cluster directory, and how review catches a marker accidentally deleted during a refactor.
## Why the controller needs to be told A repository full of Kubernetes YAML contains many strings that look like image references — sidecars, init containers, chart values, comments, documentation. An automation that rewrote all of them would be dangerous, and one that guessed which to rewrite would be unpredictable. Flux therefore requires an explicit, per-value opt-in written into the manifest itself. That marker is the entire contract between your repository and the automation. ## The marker A setter marker is a YAML comment placed on the same line as the value it governs: ```yaml spec: template: spec: containers: - name: app image: ghcr.io/org/app:1.2.3 # {"$imagepolicy": "flux-system:app"} ``` The comment body is a small JSON object whose `$imagepolicy` key names an ImagePolicy as `namespace:name`. When that policy's selected image changes, the controller rewrites the value on that line to the policy's current selection — here the full `repository:tag` reference. Because it is a YAML comment, three things follow immediately. The marker survives normal editing and diffs cleanly in review. It cannot be used in a JSON manifest, which has no comments. And it is invisible to Kubernetes itself, which ignores comments entirely. ## Field selectors for split fields Sometimes the repository name and the tag live in different keys. The canonical case is Kustomize's image transformer: ```yaml apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization images: - name: ghcr.io/org/app newName: ghcr.io/org/app # {"$imagepolicy": "flux-system:app:name"} newTag: 1.2.3 # {"$imagepolicy": "flux-system:app:tag"} ``` Appending `:name` or `:tag` to the policy reference tells the controller to write only that component. The same trick handles a Helm values file that keeps `repository:` and `tag:` as separate keys — mark each with the matching selector. ## Path scoping `spec.update.path` bounds the walk. This is a real safety control, not just an optimisation: pointing one ImageUpdateAutomation at `./clusters/staging` means production manifests are never even read by that automation, no matter what markers they contain. A common layout is one automation per cluster directory, each with its own policies, so staging can track every build while production tracks a narrow semver range. ## The failure everyone hits once `Setters` is the strategy, and a file with no marker is not an error. It is simply not a candidate. So the classic symptom is: the ImagePolicy status shows the new image, the ImageUpdateAutomation reconciles successfully every interval, and no commit ever appears. Nothing is red. The cause is almost always one of: - the marker is missing, or was lost when someone reformatted the file; - the marker names the wrong namespace, or a policy name that does not exist — the reference is `namespace:name`, and the namespace is not inferred for you; - the file lies outside `spec.update.path`; - the value being marked is not in the repository at all, because it is generated later. That last point deserves emphasis. Automation edits **files in Git**. If your image tag only appears in output produced at apply time — a chart template rendered by helm-controller, a value injected by a post-build substitution — there is no line in the repository to mark. The fix is to move the tag into a committed file, typically a values file in your repo referenced by the HelmRelease, or the HelmRelease's own inline `spec.values`, and mark it there. ## What the commit looks like When at least one file changes, the controller stages the changes and commits with the identity under `spec.git.commit.author` and the text from `messageTemplate`, then pushes. If nothing changed, there is deliberately no empty commit — which is why a healthy, correctly configured automation is quiet for days at a time and that quiet is not evidence of a problem. ## Verifying without waiting The cheapest check is to grep the repository for `$imagepolicy` and confirm each hit names a policy that `flux get image policy` actually lists, in the namespace spelled in the marker. The second cheapest is to force a run rather than wait for the interval, and read the automation's status message, which reports the commit it pushed or that there was nothing to update.
- Your image tag only exists inside a Helm chart's own templates. How do you make it updatable?You cannot mark a rendered template — automation edits files in your Git repository, and chart templates are rendered later by helm-controller. Move the tag into something committed: a values file in your repo, or the HelmRelease's inline `spec.values`, with the marker on the `tag:` key using the `:tag` selector. Then the automation has a real line to rewrite.
- Why would you run several ImageUpdateAutomation objects in one repository instead of one?To scope writes by path. Each automation walks only its own `spec.update.path`, so a staging automation pointed at `./clusters/staging` physically cannot rewrite production manifests, and each can run on its own interval with its own policies. It also isolates failure: a broken staging automation does not stall production updates.
- Can a setter marker be used in a JSON manifest?No. The marker is a YAML comment, and JSON has no comment syntax, so there is nowhere to attach it. Keep manifests that image automation must edit in YAML. This is rarely a constraint in practice, since Kubernetes manifests, Kustomize files and Helm values are conventionally YAML anyway.
saying these in an interview costs you the question
- Believes Flux finds image references automatically
- Thinks a missing marker produces a visible error
- Puts the marker on the line above the value
- Omits the namespace from the policy reference
- Tries to mark a Helm template rendered at apply time