왜 배포 순서가 문제인가
ArgoCD는 기본적으로 Application에 속한 모든 매니페스트를 한 번에 클러스터에 적용한다. 대부분의 경우 Kubernetes 컨트롤러가 알아서 재조정(reconcile)하므로 순서를 신경 쓸 필요가 없다. 문제는 리소스 간에 런타임 의존성이 있을 때 발생한다. 예를 들어 데이터베이스 마이그레이션 Job이 애플리케이션 Deployment보다 먼저 끝나야 하거나, CRD가 등록되기 전에 해당 CR을 적용하면 no matches for kind 오류가 난다. Namespace나 ConfigMap, Secret이 준비되지 않은 상태에서 Pod가 기동하면 CrashLoopBackOff에 빠질 수도 있다.
이런 상황에서 ArgoCD는 Sync 자체는 성공했다고 보고하지만 실제로는 Pod가 죽고 재시작하는 사이클을 반복한다. 순서를 명시적으로 제어해야 하는 이유다.
Sync Wave의 동작 방식
Sync Wave는 리소스에 정수 순번을 부여해 낮은 값부터 순차적으로 적용하는 기능이다. argocd.argoproj.io/sync-wave 어노테이션에 숫자를 지정하며, 값을 지정하지 않은 리소스는 wave 0으로 취급된다. 음수도 사용할 수 있어 CRD나 Namespace처럼 가장 먼저 만들어야 하는 리소스에 유용하다.
핵심은 ArgoCD가 한 wave의 리소스가 모두 Healthy 상태가 될 때까지 기다린 뒤 다음 wave로 넘어간다는 점이다. 즉 단순히 apply 순서만 정하는 게 아니라 헬스 체크를 통과해야 진행된다. 이 때문에 헬스 상태를 판단할 수 없는 리소스(예: 커스텀 리소스)에는 헬스 정의가 필요할 수 있다.
apiVersion: apps/v1
kind: Deployment
metadata:
name: api-server
annotations:
argocd.argoproj.io/sync-wave: "2"
---
apiVersion: v1
kind: ConfigMap
metadata:
name: api-config
annotations:
argocd.argoproj.io/sync-wave: "1"
Hook과 함께 쓰는 마이그레이션 예시
실무에서 가장 흔한 패턴은 DB 마이그레이션 Job을 앱보다 먼저 실행하는 것이다. PreSync Hook과 sync-wave를 조합하면 마이그레이션 → 앱 배포 순서를 안정적으로 보장할 수 있다.
apiVersion: batch/v1
kind: Job
metadata:
name: db-migrate
annotations:
argocd.argoproj.io/hook: PreSync
argocd.argoproj.io/hook-delete-policy: HookSucceeded
argocd.argoproj.io/sync-wave: "-1"
spec:
template:
spec:
restartPolicy: Never
containers:
- name: migrate
image: registry.example.com/app:1.4.2
command: ["python", "manage.py", "migrate", "--noinput"]
Job이 성공(Complete)해야 wave -1이 Healthy로 판정되고, 그 다음 wave 0의 Deployment가 적용된다. 마이그레이션이 실패하면 Sync 전체가 중단되어 잘못된 스키마 위에 새 코드가 올라가는 사고를 막는다.
Hook과 Wave의 관계
Sync Wave는 Hook과 일반 리소스 양쪽 모두에 적용된다. ArgoCD의 sync 단계 안에서 각 phase(PreSync, Sync, PostSync)별로 wave 순서가 적용된다는 점을 이해해야 한다.
| 구분 | 적용 시점 | Wave 정렬 |
|---|---|---|
| PreSync Hook | Sync 이전 | phase 내부에서 wave 순 |
| 일반 리소스 | Sync 단계 | wave 낮은 값부터 |
| PostSync Hook | Sync 완료 후 | phase 내부에서 wave 순 |
주의점과 흔한 함정
- 헬스 체크가 없으면 대기가 무의미하다. 헬스 상태를 알 수 없는 리소스는 즉시 Healthy로 간주되어 다음 wave가 바로 진행된다. 커스텀 리소스라면 Lua 헬스 스크립트를 정의해야 실제 준비 상태를 반영한다.
- Wave 간 지연이 존재한다. 기본적으로 wave 전환 사이에 짧은 대기(기본 2초)가 있어 wave를 과도하게 잘게 나누면 전체 배포 시간이 늘어난다.
ARGOCD_SYNC_WAVE_DELAY로 조정 가능하다. - 순서는 롤백에도 영향을 준다. 삭제 시에는 wave가 역순으로 적용되지 않으므로, 제거 순서가 중요하다면 finalizer나 별도 설계를 고려해야 한다.
- Wave는 만능이 아니다. 실제 의존성은 앱의 재시도 로직이나 initContainer로 흡수하는 것이 더 견고한 경우가 많다. Wave는 "반드시 선행되어야 하는" 소수의 리소스에만 사용하는 편이 유지보수에 유리하다.
정리
Sync Wave는 어노테이션 하나로 배포 순서와 헬스 기반 대기를 동시에 얻을 수 있는 실용적인 도구다. CRD 등록, Namespace 생성, DB 마이그레이션처럼 순서가 결과를 좌우하는 지점에 집중해서 적용하고, 나머지는 Kubernetes의 재조정 메커니즘에 맡기는 것이 좋다. Wave를 남용하면 배포가 느려지고 의존 관계가 어노테이션 숫자 속에 숨어버리므로, 정말 필요한 곳에만 최소한으로 쓰는 것이 핵심이다.