29.6 ArgoCD Image Updater: Automating Image Tag Updates
Right, so you’ve got ArgoCD happily syncing your main branch to production. It feels good, doesn’t it? You push a git commit, ArgoCD notices, and bam—your cluster matches your manifest. It’s declarative nirvana. But then you have a sobering thought: “Wait, my deployment YAML has a container image tag pinned to v1.2.3. When I build a new image, v1.2.4, I still have to manually edit a git commit and push it to update that tag.” You’re right. That is a buzzkill. You’ve automated the what and where but not the which version. This is where the ArgoCD Image Updater comes in—to automate that last, tedious, and hilariously error-prone manual step.
Think of it as a separate robot that sits next to ArgoCD. ArgoCD’s job is to make the cluster look like git. The Image Updater’s job is to make git look like the available container images. It constantly checks your container registry (like Docker Hub, ECR, GCR) for new tags that match a policy you define. When it finds one, it commits and pushes the updated manifest back to your git repo. ArgoCD then sees that change and deploys it. It’s a beautiful, closed-loop system of robots talking to each other, leaving you free to do more important things, like argue about tabs vs. spaces.
How It Actually Works: The Mechanics
It’s not magic, it’s just a clever Kubernetes controller. You don’t install it by default with ArgoCD, which is a bit of a shame, but you can add it easily with Helm. Once it’s running, it does two main things:
- Registry Scanning: It polls your container registry based on the parameters you set. It doesn’t have psychic powers; it uses the registry’s API. This is why configuring credentials correctly is non-negotiable.
- Git Writing: When it finds a new tag it likes, it uses a Git Write Backend to make the change. You have two choices here: directly committing to your git repo (requires write credentials) or using a Pull Request workflow (highly recommended for any sane human being).
Here’s the Helm install. Don’t just copy-paste this; look at the values you need to change, especially the config.credentials.
helm repo add argo https://argoproj.github.io/argo-helm
helm install argocd-image-updater argo/argocd-image-updater \
--namespace argocd \
--set config.credentials.\"docker.io\".username=your_username \
--set config.credentials.\"docker.io\".password=your_password_or_token \
--set config.credentials.\"docker.io\".email=your_email \
--set logLevel=debug
Configuring an Application for Automation
You don’t configure the Image Updater itself for each app; you annotate the ArgoCD Application resource. This is brilliant because it keeps the automation policy right next to the app definition. The key annotations tell the updater which images to track and how to update them.
Let’s say you have an app called my-api and you want to track the my-org/api image. You want to update to the latest patch version of the 1.x series. Here’s how you’d annotate the Application:
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: my-api
annotations:
# Tell the updater which image(s) to consider
argocd-image-updater.argoproj.io/image-list: api=my-org/api
# Define the update strategy for the 'api' image alias
argocd-image-updater.argoproj.io/api.update-strategy: latest
# Constrain to the 1.x semver range
argocd-image-updater.argoproj.io/api.allow-tags: regexp:^1.*
# How often to check (default is 2m)
argocd-image-updater.argoproj.io/api.pull-secret: pullsecret:argocd/image-updater/my-registry-creds
spec:
destination:
namespace: default
server: https://kubernetes.default.svc
source:
path: applications/my-api
repoURL: git@github.com:my-org/gitops-repo.git
targetRevision: main
project: default
Notice the pull-secret annotation. This is the correct way to handle registry credentials. Don’t put them in the global config for everything; create a Kubernetes Secret in the same namespace as the Image Updater and reference it per-image. This is a best practice you’ll thank me for later.
apiVersion: v1
kind: Secret
metadata:
name: my-registry-creds
namespace: argocd
type: kubernetes.io/dockerconfigjson
data:
.dockerconfigjson: <base64-encoded-docker-config-json>
Update Strategies: Beyond “Latest”
Saying “use the latest tag” is a fantastic way to get fired at 3 AM. The Image Updater’s real power is in its tag selection policies.
semver: This is what you actually want. You can use constraints like>=1.0.0,<2.0.0to stick to a major version.latest: Picks the tag with the most recent build date. Surprisingly useful formainordevbranch builds.name: Picks the last tag alphabetically. Weird, but sometimes necessary.
The allow-tags and ignore-tags fields are your filters. Use regex to be precise. To only allow stable semver tags and ignore -alpha or -dev suffixes:
argocd-image-updater.argoproj.io/api.update-strategy: semver
argocd-image-updater.argoproj.io/api.allow-tags: regexp:^[0-9]+\.[0-9]+\.[0-9]+$
argocd-image-updater.argoproj.io/api.ignore-tags: regexp:^.*-(alpha|dev).*$
The Git Write Backend: PRs vs. Direct Commits
This is the decision point. Direct commits are simpler but terrifying. You’re giving a robot write access to your main branch. If its tag policy is wrong, it will happily deploy broken code directly to production.
The PR workflow is the safety net. The updater opens a PR with the image tag change. This triggers your CI pipeline, runs tests against the new image, and requires a human (or a trusted bot) to merge it. It adds a step, but it’s a step that prevents catastrophe.
# To force the use of Pull Requests
argocd-image-updater.argoproj.io/git-write-backend: gitlab
# or 'github' for GitHub
Common Pitfalls and “Oh, Right” Moments
- Credentials, Credentials, Credentials: 90% of problems are here. The updater needs read access to your registry and write access to your git repo. For git, use SSH keys. For registries, use short-lived tokens, not passwords. Test them manually first.
- Rate Limiting: If you’re using a public registry like Docker Hub, the updater will get rate-limited into oblivion. You must configure a cache (
redis) for any serious use. - It’s Not a CDN: The poll interval is not instantaneous. By default, it checks every 2 minutes. If you need sub-second deployment from build finish, this isn’t your tool. You need to hook your CI pipeline directly into ArgoCD.
- Annotation Typos: The annotations are long and easy to mistype. A typo means silence. The updater’s logs (
kubectl logs -l app=argocd-image-updater -n argocd) are your first and best debug tool.
The Image Updater isn’t for every application. Your core database probably shouldn’t auto-update. But for stateless, well-tested microservices where you want to eliminate the toil of cutting a new release PR for every patch, it’s an absolute game-changer. It completes the GitOps loop, finally making it feel truly automated.