- Published on
Argo CD Sync 실패 comparisonError 원인·해결
- Authors
- Name
- 스타차일드
- https://x.com/ETFBITX
서로 다른 환경에서 Argo CD를 운영하다 보면 Sync failed의 원인이 실제 Apply 실패가 아니라, 그 이전 단계인 비교(Comparison/Diff) 단계에서 터지는 경우가 많습니다. 이때 UI에는 흔히 comparisonError로 뭉뚱그려 표시되는데, 메시지가 짧거나 “failed to load live state” 같은 형태로만 보여서 원인 파악이 어렵습니다.
이 글에서는 comparisonError가 무엇인지(어느 단계에서 발생하는지), 로그/CLI로 원인을 좁히는 방법, 그리고 현장에서 자주 만나는 원인별 해결책을 정리합니다.
comparisonError란 무엇인가
Argo CD의 기본 흐름을 단순화하면 다음과 같습니다.
- Git에서 Desired 상태(매니페스트)를 가져옴
- 매니페스트를 렌더링(Helm/Kustomize/플러그인)
- 클러스터에서 Live 상태를 조회(K8s API)
- Desired vs Live를 비교(Diff)
- Sync 시 Apply
comparisonError는 대체로 2~4 단계(렌더링/라이브 조회/비교)에서 문제가 생겼다는 의미입니다. 즉, “적용하다가 실패”라기보다 “적용하기 전에 비교할 수 없어서 실패”에 가깝습니다.
특히 다음 상황에서 자주 발생합니다.
- Helm/Kustomize 렌더링 실패(차트 의존성, values, 플러그인)
- 클러스터 Live 리소스 조회 실패(RBAC, API 오류)
- CRD/스키마 불일치로 Diff가 실패
- Admission Webhook이 Live 조회/서버 사이드 디프 과정에 간섭
- Argo CD repo-server / application-controller 네트워크 문제
가장 먼저 확인할 것: UI 이벤트 vs 컨트롤러 로그
UI의 애플리케이션 상세 화면에서 Conditions 또는 Events에 ComparisonError가 찍힙니다. 하지만 핵심 원인은 application-controller 또는 repo-server 로그에 있습니다.
- 렌더링/리포지토리 접근/플러그인 문제:
argocd-repo-server로그 - 라이브 상태 조회/클러스터 접근/RBAC 문제:
argocd-application-controller로그
아래처럼 네임스페이스를 확인한 뒤 로그를 봅니다.
# Argo CD가 설치된 네임스페이스 예: argocd
kubectl -n argocd get pods
# repo-server 로그
kubectl -n argocd logs deploy/argocd-repo-server -f --tail=200
# application-controller 로그
kubectl -n argocd logs deploy/argocd-application-controller -f --tail=200
이때 로그에 자주 보이는 패턴은 다음과 같습니다.
rpc error: code = Unknown desc = ...(repo-server gRPC/렌더링)failed to load live state(클러스터 조회/RBAC)the server could not find the requested resource(CRD 미설치/버전 불일치)x509: certificate signed by unknown authority(TLS/프록시)
원인 1) Helm/Kustomize 렌더링 실패
증상
- UI에는
comparisonError - repo-server 로그에 Helm 템플릿 에러가 찍힘
예시 로그/메시지:
Error: failed to download ... chart(의존성 다운로드 실패)YAML parse error/template: ...(템플릿 문법)cannot load values(values 파일 경로)
해결 체크리스트
- 차트 의존성(Chart.lock/Chart.yaml)과 repo-server 네트워크
- Argo CD Helm 렌더링은 repo-server에서 수행됩니다.
- 사내망/프록시 환경이면 repo-server가 외부 Helm repo에 접근하지 못해 비교 단계부터 실패합니다.
- Helm dependency를 Git에 vendor
- 외부 접근이 불안정하면
charts/디렉터리에 의존성을 포함하거나, OCI 레지스트리 사용을 검토합니다.
- Kustomize remote base / Helm chart remote 참조 제한
- 보안 설정에 따라 remote base를 막아두면 렌더링이 실패할 수 있습니다.
빠른 재현(로컬에서 동일 렌더링)
# Helm 렌더링 재현
helm template myapp ./chart -f values.yaml --namespace myns
# Kustomize 렌더링 재현
kustomize build overlays/prod
로컬에서는 되는데 Argo CD에서만 실패하면, repo-server 환경(네트워크/DNS/CA/프록시/플러그인 바이너리) 차이를 의심해야 합니다.
원인 2) 클러스터 Live 상태 조회 실패(RBAC)
증상
- application-controller 로그에
forbidden또는cannot list resource - UI에는
failed to load live state
Argo CD는 비교를 위해 대상 네임스페이스의 리소스를 get/list/watch 해야 합니다. RBAC이 부족하면 Apply 이전에 비교 단계에서 막힙니다.
확인 방법
Argo CD가 사용하는 ServiceAccount(설치 방식에 따라 다름)가 무엇인지 확인합니다.
kubectl -n argocd get sa
kubectl -n argocd describe deploy argocd-application-controller | sed -n '/Service Account/,$p'
그리고 해당 SA가 대상 네임스페이스 리소스를 읽을 수 있는지 kubectl auth can-i로 확인합니다.
SA="system:serviceaccount:argocd:argocd-application-controller"
kubectl auth can-i list deployments.apps -n myns --as="$SA"
kubectl auth can-i list secrets -n myns --as="$SA"
kubectl auth can-i get configmaps -n myns --as="$SA"
해결
- 최소 권한 원칙을 유지하되, Argo CD가 관리하는 리소스 종류에 대해
get/list/watch권한을 부여합니다. - 클러스터 스코프 리소스(CRD, ClusterRole, Namespace 등)를 관리한다면 clusterrole 권한이 필요합니다.
원인 3) CRD 미설치/버전 불일치로 인한 비교 실패
증상
the server could not find the requested resource- 특정 CR(Custom Resource)만 비교에서 실패
예: Git에는 Foo CR이 있는데, 클러스터에는 Foo의 CRD가 없거나 apiVersion이 다릅니다.
진단
# CRD 존재 여부
kubectl get crd | grep -i foo
# 특정 리소스 조회
kubectl api-resources | grep -i foo
해결
- CRD를 먼저 설치하도록 앱을 분리하거나(예:
crds앱 →workloads앱), sync wave를 사용해 CRD가 먼저 적용되게 합니다. - Helm 차트의
crds/디렉터리를 사용하는 경우, Argo CD에서 CRD 적용 순서가 기대와 다를 수 있으니 운영 정책에 맞게 분리하는 편이 안전합니다.
원인 4) Admission Webhook/OPA/Gatekeeper/Kyverno로 인한 부작용
증상
- Apply가 아니라 비교 단계에서 에러가 나는데, 로그에 웹훅 타임아웃/거부가 섞여 있음
context deadline exceeded또는failed calling webhook형태
일부 웹훅은 특정 리소스 조회/패치/서버사이드 적용 경로에서 예상치 못한 영향을 줄 수 있습니다. 특히 웹훅 엔드포인트 장애나 네트워크 정책으로 접근이 막히면, K8s API가 웹훅 호출에서 지연되어 Argo CD의 비교가 실패할 수 있습니다.
해결
- 웹훅 서비스 엔드포인트/헬스 확인
failurePolicy: Ignore적용 여부 검토(보안 정책에 따라 신중)- 타임아웃/네트워크 정책/보안그룹 점검
클러스터 네트워크 이슈가 의심될 때는 egress 관점 점검도 도움이 됩니다. 특히 EKS 환경에서 “Pod는 정상인데 외부 통신만 막힘” 같은 케이스는 비교 단계에서 repo-server가 의존성 다운로드를 못 하거나, 컨트롤러가 API/웹훅과 통신이 꼬이면서 comparisonError로 보이기도 합니다. 관련 점검 흐름은 EKS에서 Pod는 정상인데 egress만 막힐 때 점검을 참고하세요.
원인 5) repo-server 플러그인/커스텀 툴 체인 문제
증상
- CMP(Config Management Plugin) 사용 시
plugin sidecar/exec실패 permission denied,no such file or directory,exec format error
플러그인은 repo-server에서 실행되므로 다음이 중요합니다.
- 바이너리 아키텍처(amd64/arm64) 일치
- 실행 권한/파일 경로
- 컨테이너 보안 컨텍스트(readOnlyRootFilesystem 등)
- 플러그인이 호출하는 외부 도구(예:
yq,helm,kustomize) 존재 여부
해결
- repo-server 이미지에 필요한 바이너리를 bake 하거나, sidecar에 넣고 경로를 명확히 지정
securityContext때문에 실행이 막히는지 확인
kubectl -n argocd describe pod -l app.kubernetes.io/name=argocd-repo-server | sed -n '/Containers:/,$p'
원인 6) 리소스가 너무 커서 Diff/조회가 실패(Timeout/메모리)
대규모 CR(거대한 ConfigMap, 큰 CRD 스펙, 수천 개 리소스)에서 비교 단계가 느려지거나 repo-server/application-controller가 리소스 부족으로 불안정해질 수 있습니다.
증상
context deadline exceeded- 컨트롤러/리포서버 재시작
이 경우에는 OOM이나 리소스 누수로 이어지기도 하므로, 컨테이너 메모리/CPU 제한과 실제 사용량을 확인하세요. OOM 진단 흐름은 Kubernetes OOMKilled 진단과 메모리 누수 추적 실전이 도움이 됩니다.
실전 트러블슈팅 절차(빠르게 원인 좁히기)
1) 어떤 컴포넌트 문제인지 분리
- repo-server 로그에 에러가 있다 → 렌더링/레포 접근/플러그인
- application-controller 로그에
forbidden/live state→ RBAC/클러스터 접근
2) Argo CD CLI로 상태/메시지 확인
argocd app get myapp
argocd app diff myapp
argocd app logs myapp --since 10m # 환경에 따라 지원/권한 필요
app diff가 실패하면 비교 단계 문제 확률이 매우 높습니다.
3) “특정 리소스만” 문제인지 확인
- 한 리소스 타입(CR)에서만 터지면 CRD/웹훅/스키마
- 특정 네임스페이스만 터지면 RBAC/네임스페이스 정책
- 특정 환경(prod만)에서 터지면 네트워크/프록시/인증서
자주 쓰는 해결 패턴 모음
패턴 A: CRD 먼저, 워크로드 나중
argocd app을 2개로 분리platform-crdsplatform-workloads
- 또는 sync wave/depends-on을 활용
패턴 B: RBAC을 “읽기” 중심으로 먼저 맞추기
비교 단계에서 필요한 건 기본적으로 get/list/watch입니다. Apply 권한보다 먼저 읽기 권한이 맞는지 확인하세요.
패턴 C: repo-server 네트워크/CA/프록시 표준화
- 사내 CA를 repo-server에 주입
- outbound 정책(네트워크 정책/보안그룹/NAT) 확인
- Helm repo/OCI registry 접근 경로를 고정
패턴 D: 웹훅 장애가 전체 배포를 막지 않게 설계
- 웹훅
timeoutSeconds조정 - 장애 시 영향 범위를 줄이기 위한
failurePolicy검토 - 웹훅 서비스의 HPA/리소스/네트워크 정책 점검
비교 오류를 줄이는 운영 팁
- App-of-Apps 구조에서는 CRD/클러스터 공통 리소스를 별도 앱으로 분리
- 큰 리소스(대형 ConfigMap/CR)는 분할하거나 생성 방식을 재검토
- repo-server/application-controller에 적절한 리소스 요청/제한을 설정
- Argo CD 업그레이드 시 diff/health 관련 변경사항 릴리즈 노트 확인
마무리
comparisonError는 “Sync가 실패했다”는 결과만 보여주지만, 실제로는 렌더링(repo-server) 또는 라이브 상태 조회(application-controller) 단계에서 실패한 경우가 대부분입니다. 따라서 문제를 빠르게 푸는 핵심은 (1) 에러가 어느 컴포넌트에서 났는지 분리하고, (2) RBAC/CRD/웹훅/네트워크/플러그인 중 어디가 병목인지 로그로 좁히는 것입니다.
운영 환경이 EKS이고 네트워크 이슈 가능성이 있다면 egress 경로부터 점검해보는 것도 시간을 크게 줄여줍니다. 또한 비교 단계에서의 타임아웃/재시작이 보이면 리소스 부족(OOM)까지 함께 의심해보세요.