Application configuration¶
Argo CD Image Updater uses ImageUpdater custom resources to configure which
Argo CD applications should be monitored for image updates and how those updates
should be applied.
This section explains how to configure ImageUpdater resources to manage your
Argo CD applications.
Creating an ImageUpdater custom resource¶
To configure Argo CD Image Updater, you create an ImageUpdater custom resource
that defines which applications to monitor and how to update their images.
The basic structure of an ImageUpdater resource looks like this:
apiVersion: argocd-image-updater.argoproj.io/v1alpha1
kind: ImageUpdater
metadata:
name: my-image-updater
namespace: argocd
spec:
applicationRefs:
- namePattern: "my-app-*" # Select applications matching this pattern
images:
- alias: "nginx"
imageName: "nginx:1.20"
Selecting applications¶
Applications are selected using the applicationRefs field, which supports
multiple selection criteria:
Name pattern matching¶
Use the namePattern field to select applications by name using glob patterns:
spec:
applicationRefs:
- namePattern: "frontend-*" # Matches frontend-app, frontend-web, etc.
images:
- alias: "app"
imageName: "myregistry/frontend:latest"
- namePattern: "backend" # Exact match for backend application
images:
- alias: "api"
imageName: "myregistry/backend:v1.0"
NamePattern Specificity Rules¶
When multiple namePattern rules could match the same application, the
ImageUpdater uses a specificity-based selection algorithm to choose the
most specific rule. This ensures predictable and deterministic behavior.
How Specificity Works¶
The specificity algorithm calculates a score for each namePattern based on
several factors:
- Exact matches get the highest priority
- Literal characters in the pattern add to the score
- Label selectors add significant bonus points
- Complex label selectors get additional points
Specificity Examples¶
Given an application named app-1, here's how different patterns would be
ranked:
| Pattern | Specificity Score | Reason |
|---|---|---|
app-1 |
1,000,000+ | Exact match (highest priority) |
app-prod-* |
~9 points | More literal characters than app-* |
app-* |
~4 points | Fewer literal characters |
app-? |
~4 points | Single wildcard character |
app-[1234567] |
~4 points | Character set wildcard |
Label Selector Impact¶
Label selectors significantly increase specificity:
# This pattern will be more specific than a simple name pattern
- namePattern: "app-*"
labelSelectors:
matchLabels:
environment: production
tier: frontend
images:
- alias: "nginx"
imageName: "nginx:1.20"
Complete Example¶
apiVersion: argocd-image-updater.argoproj.io/v1alpha1
kind: ImageUpdater
metadata:
name: my-image-updater
namespace: argocd
spec:
applicationRefs:
# This will be used for app-1 (most specific - exact match)
- namePattern: "app-1"
images:
- alias: "test1"
imageName: "test:1.1.0"
# This will be used for app-prod-* applications (more specific than app-*)
- namePattern: "app-prod-*"
images:
- alias: "nginx"
imageName: "nginx:1.20"
# This will be used for other app-* applications (least specific)
- namePattern: "app-*"
images:
- alias: "redis"
imageName: "redis:6.2"
Application Selection Process¶
- List all applications in the ImageUpdater CR's namespace (performed once per reconciliation)
- Sort applicationRefs by specificity (most specific first)
- For each application, find the first matching rule in the sorted list
- Stop at the first match - this ensures the most specific rule is used
Multiple ImageUpdater Resources Conflict
Important: The current implementation does not handle conflicts between
multiple ImageUpdater CRs that target the same application. If multiple CRs
have namePattern rules that match the same application, they will
continuously overwrite each other's changes, causing the application to
"thrash" between different image versions.
For example, if you have two CRs:
- CR-A with
namePattern: "app-1"andimageName: "nginx:1.20" - CR-B with
namePattern: "app-*"andimageName: "nginx:1.21"
Both CRs will try to manage app-1, causing the application to flip between
nginx:1.20 and nginx:1.21 on every reconciliation cycle.
Workaround: Ensure that each application is only targeted by one
ImageUpdater CR, or use more specific namePattern rules to avoid overlaps.
A solution for handling conflicts between multiple CRs will be implemented in future versions.
Label-based selection¶
Use labelSelectors to select applications based on their labels:
spec:
applicationRefs:
- namePattern: "*" # Match all applications
labelSelectors:
matchLabels:
app.kubernetes.io/part-of: "my-project"
matchExpressions:
- key: "environment"
operator: In
values: [ "production", "staging" ]
images:
- alias: "app"
imageName: "myregistry/myapp:stable"
Combining selection criteria¶
You can combine name patterns and label selectors for precise application selection:
spec:
applicationRefs:
- namePattern: "web-*"
labelSelectors:
matchLabels:
tier: "frontend"
images:
- alias: "webapp"
imageName: "myregistry/webapp:latest"
Reading configuration from Application annotations¶
When using ApplicationSets that template image updater configuration as annotations,
you can configure the ImageUpdater CR to read those annotations instead of
requiring explicit images configuration:
spec:
applicationRefs:
- namePattern: "*"
labelSelectors:
matchLabels:
image-updater: my-image-updater
useAnnotations: true
When useAnnotations is set to true, all CR-based configuration
is ignored (images including manifestTargets within each image, commonUpdateSettings,
writeBackConfig). Instead, the controller reads everything from the Application's
legacy argocd-image-updater.argoproj.io/* annotations. Only namePattern and
labelSelectors are used from the CR for application selection.
Required annotations¶
The following annotation is required when using useAnnotations: true:
argocd-image-updater.argoproj.io/image-list- A comma-separated list of images to update. Each image can optionally have an alias (format:alias=image:tagor justimage:tag). Example:app=myregistry/myapp:v1.0
Optional annotations¶
For a complete list of all available legacy annotations, please refer to the Migration Guide, which provides detailed examples of all annotation-based configuration options.
This allows a single ImageUpdater CR to manage multiple Applications generated by ApplicationSets, with each Application providing its own image configuration via annotations. This is particularly useful when you have hundreds of ApplicationSets generating thousands of Applications, as it avoids the need to create a separate ImageUpdater CR for each Application.
Performance Consideration
When using useAnnotations: true with namePattern: "*" and
no labelSelectors, the ImageUpdater will attempt to process all Applications
in the ImageUpdater CR's namespace. This can lead to performance issues if you have many
Applications. It is strongly recommended to use labelSelectors to limit the
scope of Applications that will be processed.
Hierarchical configuration¶
Configuration can be specified at multiple levels, with more specific levels overriding more general ones:
- Global level (
spec.commonUpdateSettings,spec.writeBackConfig) - Application level (
spec.applicationRefs[].commonUpdateSettings,spec.applicationRefs[].writeBackConfig) - Image level (
spec.applicationRefs[].images[].commonUpdateSettings)
Global configuration¶
Set defaults that apply to all applications unless overridden:
spec:
commonUpdateSettings:
updateStrategy: "semver" # Default: "semver"
forceUpdate: false # Default: false
allowTags: "regexp:^v[0-9]+\\.[0-9]+\\.[0-9]+$" # Default: all tags
ignoreTags: [ "latest", "dev" ] # Default: no tags ignored
pullSecret: "" # Default: no pull secret
platforms: [ ] # Default: no platform restrictions
writeBackConfig:
method: "argocd" # Default: "argocd"
applicationRefs:
- namePattern: "*"
images:
- alias: "app"
imageName: "myregistry/myapp:1.0"
Application-level overrides¶
Override global settings for specific applications:
spec:
commonUpdateSettings:
updateStrategy: "semver"
applicationRefs:
- namePattern: "production-*"
commonUpdateSettings:
updateStrategy: "latest" # Override for production apps
forceUpdate: true
images:
- alias: "app"
imageName: "myregistry/myapp:stable"
- namePattern: "development-*"
images:
- alias: "app"
imageName: "myregistry/myapp:dev"
Image-level overrides¶
Override settings for specific images:
spec:
commonUpdateSettings:
updateStrategy: "semver"
applicationRefs:
- namePattern: "*"
images:
- alias: "app"
imageName: "myregistry/myapp:1.0"
commonUpdateSettings:
updateStrategy: "latest" # Override for this specific image
- alias: "database"
imageName: "postgres:13"
# Uses global semver strategy
Application requirements¶
For Argo CD Image Updater to manage an application, the following criteria must be met:
- The application must be of type
HelmorKustomize - The application must be located in the
metadata.namespaceof the ImageUpdater CR - The application must match at least one
applicationRefcriteria
Configuring the write-back method¶
The Argo CD Image Updater supports two distinct methods on how to update images of an application:
- imperative, via Argo CD API
- declarative, by pushing changes to a Git repository
Depending on your setup and requirements, you can choose the write-back method
per Application, but not per image. As a rule of thumb, if you are managing
Application in Git (i.e. in an app-of-apps setup), you most likely want
to choose the Git write-back method.
The write-back method is configured via an ImageUpdater resource:
Where <method> must be one of argocd (imperative) or git (declarative).
The default used by Argo CD Image Updater is argocd.
Complete example¶
Here's a complete example that demonstrates various configuration options:
apiVersion: argocd-image-updater.argoproj.io/v1alpha1
kind: ImageUpdater
metadata:
name: production-updater
namespace: argocd
spec:
commonUpdateSettings:
updateStrategy: "semver"
forceUpdate: false
allowTags: "regexp:^v[0-9]+\\.[0-9]+\\.[0-9]+$"
ignoreTags: [ "latest", "dev", "test" ]
writeBackConfig:
method: "argocd"
applicationRefs:
- namePattern: "frontend-*"
labelSelectors:
matchLabels:
environment: "production"
commonUpdateSettings:
updateStrategy: "latest"
forceUpdate: true
writeBackConfig:
method: "git"
gitConfig:
repository: "git@github.com:myorg/frontend-config.git"
branch: "main"
writeBackTarget: "helmvalues:/values.yaml"
images:
- alias: "frontend"
imageName: "myregistry/frontend:v1.0"
commonUpdateSettings:
allowTags: "regexp:^v[0-9]+\\.[0-9]+\\.[0-9]+-prod$"
- alias: "nginx"
imageName: "nginx:1.20"
- namePattern: "backend"
images:
- alias: "api"
imageName: "myregistry/backend:v2.0"
commonUpdateSettings:
updateStrategy: "digest"
- alias: "database"
imageName: "postgres:13"
This configuration:
- Sets global defaults for semver updates
- Overrides frontend applications to use latest strategy and Git write-back
- Uses specific update strategies for individual images
- Combines name patterns with label selectors for precise targeting
For more details on configuring images and update strategies, see the Images Configuration and Update Strategies documentation.
Monitoring status¶
The ImageUpdater CR exposes a status subresource that reflects the observed
state of each resource. You can inspect it with:
The default output includes printer columns for quick visibility:
For the full status, use:
Status fields¶
| Field | Type | Description |
|---|---|---|
observedGeneration |
int64 | The most recent .metadata.generation observed by the controller. |
lastCheckedAt |
timestamp | When the controller last checked for image updates. |
lastUpdatedAt |
timestamp | When the controller last performed an image update. Only set when at least one image was updated. |
applicationsMatched |
int32 | Number of Argo CD applications matched by this CR's selectors. |
imagesManaged |
int32 | Number of images eligible for update checking. |
recentUpdates |
list | Image updates performed during the last update cycle (see below). |
conditions |
list | Standard Kubernetes conditions (see below). |
Recent updates¶
The recentUpdates list records each image that was updated during the most
recent update cycle. Each entry contains:
| Field | Type | Description |
|---|---|---|
alias |
string | The alias of the image configuration that was updated. |
image |
string | The full image reference. |
newVersion |
string | The new tag or digest the image was updated to. |
applicationsUpdated |
int32 | Number of applications in which this image was updated. |
updatedAt |
timestamp | When the update was applied. |
message |
string | Human-readable description of the update action. |
Conditions¶
The controller maintains three condition types following standard Kubernetes API conventions:
| Condition | Meaning when True |
Meaning when False |
|---|---|---|
Ready |
Last reconciliation completed successfully. | Last reconciliation failed entirely. |
Reconciling |
An image update check is currently in progress. | Controller is idle, awaiting the next cycle. |
Error |
Errors occurred during the last reconciliation. | No errors during the last reconciliation. |
Ready with partial errors
When some applications succeed and others fail, Ready is True with
reason ReconcileCompletedWithErrors, while Error is also True with
reason PartialErrors. Check the condition messages for details.
Example status¶
status:
observedGeneration: 5
lastCheckedAt: "2026-03-02T22:10:00Z"
lastUpdatedAt: "2026-03-02T22:12:35Z"
applicationsMatched: 7
imagesManaged: 3
recentUpdates:
- alias: "frontend-image"
image: "myregistry.com/myorg/frontend:v1.2.3"
newVersion: "v1.2.4"
applicationsUpdated: 2
updatedAt: "2026-03-02T22:12:35Z"
message: "Updated to latest patch via semver."
conditions:
- type: "Ready"
status: "True"
lastTransitionTime: "2026-03-02T22:10:00Z"
reason: "ReconcileSucceeded"
message: "Reconciled 7 applications, 2 images updated."
- type: "Reconciling"
status: "False"
lastTransitionTime: "2026-03-02T22:10:00Z"
reason: "Idle"
message: "Last check completed. Awaiting next cycle."
- type: "Error"
status: "False"
lastTransitionTime: "2026-03-02T22:10:00Z"
reason: "NoErrors"
message: "No errors during last reconciliation."