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
:latestto 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 imageand are revertable normally - Use
ImagePolicywithfilterTags.patternto only track images from a specific branch (e.g.,main-*notfeature-*)
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+ImageUpdateAutomationform 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
semverrange 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