Image Update Automation

How Flux closes the loop from container registry back to Git: image-reflector-controller scans tags, image-automation-controller commits the winning tag into your manifests, and the cluster converges from that commit.

Overview

The gap between CI and Git

Continuous delivery has a gap that plain GitOps does not close. CI builds an image and pushes it to a registry, and then somebody has to change a tag in Git so the cluster picks it up. Teams paper over this with a CI step that runs sed on a YAML file and pushes a commit with a bot token.

That works until the token leaks, the regex eats the wrong line, or two pipelines race each other on the same branch. Flux image update automation is the supported version of that step, run by controllers inside the cluster rather than by a script in a pipeline.

> [!IMPORTANT] Automation ends at git push. The image controllers never apply anything to the cluster.

Two controllers, three resources

Both controllers are not installed by default. Add them at bootstrap with --components-extra, or by editing gotk-components in the flux-system directory.

  • image-reflector-controller — ImageRepository — Read-only registry client; polls a repository on an interval and caches the tag list
  • image-reflector-controller — ImagePolicy — Applies a filter and an ordering to the cached list and publishes exactly one winning tag
  • image-automation-controller — ImageUpdateAutomation — The only Flux resource that pushes to Git; clones, rewrites marked values, commits and pushes

Why ending at git push matters

The new image reaches the cluster only because source-controller notices the new commit and kustomize-controller or helm-controller reconciles it. That is the same path a human commit takes.

  • Audit trail — Every image version in production has a commit with a diff, an author and a timestamp
  • Rollback — A git revert, not a kubectl edit
  • Drift — Cluster and repository never diverge

Setter markers

A setter marker is a YAML line comment holding a small JSON object that names the ImagePolicy. It connects a policy to a manifest field. It is easy to describe, easy to get subtly wrong, and the thing an interviewer is most likely to ask you to write on a whiteboard.

> [!TIP] The update is a structured kyaml edit, not a text replacement, so surrounding comments and formatting survive.

Scope: how far to automate

Full end-to-end automation into production is a genuine risk. An image that passes CI can still be wrong, and a controller that pushes straight to the deployed branch removes the last human gate.

  • Dev, staging — Build-metadata tags, push to the deployed branch — None
  • Production — Narrow semver patch range — None, but only patches move
  • Production — Push to a separate branch — Pull request review

> [!WARNING] Interviewers probe for whether you reach for the dev-versus-production distinction unprompted.

Key concepts

ImageRepository
image.toolkit.fluxcd.io/v1. A registry scanner. Requires spec.image (address without scheme) and spec.interval. Optional spec.secretRef for a docker-registry secret, spec.serviceAccountName, spec.certSecretRef for mTLS, spec.provider (generic, aws, azure, gcp) for cloud keyless auth, and spec.exclusionList of regexes. Publishes the tag list to status.lastScanResult. Never writes anything.
ImagePolicy
image.toolkit.fluxcd.io/v1. Selects one tag from a scanned repository via spec.imageRepositoryRef. Exactly one of three ordering policies: semver with a range, alphabetical with order asc or desc, numerical with order asc or desc. Result lands in status.latestRef.tag. spec.digestReflectionPolicy (Never, Always, IfNotPresent) controls whether the digest is resolved and pinned as well.
filterTags
The pre-processing step on an ImagePolicy. spec.filterTags.pattern is a regex applied to every scanned tag; tags that do not match are discarded. spec.filterTags.extract names a capture group whose value replaces the tag for ordering purposes. This is how a build tag such as main-1a2b3c4-1699887766 gets ordered by its trailing timestamp rather than by the commit SHA in the middle.
ImageUpdateAutomation
image.toolkit.fluxcd.io/v1. The write side. spec.sourceRef points at a GitRepository. spec.git.checkout.ref.branch selects what to read, spec.git.push.branch selects where to write, spec.git.commit sets author and messageTemplate, spec.update.path scopes the directory scanned, spec.update.strategy is Setters. Optional spec.policySelector restricts which ImagePolicy objects this automation acts on.
Setter marker
The YAML line comment that binds a manifest field to a policy. Two-field form, comment slash JSON with $imagepolicy set to namespace:policy-name, replaces the whole image reference. Three-field form appends name, tag, or digest and replaces only that component. The namespace is the ImagePolicy namespace, not the workload namespace.
Setters strategy
The only update strategy. Implemented on kyaml, so the edit is a structured YAML node replacement rather than a line-based text substitution. Comments, key ordering, anchors, and indentation are preserved, which keeps the automated commit diff small and reviewable.
push.refspec
An alternative to spec.git.push.branch for flows that need a raw Git refspec, such as pushing to a Gerrit magic ref or to a differently named remote ref for every run. Set alongside or instead of branch when a plain branch push does not express the target.
messageTemplate
A Go text/template with Sprig functions that renders the commit message. Exposes .AutomationObject, .Changed (with Changes and Objects helpers exposing OldValue and NewValue), and .Values from spec.git.commit.messageTemplateValues. Used to write meaningful commit subjects and to add trailers such as skip-ci markers.

When to use it

  • Dev and staging environments where every green build should land in the cluster without a human editing a tag
  • Replacing a CI step that runs sed and git push against the GitOps repo with a bot token — the controller does it with in-cluster credentials and a structured YAML edit
  • Consuming third-party images that publish clean semver tags, where you want automatic patch upgrades but never minor or major
  • Any environment where you need a commit-level audit trail of which image version was running when, without instrumenting CI to produce it
  • Production, but only through a separate push branch that opens a pull request for human approval

Interview questions

  • Walk me through everything that happens between CI pushing an image and the new version running in the cluster, with Flux image automation enabled.
  • Explain the setter marker comment precisely. What are the forms, and what does the namespace refer to?
  • Write an ImagePolicy for tags of the form main-1a2b3c4-1699887766. Why can you not just use semver or plain alphabetical ordering?
  • Why does Flux write the new tag back to Git rather than patching the Deployment directly? How does that compare to argocd-image-updater?
  • How would you set this up safely for production?

Sign up free to read the full topic

More DevOps topics

Start free on Cariara · Coding problems · System design studio