Automate container image updates with ArgoCD Image Updater: semver, latest, and digest strategies, write-back to Git, and patterns from automatic dev to manual approval in production.

In episode 15 we built a Git- and tag-based promotion workflow. But there's one link still manual: who changes the image version in the manifests? CI/CD can build new images, but it still takes human hands to type v1.2.4 in a kustomization or Helm values, open a PR, and wait for review. In this episode we discuss ArgoCD Image Updater — a controller that checks registries, detects new images, and updates manifests automatically, while still respecting the GitOps flow.
Why does this matter? GitOps doesn't mean "everything must be manual". Image Updater is the bridge that connects CI push to registry with ArgoCD pull from Git — a complete automatic cycle from code commit to deploy. More importantly, it can be set differently per environment: fully automatic in dev, controlled in staging, and waiting for approval in production.
Image Updater runs as a separate Deployment in the argocd namespace. The easiest installation is with Helm:
helm repo add argo https://argoproj.github.io/argo-helm
helm install argocd-image-updater -n argocd \
argocd/argocd-image-updater
kubectl rollout status deploy/argocd-image-updater -n argocdRegistry credential configuration lives in the argocd-image-updater-secret Secret, while global settings (e.g. default registries) go in the argocd-image-updater-config ConfigMap.
The controller scans all Applications every interval (default 2 minutes), looking for certain annotations. If found, it:
Because the process starts from reading annotations on the Application, no application code changes are needed — Image Updater works purely at the manifest layer.
All per-application behavior is set through annotations on the Application:
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: billing-api
namespace: argocd
annotations:
argocd-image-updater.argoproj.io/image-list: |
api=ghcr.io/devnull/billing-api
web=ghcr.io/devnull/web
argocd-image-updater.argoproj.io/api.update-strategy: semver
argocd-image-updater.argoproj.io/api.allow-tags: regexp:^v?[0-9]+\.[0-9]+\.[0-9]+$
argocd-image-updater.argoproj.io/web.update-strategy: digest
spec:
project: default
source:
repoURL: https://github.com/devnull/gitops-repo.git
path: apps/billing/overlays/prod
targetRevision: main
destination:
server: https://kubernetes.default.svc
namespace: billing-prodimage-list lists the monitored images, with an alias per image (api, web).api.update-strategy and api.allow-tags.Note
The annotation pattern is <alias>.update-strategy, <alias>.allow-tags, and so on. If you forget to add the alias to image-list, the annotations for that image will never be read — re-check the alias names when the configuration doesn't work.
Four strategies are available:
| Strategy | Tag selection | When to use |
|---|---|---|
semver | Highest semver tag (following semver rules) | Versioned releases |
latest | Most recent tag (string/date sorting) | Dev/experimental |
digest | Current image SHA digest | Reproducible pinning |
name | Tag name order (lexicographic) | Special-formatted tags |
The semver strategy is the safest choice for production: only tags satisfying allow-tags are considered, so odd tags like canary-abc never get picked.
How Image Updater writes its results back:
The most GitOps method: the controller commits to the manifest repository with a message like chore: updated billing-api image v1.2.3. That change is reviewed, audited, and rollback-able via revert — exactly the flow from episode 15. It needs commit credentials in the argocd-image-updater-secret Secret.
An alternative method: Image Updater changes the image parameter directly on the Application (equivalent to argocd app set --helm-set image.tag=v1.2.3). Simpler because it doesn't need Git access, but the change is not recorded in Git — a trade-off that reduces the GitOps audit benefit. Use it only when write-back to Git isn't possible.
annotations:
argocd-image-updater.argoproj.io/image-list: |
api=ghcr.io/devnull/billing-api
argocd-image-updater.argoproj.io/api.update-strategy: semver
argocd-image-updater.argoproj.io/api.write-back-method: git
argocd-image-updater.argoproj.io/api.git-branch: mainImage Updater's power is in the different policies per environment:
update-strategy: latest + write-back-method: argocd → every push to the registry immediately syncs dev. No review, as befits a development environment.semver with strict allow-tags, write-back to Git on the staging branch; changes show up as commits that can be lightly reviewed.Tip
The golden rule: the higher the environment, the more manual the approval. Full automation in production removes a security layer that operations teams need. Image Updater provides that flexibility — it's not a mandate to be automatic everywhere.
The ideal end-to-end flow:
This way the chain "code commit → new image → new manifest → deploy" is hands-free in lower environments, and still reviewed in higher environments.
latest) easily produce "unexpected deploys".update-strategy: digest so the deployed image is always reproducible and immune to overwritten tags.main/prod branches with required reviews; automatic commits from Image Updater must still pass CI checks.Warning
If write-back-method: git is used, Image Updater needs commit rights to the manifest repository. Make sure the account used is a limited account (e.g. a bot), and that protected branches still enforce review for dangerous changes.
latest tag in production. Hard to roll back and not reproducible. Use semver or digest.image-list must match the api.update-strategy annotation prefix exactly.This episode closed the automation loop: installing Image Updater with Helm, how the scanning controller works, the semver/latest/digest/name update strategies, the two write-back methods (Git vs ArgoCD), per-environment automation patterns from automatic dev to production with approval, CI integration, and best practices for semver, digest pinning, and branch protection.
The points you should take with you:
update-strategy: semver is the safest choice for releases.image-list annotation and aliases are the key to all configuration.Good automation must be visible — the team needs to know when a deploy succeeds, fails, or waits. In the next episode 17 we discuss Notifications & Alerts: argocd-notifications, triggers and templates, subscriptions to Slack/Teams/email/webhook, and patterns for deploy notifications, failure alerts, and audit trails. See you in episode 17!