Getting Started¶
Breaking Change: Default watch scope is now namespace-scoped
Previously, the controller operated in cluster-wide mode by default, watching
all namespaces using a ClusterRole and ClusterRoleBinding. The default is
now namespace-scoped: the controller watches only its own namespace using a
Role and RoleBinding. Existing installations that rely on cluster-wide
watching must explicitly set --watch-namespaces="*" and switch to
ClusterRole+ClusterRoleBinding RBAC. See
Choosing an installation namespace for
details.
Installation methods¶
The Argo CD Image Updater controller must be run in the same Kubernetes cluster where your Argo CD Application resources are managed. The current controller architecture does not support connecting to a remote Kubernetes cluster to manage applications.
While the argocd-image-updater binary can be run locally from your workstation for one-time updates (see Running locally section), the standard and supported installation for continuous, automated updates is as a controller inside your cluster.
Multi-Cluster Environments¶
In a multi-cluster setup where Argo CD, running on a central control plane cluster (let's call it cluster A), manages Application resources that are deployed to another cluster (cluster B), there is one important restriction:
- The Image Updater controller must be installed on cluster A.
- All
ImageUpdatercustom resources (CRs) must also be created on cluster A.
The controller cannot discover or process ImageUpdater CRs created on cluster B.
In short: The Image Updater controller and its ImageUpdater CRs must reside with your Argo CD Application resources, not with the deployed application workloads.
Namespace scope¶
The controller's watch scope is controlled by the --watch-namespaces flag (or IMAGE_UPDATER_WATCH_NAMESPACES env var) and determines which namespaces it monitors for ImageUpdater CRs and Argo CD Applications:
| Value | Scope | RBAC required |
|---|---|---|
| Not set (default) | Controller's own namespace only | Role + RoleBinding in that namespace |
"ns1,ns2,..." |
Listed namespaces only | Role + RoleBinding in each namespace |
"*" |
All namespaces, cluster-wide | ClusterRole + ClusterRoleBinding |
The default installation (install.yaml) uses Role and RoleBinding scoped to the controller's namespace. For --watch-namespaces="*", replace these with a ClusterRole and ClusterRoleBinding (see Option 3 below).
Choosing an installation namespace¶
Option 1: Install into the Argo CD namespace (Recommended)¶
The simplest approach. The controller runs in the same namespace as Argo CD, so the default scope (own namespace) covers both ImageUpdater CRs and Applications without any extra configuration.
If Argo CD is running in the argocd namespace, use the following command:
Note
We also provide a Kustomize base in addition to the plain Kubernetes YAML
manifests. You can use it as remote base and create overlays with your
configuration on top of it. The remote base's URL is
https://github.com/argoproj-labs/argocd-image-updater/config/default.
You can view the manifests here
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj-labs/argocd-image-updater/stable/config/install.yaml
By default, the controller watches only its own namespace. If you use Argo CD's Applications in any namespace feature and have Application resources in additional namespaces, configure --watch-namespaces and create a Role + RoleBinding in each extra namespace (see the Namespace scope table above).
Option 2: Install into a separate namespace¶
For better workload isolation, you can install the image updater into its own namespace. This use case requires several manual configuration steps.
Let's assume Argo CD runs in <argocd_namespace> and you are installing the image updater in <updater_namespace>.
-
Install the Controller
First, create the target namespace and apply the installation manifest.
-
Configure the Argo CD Namespace
The controller needs to know where to find Argo CD resources. Edit the
argocd-image-updater-controllerdeployment manifest and add theARGOCD_NAMESPACEenvironment variable to theargocd-image-updater-controllercontainer or addargocd.namespacekey to the ConfigMapargocd-image-updater-config, pointing to the namespace where Argo CD is installed.Also set
IMAGE_UPDATER_WATCH_NAMESPACES(or--watch-namespaces) to include both namespaces, since by default the controller only watches its own namespace and would not seeApplicationsin<argocd_namespace>.... env: - name: ARGOCD_NAMESPACE value: "<argocd_namespace>" - name: IMAGE_UPDATER_WATCH_NAMESPACES value: "<updater_namespace>,<argocd_namespace>" ...or
... data: argocd.namespace: "<argocd_namespace>" watch.namespaces: "<updater_namespace>,<argocd_namespace>" ...Alternatively, you can add the
--argocd-namespace=<argocd_namespace>and--watch-namespaces=<updater_namespace>,<argocd_namespace>flags to the container'scommandarguments in the deployment manifest. -
Patch the metrics ClusterRoleBindings
The
install.yamlmanifest hardcodesnamespace: argocdin the subjects of the metricsClusterRoleBindingresources (argocd-image-updater-metrics-auth-rolebindingandargocd-image-updater-metrics-reader-rolebinding). Patch both to reference<updater_namespace>instead, otherwise the controller's ServiceAccount will not receive theTokenReview/SubjectAccessReview/metrics-reader permissions. -
Grant permissions in the Argo CD namespace
ImageUpdaterCRs must be in the same namespace as theApplicationsthey reference, so they belong in<argocd_namespace>. The controller needs a fullRoleandRoleBindingthere to manage them alongsideApplicationsand Argo CDSecrets/ConfigMaps:apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: name: argocd-image-updater-argocd-ns-role namespace: <argocd_namespace> rules: - apiGroups: [""] resources: ["secrets", "configmaps"] verbs: ["get", "list", "watch"] - apiGroups: [""] resources: ["events"] verbs: ["create"] - apiGroups: ["argocd-image-updater.argoproj.io"] resources: ["imageupdaters"] verbs: ["create", "delete", "get", "list", "patch", "update", "watch"] - apiGroups: ["argocd-image-updater.argoproj.io"] resources: ["imageupdaters/finalizers"] verbs: ["update"] - apiGroups: ["argocd-image-updater.argoproj.io"] resources: ["imageupdaters/status"] verbs: ["get", "patch", "update"] - apiGroups: ["argoproj.io"] resources: ["applications"] verbs: ["get", "list", "patch", "update", "watch"] --- apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: name: argocd-image-updater-argocd-ns-rolebinding namespace: <argocd_namespace> roleRef: apiGroup: rbac.authorization.k8s.io kind: Role name: argocd-image-updater-argocd-ns-role subjects: - kind: ServiceAccount name: argocd-image-updater-controller namespace: <updater_namespace>
Option 3: Cluster-scoped installation¶
For environments where the controller must watch ImageUpdater CRs in any namespace, use --watch-namespaces="*". This requires a ClusterRole and ClusterRoleBinding.
-
Install the Controller
-
Replace Role with ClusterRole
Delete the namespace-scoped RBAC from the default install and apply cluster-scoped equivalents. The required permissions mirror
config/rbac/role.yaml:kubectl delete role argocd-image-updater-manager-role -n argocd kubectl delete rolebinding argocd-image-updater-manager-rolebinding -n argocdapiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: argocd-image-updater-manager-role rules: - apiGroups: [""] resources: ["events"] verbs: ["create"] - apiGroups: ["argocd-image-updater.argoproj.io"] resources: ["imageupdaters"] verbs: ["create", "delete", "get", "list", "patch", "update", "watch"] - apiGroups: ["argocd-image-updater.argoproj.io"] resources: ["imageupdaters/finalizers"] verbs: ["update"] - apiGroups: ["argocd-image-updater.argoproj.io"] resources: ["imageupdaters/status"] verbs: ["get", "patch", "update"] - apiGroups: ["argoproj.io"] resources: ["applications"] verbs: ["get", "list", "patch", "update", "watch"] --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: argocd-image-updater-manager-rolebinding roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: argocd-image-updater-manager-role subjects: - kind: ServiceAccount name: argocd-image-updater-controller namespace: argocd # Replace with your controller namespace -
Enable cluster-scoped watching
Configure the desired log level¶
While this step is optional, we recommend to set the log level explicitly. During your first steps with the Argo CD Image Updater, a more verbose logging can help greatly in troubleshooting things.
Edit the argocd-image-updater-config ConfigMap and add the following keys
(the values are dependent upon your environment)
If you omit the log.level setting, the default info level will be used.
Running locally¶
As long as you have access to your Kubernetes cluster from your workstation, running Argo CD Image Updater is simple. Make sure that your Kubernetes client configuration points to the correct K8s cluster.
Grab the binary and run:
Note: The --once flag disables the health server and the check interval, so
the tool will not regularly check for updates but exit after the first run.
Check argocd-image-updater --help for a list of valid command line flags, or
consult the appropriate section of the documentation.
Running multiple instances¶
Generally, multiple instances of Argo CD Image Updater can be run within the same Kubernetes cluster, however they should not operate on the same set of applications. This allows for multiple application teams to manage their own set of applications.
If opting for such an approach, you should make sure that:
- Each instance of Argo CD Image Updater runs in its own namespace
- Each instance has a dedicated user in Argo CD, with dedicated RBAC permissions
- RBAC permissions are set-up so that instances cannot interfere with each others managed resources
Metrics¶
Starting with v0.8.0, Argo CD Image Updater exports Prometheus-compatible
metrics. This feature is disabled by default but can be enabled using the
--metrics-bind-address flag to specify a listening address (e.g., :8080).
Metrics are then served on the /metrics path.
CR-scoped metrics are labeled by image_updater_cr_name and
image_updater_cr_namespace. They are populated only when the controller runs
with polling (default run command); in webhook-only mode (webhook command)
they are disabled to avoid orphaned series when CRs are deleted.
Available metrics
argocd_image_updater_applications_watched_total- A gauge that shows the number of applications watched perImageUpdaterCR.argocd_image_updater_images_watched_total- A gauge that shows the number of images watched (considered for update) perImageUpdaterCR.argocd_image_updater_images_updated_total- A counter of the number of images updated perImageUpdaterCR.argocd_image_updater_images_errors_total- A counter of the number of errors during image updates perImageUpdaterCR.
Sample output on the /metrics endpoint
# HELP argocd_image_updater_applications_watched_total The total number of applications watched by Argo CD Image Updater CR
# TYPE argocd_image_updater_applications_watched_total gauge
argocd_image_updater_applications_watched_total{image_updater_cr_name="dev",image_updater_cr_namespace="argocd"} 1
argocd_image_updater_applications_watched_total{image_updater_cr_name="prod",image_updater_cr_namespace="argocd"} 2
# HELP argocd_image_updater_images_watched_total Number of images watched by Argo CD Image Updater CR
# TYPE argocd_image_updater_images_watched_total gauge
argocd_image_updater_images_watched_total{image_updater_cr_name="dev",image_updater_cr_namespace="argocd"} 2
argocd_image_updater_images_watched_total{image_updater_cr_name="prod",image_updater_cr_namespace="argocd"} 1
# HELP argocd_image_updater_images_updated_total Number of images updated by Argo CD Image Updater CR
# TYPE argocd_image_updater_images_updated_total counter
argocd_image_updater_images_updated_total{image_updater_cr_name="dev",image_updater_cr_namespace="argocd"} 2
argocd_image_updater_images_updated_total{image_updater_cr_name="prod",image_updater_cr_namespace="argocd"} 5
# HELP argocd_image_updater_images_errors_total Number of errors reported by Argo CD Image Updater CR
# TYPE argocd_image_updater_images_errors_total counter
argocd_image_updater_images_errors_total{image_updater_cr_name="dev",image_updater_cr_namespace="argocd"} 0
argocd_image_updater_images_errors_total{image_updater_cr_name="prod",image_updater_cr_namespace="argocd"} 0
Here, two ImageUpdater CRs in the argocd namespace are tracked. Gauges
reflect the current state of the last run; counters are cumulative since
controller start.
Other Defined Metrics
The metrics listed below are also defined within the application. However,
for various reasons, they are either not populated with data or have been
temporarily disabled. They may not appear on the /metrics endpoint or may
always report a value of 0.
argocd_image_updater_k8s_api_requests_totalargocd_image_updater_k8s_api_errors_totalargocd_image_updater_registry_requests_totalargocd_image_updater_registry_requests_failed_total
A (very) rudimentary example dashboard definition for Grafana is provided here