- Published on
Argo CD Image Updater 미동작 원인 7가지
- Authors
- Name
- 스타차일드
- https://x.com/ETFBITX
서론
Argo CD Image Updater(이하 Image Updater)는 컨테이너 레지스트리의 새 태그를 감지해 Argo CD Application의 이미지 파라미터를 업데이트(보통 Git write-back 또는 Argo CD API patch)하는 도구입니다. 그런데 운영에서 자주 겪는 문제가 “이미지 태그는 올라가는데 Argo CD 쪽이 전혀 안 바뀐다”, “가끔만 된다”, “로그는 조용한데 아무 일도 없다” 같은 미동작 케이스입니다.
이 글에서는 Image Updater가 동작하지 않는 상황을 7가지 원인으로 나누고, 각 원인별로 어디를 봐야 하는지(로그/리소스/설정), 어떻게 고치는지, 검증 체크리스트를 제공합니다.
> 참고: 증상이 ‘동작은 하는데 배포가 계속 겹친다’에 가깝다면, CI/CD 동시성 제어도 함께 보세요: GitHub Actions 동시성 꼬임으로 배포 겹침 막기
빠른 5분 점검(공통)
아래 3가지만 먼저 확인해도 절반은 잡힙니다.
# 1) Image Updater가 살아있는지
kubectl -n argocd get deploy,pod | grep -E 'image-updater|argocd-image-updater'
# 2) 로그에서 스캔/업데이트 시도 흔적이 있는지
kubectl -n argocd logs deploy/argocd-image-updater --since=30m
# 3) 대상 Application에 annotation이 제대로 붙었는지
kubectl -n argocd get app <APP_NAME> -o yaml | sed -n '/annotations:/,/spec:/p'
이제 본격적으로 “왜 미동작처럼 보이는지”를 7가지로 쪼개 보겠습니다.
1) Application annotation/alias 오타로 ‘대상 자체를 스킵’
Image Updater는 보통 Application에 달린 annotation을 기준으로 “어떤 이미지를 추적할지”를 결정합니다. 가장 흔한 실수는:
argocd-image-updater.argoproj.io/image-list오타- 이미지 alias를 썼는데 다른 annotation에서 alias가 불일치
image-list에는 있는데 실제 Helm/Kustomize 파라미터 매핑이 없음
예시(정상):
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: myapp
namespace: argocd
annotations:
argocd-image-updater.argoproj.io/image-list: |
app=ghcr.io/acme/myapp
argocd-image-updater.argoproj.io/app.update-strategy: newest-build
argocd-image-updater.argoproj.io/app.helm.image-name: image.repository
argocd-image-updater.argoproj.io/app.helm.image-tag: image.tag
spec:
# ...
점검 포인트:
# annotation 키가 정확한지, image-list가 파싱 가능한지
kubectl -n argocd get app myapp -o jsonpath='{.metadata.annotations.argocd-image-updater\.argoproj\.io/image-list}'
해결:
- alias를 쓴다면
image-list와 매핑 annotation에서 alias를 동일하게 유지 - Helm values 경로(
image.repository,image.tag)가 실제 chart values와 일치하는지 확인
2) 업데이트 전략/태그 필터가 너무 빡세서 ‘새 태그가 있어도 후보가 0개’
Image Updater는 “아무 태그나” 잡지 않습니다. update-strategy, allow-tags, ignore-tags 같은 필터에 의해 후보 태그가 0개가 되면, 로그상 큰 에러 없이도 업데이트가 발생하지 않습니다.
자주 있는 케이스:
allow-tags: regexp:^v\d+\.\d+\.\d+$인데 실제 태그는v1.2.3-build.4newest-build를 기대했는데 태그가 세맨틱 버전이 아니라 정렬이 기대와 다름latest태그만 올리고 있는데 Image Updater는 digest/태그 정책에 따라 스킵
예시(필터 적용):
metadata:
annotations:
argocd-image-updater.argoproj.io/image-list: app=ghcr.io/acme/myapp
argocd-image-updater.argoproj.io/app.allow-tags: regexp:^v\d+\.\d+\.\d+$
argocd-image-updater.argoproj.io/app.update-strategy: semver
점검 포인트:
- 레지스트리에 실제로 어떤 태그가 있는지 확인
- Image Updater 로그에서 “considered tags” / “found tags” / “no suitable tags” 류 메시지 확인
해결:
- 태그 규칙을 먼저 표준화(예:
vX.Y.Z또는X.Y.Z)하고, 그에 맞춰allow-tags를 단순화 - 빌드 메타를 쓰고 싶다면 정규식/전략을 그에 맞게 조정
3) 레지스트리 인증/권한 문제: 401/403인데 ‘조용히 스캔 실패’
프라이빗 레지스트리(ECR/GHCR/GCR/사내 Harbor 등)에서 인증이 안 되면 스캔 자체가 실패합니다. 다만 설정에 따라 에러가 눈에 띄지 않거나, 특정 이미지 스캔만 실패해 “가끔 된다”처럼 보일 수 있습니다.
점검 포인트:
# Image Updater가 사용하는 secret/config 확인(설치 방식에 따라 다름)
kubectl -n argocd get secret | grep -iE 'reg|registry|docker|ecr|ghcr'
# 로그에서 401/403/denied/unauthorized 탐색
kubectl -n argocd logs deploy/argocd-image-updater --since=2h | grep -iE 'unauth|401|403|denied|forbidden'
EKS에서 IRSA로 ECR을 읽는다면, 토큰/AssumeRole 이슈가 원인일 때도 있습니다. 이런 경우는 STS 에러로 표면화되기도 하니 함께 점검하세요: AWS STS 토큰 만료로 403? IRSA·AssumeRole 점검
해결:
- 레지스트리별 권장 인증 방식 사용(ECR: IRSA + ecr:GetAuthorizationToken 등)
- Image Updater Pod의 ServiceAccount 권한/어노테이션(IRSA) 확인
- GHCR은 PAT scope(
read:packages) 누락이 흔함
4) Git write-back 설정 불일치: 커밋을 못 하거나 엉뚱한 브랜치로 푸시
Image Updater의 대표 동작 모드는 Git write-back입니다. 이때 “업데이트는 감지했는데 Git에 반영이 안 됨”이 매우 흔합니다.
대표 원인:
write-back-method가 설정되지 않았거나 기대와 다름- SSH 키/토큰 권한 부족(푸시 권한 없음)
- 기본 브랜치(main/master) 불일치
- 보호 브랜치 정책으로 direct push 금지(필요시 PR 기반으로 전환)
예시(SSH 기반 Git write-back):
metadata:
annotations:
argocd-image-updater.argoproj.io/write-back-method: git
argocd-image-updater.argoproj.io/git-branch: main
argocd-image-updater.argoproj.io/write-back-target: kustomization
점검 포인트:
# 로그에서 git push/commit 실패 확인
kubectl -n argocd logs deploy/argocd-image-updater --since=2h | grep -iE 'git|commit|push|write-back|permission'
해결:
- 토큰은 최소한
repo(GitHub) 또는 프로젝트 write 권한 필요 - 브랜치 이름을 명시(
git-branch)하고, Argo CD Application의targetRevision과 일치시키기 - 보호 브랜치라면 PR 방식(지원 설정) 또는 별도 자동 머지 파이프라인 설계
5) Argo CD sync 정책/자동 동기화 문제: ‘이미지는 바뀌었는데 배포는 그대로’
Image Updater가 Git에 커밋을 남겼더라도, Argo CD가 자동 동기화(Auto-Sync)를 하지 않으면 클러스터 리소스는 그대로일 수 있습니다. 이때 사용자는 “Image Updater가 안 도는 것 같다”고 착각합니다.
점검 포인트:
- Application이 Auto-Sync인지
- Sync가 막혀 있는지(Health/Sync 실패, Sync Window 제한 등)
argocd app get myapp
# Sync Policy, Sync Status, Conditions 확인
해결:
- 운영 정책상 자동 동기화를 끄는 경우, 커밋 반영 후
argocd app sync를 별도 파이프라인에서 수행 - Sync Window/프로젝트 정책 제한이 있는지 확인
6) 이미지 필드 매핑 실패(Helm/Kustomize/Plain YAML): ‘어디를 바꿔야 할지 모름’
Image Updater는 “이미지 태그를 어디에 기록할지”를 알아야 합니다. Helm 차트라면 values 경로, Kustomize라면 images: 또는 kustomization.yaml 타겟 등과의 매핑이 필요합니다.
실패 패턴:
- Helm values 키 경로가 실제 차트와 다름
- 한 차트 안에 이미지 키가 여러 개인데 일부만 매핑
- Kustomize overlay 구조에서 write-back target이 다른 위치를 가리킴
Kustomize 예시(정상적인 kustomization 타겟):
# overlays/prod/kustomization.yaml
images:
- name: ghcr.io/acme/myapp
newTag: v1.2.3
그리고 Application annotation:
metadata:
annotations:
argocd-image-updater.argoproj.io/image-list: app=ghcr.io/acme/myapp
argocd-image-updater.argoproj.io/write-back-target: kustomization
점검 포인트:
- 리포지토리에서 실제로 수정되어야 하는 파일이 무엇인지(overlay/prod인지 base인지)
- Image Updater가 커밋한 diff가 기대 경로인지
해결:
- Helm이면
*.helm.image-name,*.helm.image-tag를 실제 values 구조에 맞게 재설정 - Kustomize면 overlay 별로 write-back target을 명확히(필요 시 app 별도 분리)
7) 네트워크/DNS/프록시 문제로 레지스트리 조회가 간헐 실패
클러스터 네트워크가 불안정하거나, 사내 프록시/방화벽 정책 때문에 외부 레지스트리 조회가 실패하면 Image Updater는 주기적으로 실패합니다. 이 경우 “어쩔 땐 되고 어쩔 땐 안 됨”이 됩니다.
점검 포인트:
# Image Updater Pod에서 직접 레지스트리 엔드포인트 확인
kubectl -n argocd exec -it deploy/argocd-image-updater -- sh -lc '
nslookup ghcr.io || true
wget -S -O- https://ghcr.io/v2/ 2>&1 | head -n 30 || true
'
# 타임아웃/EOF/connection reset 등
kubectl -n argocd logs deploy/argocd-image-updater --since=2h | grep -iE 'timeout|i/o|eof|reset|dns'
EKS에서 CNI/네트워크 플러그인 이슈가 있으면 다른 워크로드도 함께 흔들립니다. Pod 네트워크 문제를 빠르게 분리 진단하려면 다음 글도 도움이 됩니다: EKS Pod NotReady(NetworkPlugin cni) 10분 해결
해결:
- 프록시 환경이면 Image Updater Deployment에
HTTP_PROXY/HTTPS_PROXY/NO_PROXY환경변수 설정 - DNS 정책(CoreDNS) 및 egress NAT/방화벽 정책 점검
- 레지스트리를 사내 미러로 두거나, egress 허용 CIDR을 명확히
실전 디버깅 루틴(재현 없이도 원인 좁히기)
문제 상황에서 아래 순서로 보면 빠르게 범위를 줄일 수 있습니다.
- Application annotation 파싱이 되는가?
image-list가 비어 있거나 오타면 그 즉시 끝
- 레지스트리 스캔이 성공하는가?
- 401/403/timeout/DNS 실패 여부
- 태그 후보가 실제로 존재하는가?
- allow/ignore/strategy 때문에 후보 0개인지
- write-back이 성공하는가?
- git push/commit 실패, 브랜치 불일치, 보호 브랜치
- Argo CD가 sync하는가?
- Auto-Sync off, Sync Window, 프로젝트 정책
결론
Argo CD Image Updater의 “미동작”은 대부분 (1) 대상 지정(annotation) 문제, (2) 태그 필터/전략 문제, (3) 레지스트리 인증/네트워크 문제, (4) Git write-back/브랜치 정책 문제, (5) Argo CD Sync 정책 문제, (6) 매핑(Helm/Kustomize) 문제로 귀결됩니다.
운영에서는 로그 한 줄만 보고 추측하기보다, 스캔(레지스트리) → 후보(필터) → 기록(write-back) → 적용(sync) 4단계를 분리해서 확인하면 원인을 빠르게 고립시킬 수 있습니다.
원하시면 사용 중인 설치 방식(Helm values, Image Updater 버전, write-back 방식, 레지스트리 종류, Application YAML 일부)을 기준으로, 위 7가지 중 어디가 가장 유력한지 체크리스트 형태로 같이 좁혀드릴게요.