Skip to content

ArgoCD Image Updater Integration

This guide covers integrating NORA with ArgoCD Image Updater for automated image updates in GitOps workflows.

  • NORA registry accessible via HTTPS with valid certificate
  • ArgoCD Image Updater installed in your cluster
  • DNS hostname configured for NORA (not just IP address)

⚠️ Critical: Use Hostname, Not IP Address

Section titled “⚠️ Critical: Use Hostname, Not IP Address”

Always configure ArgoCD Image Updater with a DNS hostname, never an IP address.

# argocd-image-updater-config ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
name: argocd-image-updater-config
namespace: argocd
data:
registries.conf: |
registries:
- name: nora
api_url: https://nora.example.com # ✅ Use hostname
prefix: nora.example.com # ✅ Use hostname
insecure: no
default: yes
# DO NOT USE IP ADDRESS
registries:
- name: nora
api_url: https://10.0.202.20 # ❌ IP address causes issues
prefix: 10.0.202.20 # ❌ Will create .meta tags

Why this matters: Using IP addresses causes ArgoCD Image Updater to incorrectly track image metadata, resulting in recursive .meta tags (see Known Issues below).


apiVersion: v1
kind: ConfigMap
metadata:
name: argocd-image-updater-config
namespace: argocd
data:
registries.conf: |
registries:
- name: nora
api_url: https://nora.devitacademy.lab
prefix: nora.devitacademy.lab
insecure: no
default: yes
log.level: debug # Optional: for troubleshooting

Apply:

Terminal window
kubectl apply -f argocd-image-updater-config.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: myapp
namespace: argocd
annotations:
argocd-image-updater.argoproj.io/image-list: myapp=nora.devitacademy.lab/myapp
argocd-image-updater.argoproj.io/myapp.update-strategy: latest
argocd-image-updater.argoproj.io/myapp.allow-tags: regexp:^[0-9a-f]{7}$
spec:
source:
repoURL: https://gitlab.example.com/myorg/myapp-infra.git
path: overlays/prod
Terminal window
kubectl rollout restart deployment argocd-image-updater -n argocd
Terminal window
# Check Image Updater logs
kubectl logs -n argocd -l app.kubernetes.io/name=argocd-image-updater -f
# Expected output:
# level=info msg="Initialized registry endpoint https://nora.devitacademy.lab"

Option 1: No Authentication (Internal Network)

Section titled “Option 1: No Authentication (Internal Network)”

If NORA runs without authentication (internal network only):

registries:
- name: nora
api_url: https://nora.example.com
prefix: nora.example.com
insecure: no
# No credentials needed

Create secret:

Terminal window
kubectl create secret generic nora-creds \
--namespace argocd \
--from-literal=username=admin \
--from-literal=password=secret

Reference in ConfigMap:

registries:
- name: nora
api_url: https://nora.example.com
prefix: nora.example.com
credentials: secret:argocd/nora-creds
Terminal window
kubectl create secret generic nora-token \
--namespace argocd \
--from-literal=token=<your-token>
registries:
- name: nora
api_url: https://nora.example.com
prefix: nora.example.com
credentials: secret:argocd/nora-token

Symptom:

Registry accumulates tags like:

latest
latest.meta
latest.meta.meta
latest.meta.meta.meta
...

Root Cause:

ArgoCD Image Updater was configured with IP address instead of hostname. When using IP addresses, Image Updater cannot properly correlate image metadata and creates recursive tracking tags.

Solution:

  1. Update ConfigMap to use hostname:
registries:
- name: nora
api_url: https://nora.example.com # Change from IP to hostname
prefix: nora.example.com
  1. Restart Image Updater:
Terminal window
kubectl delete pod -n argocd -l app.kubernetes.io/name=argocd-image-updater
  1. Clean up existing .meta tags:
#!/bin/bash
REGISTRY="https://nora.example.com"
REPO="myapp"
# Get all .meta tags
META_TAGS=$(curl -s "${REGISTRY}/v2/${REPO}/tags/list" | \
jq -r '.tags[] | select(contains(".meta"))')
# Delete each .meta tag
for TAG in $META_TAGS; do
# Get manifest digest
DIGEST=$(curl -sI \
-H "Accept: application/vnd.docker.distribution.manifest.v2+json" \
"${REGISTRY}/v2/${REPO}/manifests/${TAG}" | \
grep Docker-Content-Digest | awk '{print $2}' | tr -d '\r')
# Delete manifest
curl -X DELETE "${REGISTRY}/v2/${REPO}/manifests/${DIGEST}"
echo "Deleted ${TAG} (${DIGEST})"
done

Prevention:

Always use DNS hostnames in ArgoCD Image Updater configuration, never IP addresses.


Problem: Image Updater not detecting new images

Section titled “Problem: Image Updater not detecting new images”

Check:

  1. Verify registry configuration:
Terminal window
kubectl get cm argocd-image-updater-config -n argocd -o yaml
  1. Check Image Updater logs:
Terminal window
kubectl logs -n argocd -l app.kubernetes.io/name=argocd-image-updater | grep nora
  1. Test registry access from Image Updater pod:
Terminal window
kubectl exec -n argocd deployment/argocd-image-updater -- \
wget -O- https://nora.example.com/v2/_catalog

Solution: Ensure hostname is resolvable and certificate is trusted


Error:

x509: certificate signed by unknown authority

Solution:

Add CA certificate to Image Updater:

  1. Create ConfigMap with CA cert:
Terminal window
kubectl create configmap nora-ca \
--namespace argocd \
--from-file=ca.crt=/path/to/ca.crt
  1. Mount in Image Updater deployment:
spec:
template:
spec:
containers:
- name: argocd-image-updater
volumeMounts:
- name: nora-ca
mountPath: /etc/ssl/certs/nora-ca.crt
subPath: ca.crt
volumes:
- name: nora-ca
configMap:
name: nora-ca
  1. Restart deployment:
Terminal window
kubectl rollout restart deployment argocd-image-updater -n argocd

Error:

429 Too Many Requests

Solution:

Increase NORA rate limits (see Rate Limits Guide):

Terminal window
NORA_RATE_LIMIT_GENERAL_RPS=1000
NORA_RATE_LIMIT_GENERAL_BURST=2000

Image Updater polls registries frequently; ensure general limits accommodate this.


  1. Always use HTTPS - Never use insecure registries in production
  2. Use DNS hostnames - Avoid IP addresses to prevent .meta tag issues
  3. Limit update frequency - Configure reasonable polling intervals
  4. Monitor logs - Watch for authentication or network issues
  5. Tag patterns - Use specific tag patterns to avoid unwanted updates
  6. Test in staging - Verify configuration before production deployment

Terminal window
# Docker run command
docker run -d --name nora \
--restart unless-stopped \
-p 5000:5000 -p 4000:4000 \
-v /data/nora:/data \
-e NORA_STORAGE_PATH=/data \
-e NORA_RATE_LIMIT_GENERAL_RPS=1000 \
-e NORA_RATE_LIMIT_GENERAL_BURST=2000 \
ghcr.io/getnora-io/nora:latest serve
Terminal window
# /etc/hosts or DNS server
10.0.202.20 nora.devitacademy.lab
nora.devitacademy.lab:443 {
tls /etc/ssl/certs/nora.crt /etc/ssl/private/nora.key
reverse_proxy localhost:5000
}
apiVersion: v1
kind: ConfigMap
metadata:
name: argocd-image-updater-config
namespace: argocd
data:
registries.conf: |
registries:
- name: nora
api_url: https://nora.devitacademy.lab
prefix: nora.devitacademy.lab
insecure: no
default: yes
metadata:
annotations:
argocd-image-updater.argoproj.io/image-list: |
backend=nora.devitacademy.lab/lms-backend:latest,
frontend=nora.devitacademy.lab/lms-frontend:latest

Result: Image Updater successfully detects new images and updates applications without creating .meta tags.