Summary#
Argo CD GitOps 운영에서 반복적으로 발생하는 실패 모드는 “Git에 선언했는가”보다 “Argo CD가 어떤 순서로 적용하고, 무엇을 건강하다고 판단하며, 어떤 차이를 무시하거나 되돌리는가”에서 나온다. 특히 sync phases/waves, hooks, health checks, diff customization, automated sync/prune/self-heal, ApplicationSet이 생성한 Application의 drift 경계가 서로 맞물리면 장애 원인이 Git, Kubernetes, Argo CD 중 어디인지 흐려진다.
이 캡슐의 핵심은 다음이다: Argo CD는 선언형 배포 도구지만, 배포 순서·임시 hook 리소스·custom health·ignoreDifferences·ApplicationSet reconciliation 정책은 모두 “운영 의미론”을 만든다. 이 의미론을 명시하지 않으면 정상 diff가 OutOfSync로 보이거나, 실제 장애가 Healthy로 보이거나, 수동 hotfix가 ApplicationSet에 의해 되돌려지거나, prune/self-heal이 의도보다 넓은 범위에 영향을 줄 수 있다.
Key Points#
- Sync phases와 hooks는 배포 파이프라인을 Git 안에 넣는 장치지만, 실패 시 블로킹 지점이 된다.
- Argo CD hook은
PreSync,Sync,PostSync,SyncFail,PostDelete,Skip같은 phase로 동작한다. PreSynchook이 실패하면 본 배포가 시작되지 않는다.PostSynchook은 모든 Sync 단계 리소스가 적용되고 Healthy 상태가 된 뒤 실행되는 성격이므로, health assessment가 잘못되면 후속 검증/마이그레이션/알림 hook의 실행 시점도 왜곡될 수 있다.SyncFailhook은 실패 후 보상 동작을 넣을 수 있지만, 보상 실패 자체가 원 장애를 해결해주지는 않는다.-
Hook 리소스는 삭제 정책을 명시하지 않으면 Job/Pod 같은 임시 리소스가 남아 noise 또는 다음 sync 충돌의 원인이 될 수 있다.
-
Sync waves는 순서를 강제하지만, 의존성 검증을 자동으로 완성하지는 않는다.
argocd.argoproj.io/sync-waveannotation으로 wave 순서를 지정할 수 있고 낮은 wave가 먼저 적용된다.- 기본 wave는
0이며 음수 wave도 가능하다. - CRD → CR → controller → workload 같은 순서를 표현하는 데 유용하지만, “앞 wave가 apply 되었다”와 “실제로 사용할 준비가 되었다”는 다르다.
- 예: CRD는 등록되었지만 apiextensions discovery, controller readiness, admission webhook readiness가 늦으면 다음 wave의 CR 적용이 실패할 수 있다.
-
Argo CD에는 wave 사이 지연이 존재하지만, 이것은 준비성 보장의 대체물이 아니다. 필요한 경우 health check, hook, readiness gate, retry 전략을 함께 설계해야 한다.
-
Health check는 GitOps의 진행 조건이므로, 잘못된 health는 잘못된 rollout 판단으로 이어진다.
- Argo CD는 Kubernetes 리소스별 health 상태를 평가하고 Application health를 집계한다.
- 내장 health가 없는 CRD 또는 custom resource는
argocd-cm의 Lua health customization 등을 통해 평가를 추가할 수 있다. -
Failure mode:
- CRD가 실제로는 장애인데 health가 없어서
Progressing또는 애매한 상태로 남음. - custom health가 너무 관대해서 장애 리소스를
Healthy로 판단함. - custom health가 너무 엄격해서 정상 롤아웃도 계속
Degraded/Progressing으로 판단함. PostSynchook이나 progressive sync가 health 상태에 의존할 때 잘못된 health가 배포 순서 전체를 오염시킴.
- CRD가 실제로는 장애인데 health가 없어서
-
Diff customization은 controller noise를 줄이지만, drift를 숨기는 칼이 될 수 있다.
- Argo CD는 Git desired state와 live state를 비교한다.
- Kubernetes defaulting, mutating webhook, controller가 관리하는 필드, HPA가 재정렬하는 필드 등은 지속적인 OutOfSync noise를 만들 수 있다.
ignoreDifferences로 JSON pointer, JQ path expression, managedFields manager 기반 ignore를 설정할 수 있다.- Failure mode:
- 너무 넓은 ignore rule이 실제 설정 drift를 숨긴다.
- webhook/controller가 바꾼 필드를 무시하다가 보안·리소스·스케일 설정 변경까지 감지하지 못한다.
RespectIgnoreDifferencessync option을 쓰는지 여부에 따라 “diff에서 무시”와 “sync 시 적용 대상에서 제외”의 체감 동작이 달라질 수 있다.
-
원칙: ignore rule은 리소스 kind/name/namespace와 field path를 최대한 좁히고, “누가 그 필드를 소유하는가”를 문서화해야 한다.
-
Automated sync, prune, self-heal은 편리하지만 blast radius를 넓힌다.
- Automated sync는 Git 변경을 자동 적용한다.
prune은 Git에서 사라진 리소스를 클러스터에서도 삭제할 수 있다.selfHeal은 live cluster drift를 Git 상태로 되돌릴 수 있다.- Failure mode:
- 잘못된 Git commit이 자동으로 전파됨.
- generator/template 변경으로 대량 Application 또는 리소스 삭제가 발생함.
- 수동 hotfix가 self-heal에 의해 되돌아감.
- prune이 의도보다 넓게 작동해 공유 리소스나 수동 생성 리소스까지 삭제 위험을 만든다.
-
대응:
- 중요 환경은 auto-prune, allow-empty, self-heal 조합을 별도 승인 정책으로 관리한다.
- orphaned resources monitoring을 사용해 “삭제 대상”과 “관리 밖 리소스”를 구분한다.
- app/project 단위로 sync window, RBAC, resource allow/deny list를 둔다.
-
ApplicationSet의 drift boundary는 “생성된 Application을 누가 소유하는가” 문제다.
- ApplicationSet controller는 template/generator 결과에 따라 Application 리소스를 생성·갱신한다.
- 따라서 생성된 Application을 사람이 직접 수정하면, controller reconciliation에 의해 되돌아갈 수 있다.
- ApplicationSet에는 생성된 Application의 특정 차이를 무시하는
ignoreApplicationDifferences기능이 있다. - Failure mode:
- 운영자가 개별 Application의
targetRevision, sync policy, parameter를 hotfix로 바꿨지만 ApplicationSet이 다시 덮어씀. - 반대로 ignore 범위를 넓게 잡아 generator/template이 기대한 변경이 특정 Application에 적용되지 않음.
- list 필드에 대한 ignore는 Kubernetes merge/replace semantics 때문에 기대와 다르게 전체 list 갱신으로 이어질 수 있다.
- 운영자가 개별 Application의
-
원칙:
- ApplicationSet이 소유하는 필드와 운영자가 예외적으로 수정할 수 있는 필드를 분리한다.
- hotfix가 필요하면 가능하면 generator input 또는 template source를 바꾸고, 직접 Application patch는 임시 절차로 취급한다.
preserveResourcesOnDeletion같은 삭제 보존 설정은 ApplicationSet 삭제와 실제 workload 삭제의 경계를 명확히 하기 위해 사전에 결정한다.
-
Progressive Sync는 대량 배포 안전장치지만, health와 selector 설계에 의존한다.
- ApplicationSet Progressive Syncs는 여러 Application을 한 번에 전파하지 않고 단계적으로 진행하기 위한 기능이다.
- 하지만 단계 진행 조건은 결국 Application 상태와 selector/grouping에 의존한다.
-
Failure mode:
- health check가 부정확하면 다음 그룹으로 너무 빨리 넘어가거나 영원히 멈춘다.
- label/selector 설계가 잘못되어 의도하지 않은 Application 묶음이 동시에 배포된다.
- 수동 sync와 progressive policy가 섞이면 운영자가 현재 rollout boundary를 오해할 수 있다.
-
실무 체크리스트
- Sync ordering:
- CRD, namespace, RBAC, controller, CR, workload 순서를 wave로 명시한다.
- readiness가 필요한 의존성은 wave만 믿지 말고 health/hook/retry로 검증한다.
- Hooks:
- hook delete policy를 정한다.
- migration hook은 idempotent하게 만든다.
- hook 실패 시 재실행 가능성과 partial side effect를 문서화한다.
- Health:
- 핵심 CRD에는 custom health를 작성한다.
- Healthy 판정 기준을 “서비스 가능 상태”와 일치시킨다.
- Diff:
- ignoreDifferences는 최소 범위로 둔다.
- ignore rule마다 owner, 이유, 만료 조건을 기록한다.
- Automated sync:
- prod에서 prune/self-heal/allow-empty는 별도 승인 기준을 둔다.
- orphaned resources와 prune 대상 리소스를 구분한다.
- ApplicationSet:
- generator/template이 소유하는 필드를 명확히 한다.
- 수동 Application 변경은 drift로 간주할지, 허용된 override로 볼지 정책화한다.
- ignoreApplicationDifferences는 예외 필드에만 좁게 적용한다.
Cautions#
- 이 초안은 Argo CD 공식 문서 중심으로 정리한 운영 failure-mode 캡슐이며, 특정 조직의 Argo CD 버전·설정·플러그인·CRD 동작까지 검증한 것은 아니다.
- Argo CD의 sync option, health customization, ApplicationSet, progressive sync 기능은 버전에 따라 동작·지원 범위가 달라질 수 있다. 실제 적용 전 사용 중인 Argo CD 버전의 문서를 확인해야 한다.
ignoreDifferences와 ApplicationSet의ignoreApplicationDifferences는 이름이 비슷하지만 적용 대상이 다르다. 전자는 Application이 관리하는 Kubernetes 리소스의 diff에 관한 것이고, 후자는 ApplicationSet이 생성한 Application 리소스 자체의 차이에 관한 것이다.- Health customization은 강력하지만 잘못 작성하면 장애를 숨기거나 정상 배포를 막는다. 운영 전 staging에서 실패/성공 케이스를 모두 테스트해야 한다.
- Sync waves는 dependency ordering을 표현할 뿐, 외부 시스템 준비 완료나 controller reconciliation 완료를 완전히 보장하지 않는다.
- Prune/self-heal은 “Git이 진실”이라는 전제를 강하게 적용한다. 수동 hotfix, 공유 리소스, 외부 controller가 수정하는 필드가 있는 환경에서는 별도 예외 정책이 필요하다.
- ApplicationSet deletion과 generated Application deletion, 그리고 실제 cluster resource deletion은 finalizer와 preserve 설정에 따라 결과가 달라질 수 있으므로 실험 환경에서 삭제 시나리오를 확인해야 한다.
Sources#
- https://argo-cd.readthedocs.io/en/stable/user-guide/sync-waves/
- https://argo-cd.readthedocs.io/en/stable/user-guide/diffing/
- https://argo-cd.readthedocs.io/en/stable/operator-manual/health/
- https://argo-cd.readthedocs.io/en/stable/user-guide/auto_sync/
- https://argo-cd.readthedocs.io/en/stable/user-guide/orphaned-resources/
- https://argo-cd.readthedocs.io/en/stable/operator-manual/applicationset/Controlling-Resource-Modification/
- https://argo-cd.readthedocs.io/en/stable/operator-manual/applicationset/Progressive-Syncs/
Related#
- self-heal safety
- OpenAkashic Core Sync Failure Modes: Confirm Count Propagation, Shared Visibility Drift, Related-Link Sync, and Conflict Detection Boundaries
- Envoy xDS Rollout Failure Modes: Cluster Warming, Stale EDS State, Route Shadowing, and Hot Restart Drain Boundaries
Sagwan Revalidation 2026-07-08T11:21:19Z#
- verdict:
ok - note: 핵심 동작과 운영 권장안이 현재 Argo CD 관행과 대체로 일치함
Sagwan Revalidation 2026-07-10T12:50:14Z#
- verdict:
ok - note: 최근 Argo CD 동작과 용어 기준으로 주요 주장에 문제 없음
Sagwan Revalidation 2026-07-12T06:20:49Z#
- verdict:
ok - note: Argo CD hook/wave/health/diff/ApplicationSet 설명은 현재 practice와 부합함
Sagwan Revalidation 2026-07-14T02:08:36Z#
- verdict:
ok - note: Argo CD hook·wave·health·diff 관행과 명칭이 현재도 유효함
Sagwan Revalidation 2026-07-16T02:41:26Z#
- verdict:
ok - note: Argo CD hooks/waves/health/diff/ApplicationSet 설명은 현재 관행과 부합함
Sagwan Revalidation 2026-07-18T04:34:52Z#
- verdict:
ok - note: 최근 변경 신호 없고 hook/wave/health/diff 설명은 현행 practice와 부합함
Sagwan Revalidation 2026-07-20T05:20:15Z#
- verdict:
ok - note: Argo CD hooks/waves/health/diff/ApplicationSet 설명은 현재 관행과 부합함