ADR-015: Flux Image Automation¶
Status¶
Accepted (implemented — ImageRepository, ImagePolicy, and ImageUpdateAutomation active for homekube-docs)
Date¶
2026-03-21
Context¶
The current GitOps loop is manual for container image updates: when a new image tag is available, the engineer must edit a deployment manifest, commit, and push. Flux's Image Automation components close this loop by:
- Polling a container registry for new tags (
image-reflector-controller) - Matching tags against a policy (semver range, regex, etc.) (
image-reflector-controller) - Committing an updated image tag back to Git (
image-automation-controller) - Flux then reconciles the updated manifest into the cluster in the normal way
The standard Flux bootstrap installed four controllers: source-controller, kustomize-controller, helm-controller, and notification-controller. The two image controllers are separate optional components and were not included in the initial bootstrap.
Decision¶
Install the image controllers by re-running flux bootstrap with --components-extra:
flux bootstrap github \
--owner=MarcSpeckmann \
--repository=HomeKube \
--branch=main \
--path=clusters/local \
--personal \
--components-extra=image-reflector-controller,image-automation-controller
This updates clusters/local/flux-system/gotk-components.yaml (the DO NOT EDIT bootstrap file) to add the two controller Deployments.
Scaffold the image-automation/ directory with an empty Kustomization so the Flux Kustomization object (clusters/local/image-automation.yaml) reconciles cleanly now and is ready for resources when the first workload is deployed.
Defer ImageRepository, ImagePolicy, and ImageUpdateAutomation resources until a workload with a tracked image is deployed.
Branch strategy for future automation¶
When image automation resources are added, the ImageUpdateAutomation will push tag updates to a dedicated branch:
spec:
git:
push:
branch: flux/image-updates
commit:
author:
name: Flux Image Automation
email: flux@homekube.local
This means automated tag bumps never land directly on main — they arrive as a branch that can be reviewed and merged. Appropriate for a GitOps repo where main is the production source of truth.
Marker comment format (for future use)¶
Deployment manifests must carry a policy marker comment for the automation to update them:
containers:
- name: podinfo
image: ghcr.io/stefanprodan/podinfo:5.0.3 # {"$imagepolicy": "flux-system:podinfo"}
The ImageUpdateAutomation scans files in the configured path for these markers and replaces the tag when a new policy-matched tag is found.
Alternatives Considered¶
| Option | Reason Not Chosen |
|---|---|
| Manual image tag updates | Error-prone and breaks the GitOps automation principle |
| GitHub Actions image update workflow | Works but requires a PAT with repo write scope and is not driven by registry events; also duplicates what Flux already supports natively |
| Renovate Bot | Good for dependency PRs but not registry-event-driven; would complement but not replace Flux Image Automation |
| Skip image automation entirely | Defeats the purpose of a full CNCF learning sandbox |
Consequences¶
Positive¶
- Closes the GitOps loop — no manual image tag editing
flux/image-updatesbranch gives a review gate before changes land onmain- Image controllers are lightweight and add minimal resource overhead
- Pattern is directly transferable to production Flux setups
Negative¶
- Two additional controllers running in
flux-systemnamespace (~50 MB memory combined) gotk-components.yamlmust be regenerated viaflux bootstrap(cannot be hand-edited)- The
flux/image-updatesbranch must be merged manually — automation is not fully hands-off - Requires a container registry accessible from the cluster (ghcr.io works from minikube)
Future Resources (add to image-automation/ when deploying an app)¶
# image-automation/<app>-imagerepository.yaml
apiVersion: image.toolkit.fluxcd.io/v1beta2
kind: ImageRepository
metadata:
name: <app>
namespace: flux-system
spec:
image: ghcr.io/<owner>/<app>
interval: 5m
---
# image-automation/<app>-imagepolicy.yaml
apiVersion: image.toolkit.fluxcd.io/v1beta2
kind: ImagePolicy
metadata:
name: <app>
namespace: flux-system
spec:
imageRepositoryRef:
name: <app>
policy:
semver:
range: ">=1.0.0"
---
# image-automation/automation.yaml
apiVersion: image.toolkit.fluxcd.io/v1beta2
kind: ImageUpdateAutomation
metadata:
name: homekube
namespace: flux-system
spec:
interval: 5m
sourceRef:
kind: GitRepository
name: flux-system
namespace: flux-system
git:
push:
branch: flux/image-updates
commit:
author:
name: Flux Image Automation
email: flux@homekube.local
messageTemplate: "chore: update {{range .Updated.Images}}{{println .}}{{end}}"
update:
strategy: Setters
path: ./apps