Flux Image Update Automation: auto-bump image tags in git

Published: 2026-04-12

Flux Image Update Automation watches a container registry for new image tags, matches them against a policy (semver, regex), and commits the updated tag back to git. The cluster then reconciles the change automatically — no manual image tag bumps.


Three objects

Object Purpose
ImageRepository Where to look for images (registry)
ImagePolicy Which tag to select (semver range, alphabetical, regex)
ImageUpdateAutomation When to commit updates and to which branch

ImageRepository

yamlapiVersion: image.toolkit.fluxcd.io/v1beta2
kind: ImageRepository
metadata:
  name: abot
  namespace: flux-system
spec:
  image: registry.example.com/docker/iac/prometheus/abot2
  interval: 5m
  secretRef:
    name: registry-credentials

Flux scans the registry every 5 minutes. registry-credentials is a Kubernetes Secret with a .dockerconfigjson key:

bashkubectl create secret docker-registry registry-credentials \
  --docker-server=registry.example.com \
  --docker-username=ci-reader \
  --docker-password=xxx \
  -n flux-system

ImagePolicy

Semver range (most common):

yamlapiVersion: image.toolkit.fluxcd.io/v1beta2
kind: ImagePolicy
metadata:
  name: abot
  namespace: flux-system
spec:
  imageRepositoryRef:
    name: abot
  policy:
    semver:
      range: ">=0.70.0 <1.0.0"

Selects the latest tag matching the range — v0.78 today, v0.79 after it's pushed.

Alphabetical (for non-semver registries):

yamlpolicy:
  alphabetical:
    order: desc  # "latest" in alphabetical order

Regex with timestamp extraction (CI-built images like main-1234567890-abc1234):

yamlpolicy:
  numerical:
    order: asc
  filterTags:
    pattern: "^main-(?P<ts>[0-9]+)-[a-f0-9]{7}$"
    extract: "$ts"

ImageUpdateAutomation

yamlapiVersion: image.toolkit.fluxcd.io/v1beta1
kind: ImageUpdateAutomation
metadata:
  name: flux-system
  namespace: flux-system
spec:
  interval: 10m
  sourceRef:
    kind: GitRepository
    name: flux-system
  git:
    checkout:
      ref:
        branch: master
    commit:
      author:
        email: fluxbot@example.com
        name: FluxBot
      messageTemplate: |
        chore: update image {{range .Updated.Images}}{{.}} {{end}}
    push:
      branch: master
  update:
    strategy: Setters
    path: ./fluxcd

Flux needs write access to the git repo. The flux-system GitRepository SSH key must have push permission. Add its public key as a deploy key with write access in GitLab/GitHub.

Get Flux's public key:

bashkubectl get secret flux-system -n flux-system -o jsonpath='{.data.identity\.pub}' | base64 -d

Marker annotation in HelmRelease

For Flux to know which field to update, annotate the image tag in the HelmRelease values:

yamlspec:
  values:
    image:
      repository: registry.example.com/docker/iac/prometheus/abot2
      tag: v0.78  # {"$imagepolicy": "flux-system:abot:tag"}

The comment {"$imagepolicy": "flux-system:abot:tag"} is the marker. When Flux finds a newer matching tag, it replaces v0.78 in-place, preserving the rest of the file.

Full image reference (repo + tag):

yamlimage: registry.example.com/docker/iac/prometheus/abot2:v0.78  # {"$imagepolicy": "flux-system:abot"}

Verifying automation

bash# Check scan status and last scan time
flux get imagerepositories -A

# Check which tag is currently selected by each policy
flux get imagepolicies -A

# Check last automation commit
flux get imageupdateautomations -A

A successful automation shows as Applied revision: master/abc1234 — the SHA of the commit Flux made to the repo.

Force a scan immediately:

bashflux reconcile imagerepository abot -n flux-system

GitLab pipeline trigger

If your GitLab CI runs on push to master, automation commits will trigger a new pipeline. This is usually desired — the pipeline validates and deploys the new image. If not, add [skip ci] to the commit message template:

yamlmessageTemplate: |
  chore: update image {{range .Updated.Images}}{{.}} {{end}} [skip ci]

Safety considerations

  • Use a semver range instead of :latest to prevent accidental major-version bumps
  • Branch protection on master + bypass list for the FluxBot deploy key
  • Automation commits appear in git log with chore: update image and are revertable normally
  • Use ImagePolicy with filterTags.pattern to only track images from a specific branch (e.g., main-* not feature-*)

What can go wrong

ImageUpdateAutomation commits but Flux doesn't reconcile. The automation commits to the git repo, but if the GitRepository source has a polling interval of 10 minutes, it takes up to 10 minutes to pick up the commit. Add a postBuild hook or reduce interval on the GitRepository.

Policy matches too broadly and bumps pre-release versions. A semver range >=1.0.0 will match 1.0.0-rc.1. Use semver: {range: ">=1.0.0 <2.0.0"} with a filterTags.pattern to exclude release candidates: ^[0-9]+\.[0-9]+\.[0-9]+$.

Automation creates commits but the deploy key has no write access. The FluxCD deploy key needs write access to the git repository, not just read. Verify in the repo's Settings → Deploy keys.


Summary

  • ImagePolicy + ImageRepository + ImageUpdateAutomation form the full pipeline: scan → select → commit → reconcile
  • Automation commits the new image tag to git; Flux reconciles the change — the cluster always reflects git state
  • Use semver range in ImagePolicy to prevent accidental major-version jumps or pre-release tag adoption
  • The deploy key for automation needs write access to the git repo
  • Tag markers in the manifest (# {"$imagepolicy": "flux-system:my-app"}) tell the automation exactly which field to update