- Authors

- Name
- Youngju Kim
- @fjvbn20031
- 1. Sync 엔진 개요
- 2. Sync Phases (동기화 단계)
- 3. Resource Hooks 상세
- 4. Sync Waves와 순서 제어
- 5. Resource Tracking (리소스 추적)
- 6. Diff 엔진 상세 분석
- 7. Health Assessment (건강 상태 평가)
- 8. Pruning (리소스 정리) 상세
- 9. Retry 전략과 Backoff
- 10. Sync 옵션
- 11. Sync Window (동기화 시간대)
- 12. 실전 Sync 전략
- 13. 정리
1. Sync 엔진 개요
ArgoCD의 Sync 엔진은 Git 저장소에 정의된 원하는 상태(Desired State)를 Kubernetes 클러스터에 적용하는 핵심 모듈입니다. 단순한 kubectl apply를 넘어 Hook, Wave, Health Check, Retry 등 정교한 메커니즘을 제공합니다.
Sync 상태 머신
Pending --> Running --> Succeeded
|
+--> Failed --> (Retry or Manual)
Sync 작업은 다음 상태를 가집니다:
| 상태 | 설명 |
|---|---|
| Pending | Sync가 대기열에 있음 |
| Running | Sync가 실행 중 |
| Succeeded | 모든 리소스가 성공적으로 동기화됨 |
| Failed | Sync 중 오류 발생 |
2. Sync Phases (동기화 단계)
ArgoCD는 Sync를 여러 단계(Phase)로 나누어 실행합니다. 각 단계에서 특정 유형의 리소스를 처리합니다.
Phase 실행 순서
PreSync --> Sync --> PostSync
|
+--> SyncFail (Sync 실패 시에만)
PreSync Phase
PreSync는 메인 동기화 전에 실행되는 단계입니다:
apiVersion: batch/v1
kind: Job
metadata:
name: db-migration
annotations:
argocd.argoproj.io/hook: PreSync
argocd.argoproj.io/hook-delete-policy: HookSucceeded
spec:
template:
spec:
containers:
- name: migrate
image: myapp/migration:latest
command: ['./migrate', 'up']
restartPolicy: Never
PreSync 사용 사례:
- 데이터베이스 스키마 마이그레이션
- 설정 사전 검증
- 외부 시스템 상태 확인
- 백업 생성
Sync Phase
메인 동기화 단계에서는 실제 Kubernetes 리소스를 클러스터에 적용합니다:
1. 모든 Sync Phase 리소스를 Wave 순서로 정렬
2. 각 Wave 그룹별로:
a. 리소스 타입 순서에 따라 적용
b. 각 리소스에 대해 kubectl apply 동등 작업 수행
c. 해당 Wave의 모든 리소스가 Healthy가 될 때까지 대기
3. 다음 Wave로 진행
PostSync Phase
PostSync는 메인 동기화가 성공한 후에만 실행됩니다:
apiVersion: batch/v1
kind: Job
metadata:
name: notification
annotations:
argocd.argoproj.io/hook: PostSync
argocd.argoproj.io/hook-delete-policy: HookSucceeded
spec:
template:
spec:
containers:
- name: notify
image: curlimages/curl:latest
command:
- curl
- -X
- POST
- https://hooks.slack.com/services/XXX
- -d
- '{"text":"Deployment successful"}'
restartPolicy: Never
PostSync 사용 사례:
- 배포 완료 알림 전송
- 스모크 테스트 실행
- CDN 캐시 무효화
- 외부 시스템 동기화 트리거
SyncFail Phase
SyncFail은 Sync가 실패했을 때만 실행됩니다:
apiVersion: batch/v1
kind: Job
metadata:
name: failure-notification
annotations:
argocd.argoproj.io/hook: SyncFail
argocd.argoproj.io/hook-delete-policy: HookSucceeded
spec:
template:
spec:
containers:
- name: notify-failure
image: curlimages/curl:latest
command:
- curl
- -X
- POST
- https://hooks.slack.com/services/XXX
- -d
- '{"text":"Deployment FAILED"}'
restartPolicy: Never
3. Resource Hooks 상세
Hook 어노테이션
metadata:
annotations:
# Hook 유형 지정
argocd.argoproj.io/hook: PreSync|Sync|PostSync|SyncFail|Skip
# Hook 리소스 삭제 정책
argocd.argoproj.io/hook-delete-policy: HookSucceeded|HookFailed|BeforeHookCreation
Hook Delete Policy
| 정책 | 설명 |
|---|---|
| HookSucceeded | Hook이 성공하면 리소스를 삭제 |
| HookFailed | Hook이 실패하면 리소스를 삭제 |
| BeforeHookCreation | 다음 Sync에서 Hook을 생성하기 전에 기존 리소스를 삭제 |
BeforeHookCreation이 기본값이며, 가장 많이 사용됩니다. 이 정책은 다음 Sync 시 이전 Hook 리소스를 먼저 삭제한 후 새로 생성합니다.
Hook 실행 메커니즘
1. Application Controller가 Sync 시작
2. 현재 Phase에 해당하는 Hook 리소스 식별
3. Hook 리소스를 Wave 순서로 정렬
4. 각 Hook 리소스를 클러스터에 적용 (Job, Pod 등)
5. Hook이 완료(성공/실패)될 때까지 대기
6. 성공 시 다음 단계 진행, 실패 시 Sync 중단 또는 SyncFail Phase로 전환
7. Delete Policy에 따라 Hook 리소스 정리
4. Sync Waves와 순서 제어
Sync Wave 개념
Sync Wave는 리소스 적용 순서를 세밀하게 제어하는 메커니즘입니다:
# Wave -1: 인프라 리소스 (먼저 생성)
apiVersion: v1
kind: Namespace
metadata:
name: my-app
annotations:
argocd.argoproj.io/sync-wave: '-1'
---
# Wave 0: 설정 리소스 (기본값)
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
annotations:
argocd.argoproj.io/sync-wave: '0'
---
# Wave 1: 애플리케이션 리소스
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
annotations:
argocd.argoproj.io/sync-wave: '1'
---
# Wave 2: 외부 접근 리소스
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: my-app-ingress
annotations:
argocd.argoproj.io/sync-wave: '2'
Wave 실행 로직
1. 모든 리소스를 Wave 번호로 그룹화
2. 가장 낮은 Wave부터 순서대로 실행
3. 각 Wave 내에서는 리소스 타입 기본 순서 적용
4. 현재 Wave의 모든 리소스가 Healthy가 될 때까지 대기
5. 다음 Wave로 진행
6. 어느 Wave에서든 실패 시 전체 Sync 중단
리소스 타입 기본 순서
동일 Wave 내에서 리소스는 다음 순서로 적용됩니다:
Phase 1: 네임스페이스와 기본 설정
1. Namespace
2. NetworkPolicy
3. ResourceQuota
4. LimitRange
5. PodSecurityPolicy
6. ServiceAccount
7. Secret
8. SecretList
9. ConfigMap
Phase 2: RBAC
10. ClusterRole
11. ClusterRoleBinding
12. Role
13. RoleBinding
Phase 3: CRD
14. CustomResourceDefinition
Phase 4: 스토리지와 볼륨
15. PersistentVolume
16. PersistentVolumeClaim
17. StorageClass
Phase 5: 서비스
18. Service
19. Endpoints
Phase 6: 워크로드
20. DaemonSet
21. Deployment
22. ReplicaSet
23. StatefulSet
24. Job
25. CronJob
Phase 7: 라우팅
26. Ingress
27. IngressClass
28. APIService
5. Resource Tracking (리소스 추적)
Tracking 방식
ArgoCD는 자신이 관리하는 리소스를 추적하기 위해 두 가지 방식을 제공합니다:
Annotation 방식 (기본값, 권장):
metadata:
annotations:
argocd.argoproj.io/tracking-id: 'my-app:apps/Deployment:default/nginx'
Label 방식 (레거시):
metadata:
labels:
app.kubernetes.io/instance: my-app
Tracking ID 구조
APP_NAME:GROUP/KIND:NAMESPACE/NAME
예시:
my-app:apps/Deployment:default/nginx
my-app:/Service:default/nginx-svc
my-app:networking.k8s.io/Ingress:default/nginx-ingress
Tracking 방식 설정
argocd-cm ConfigMap에서 설정합니다:
apiVersion: v1
kind: ConfigMap
metadata:
name: argocd-cm
namespace: argocd
data:
application.resourceTrackingMethod: annotation # annotation | label | annotation+label
6. Diff 엔진 상세 분석
3-Way Diff
ArgoCD는 세 가지 상태를 비교합니다:
1. Desired State: Git에서 생성된 매니페스트 (목표 상태)
2. Live State: 클러스터에서 실행 중인 실제 상태
3. Last Applied: 마지막으로 적용된 설정 (annotation에 기록)
Structured Merge Diff
ArgoCD는 Kubernetes의 Server-Side Apply에서 사용하는 Structured Merge Diff 라이브러리를 활용합니다:
// Diff 수행 로직 (간소화)
func diff(desired, live *unstructured.Unstructured) (*DiffResult, error) {
// 1. 정규화
normalizedDesired := normalize(desired)
normalizedLive := normalize(live)
// 2. 무시 필드 제거
removeIgnoredFields(normalizedDesired)
removeIgnoredFields(normalizedLive)
// 3. 구조적 비교
result := structuredMergeDiff(normalizedDesired, normalizedLive)
return result, nil
}
Normalization (정규화) 상세
정규화는 불필요한 diff를 제거하기 위한 핵심 과정입니다:
제거 대상 필드:
metadata.resourceVersionmetadata.uidmetadata.generationmetadata.creationTimestampmetadata.managedFieldsstatus(대부분의 리소스)
정규화 규칙 예시:
- Container의
imagePullPolicy가 생략되었지만 이미지 태그가latest면 Kubernetes가Always를 자동 설정 -> diff에서 무시 - Service의
clusterIP가 생략되면 Kubernetes가 자동 할당 -> diff에서 무시 - 빈 필드(
"",[],null)와 미설정 필드의 동등 처리
Diff 결과 해석
| 결과 | 의미 |
|---|---|
| NoDiff | 원하는 상태와 실제 상태가 동일 (Synced) |
| Diff | 차이 존재 (OutOfSync) |
| Modified | 필드 값이 변경됨 |
| Added | 새 필드가 추가됨 |
| Removed | 필드가 제거됨 |
Diff Customization
특정 필드를 diff에서 무시하도록 설정할 수 있습니다:
# Application 리소스에서 설정
spec:
ignoreDifferences:
- group: apps
kind: Deployment
jsonPointers:
- /spec/replicas # HPA가 관리하는 replica 수 무시
- group: ''
kind: ConfigMap
jqPathExpressions:
- .data.generated-field # 자동 생성 필드 무시
글로벌 설정은 argocd-cm ConfigMap에서 가능합니다:
data:
resource.customizations.ignoreDifferences.all: |
managedFieldsManagers:
- kube-controller-manager
- kube-scheduler
7. Health Assessment (건강 상태 평가)
Built-in Health Check
ArgoCD는 주요 Kubernetes 리소스에 대해 내장 Health Check를 제공합니다:
Deployment:
Healthy: 모든 replica가 Ready이고 업데이트 완료
Progressing: 롤아웃이 진행 중 (새 ReplicaSet 생성 중)
Degraded: replica가 Ready 상태에 도달하지 못함
StatefulSet:
Healthy: 모든 replica가 Ready이고 currentRevision == updateRevision
Progressing: 업데이트가 진행 중
Degraded: replica가 Ready가 아님
Pod:
Healthy: Running 상태이고 모든 컨테이너가 Ready
Progressing: Pending 또는 ContainerCreating 상태
Degraded: CrashLoopBackOff, ImagePullBackOff 등
Service:
Healthy: Endpoints가 존재하고 하나 이상의 Ready 주소가 있음
Progressing: LoadBalancer 타입에서 외부 IP 할당 대기 중
Ingress:
Healthy: LoadBalancer 주소가 할당됨
Progressing: 주소 할당 대기 중
Job:
Healthy: 성공적으로 완료됨 (Completed)
Progressing: 실행 중 (Active)
Degraded: 실패 (Failed)
Custom Lua Health Check
기본 Health Check로 충분하지 않은 경우, Lua 스크립트로 커스텀 로직을 작성합니다:
# argocd-cm ConfigMap
data:
resource.customizations.health.cert-manager.io_Certificate: |
hs = {}
if obj.status ~= nil then
if obj.status.conditions ~= nil then
for _, condition in ipairs(obj.status.conditions) do
if condition.type == "Ready" then
if condition.status == "True" then
hs.status = "Healthy"
hs.message = "Certificate is ready"
else
hs.status = "Degraded"
hs.message = condition.message
end
return hs
end
end
end
end
hs.status = "Progressing"
hs.message = "Waiting for certificate"
return hs
Health Check 대상 CRD 예시
| CRD | 프로젝트 | Health Check 기준 |
|---|---|---|
| Certificate | cert-manager | Ready condition |
| VirtualService | Istio | 항상 Healthy (상태 없음) |
| Rollout | Argo Rollouts | phase 필드 기반 |
| HelmRelease | Flux | Ready condition |
| Kustomization | Flux | Ready condition |
8. Pruning (리소스 정리) 상세
Prune 동작 원리
1. Git 매니페스트에서 모든 리소스 목록 생성
2. 클러스터에서 ArgoCD가 관리하는 리소스 조회 (tracking label/annotation)
3. 클러스터에 존재하지만 Git에 없는 리소스 식별 (= Prune 대상)
4. 삭제 정책에 따라 리소스 삭제
삭제 전략
Cascade 삭제 (기본값):
- 소유 리소스를 재귀적으로 삭제
- Deployment를 삭제하면 ReplicaSet과 Pod도 함께 삭제
- Kubernetes의 garbage collection 메커니즘 사용
Foreground 삭제:
- 소유 리소스가 먼저 삭제된 후 부모 리소스 삭제
- 순서가 보장되어야 하는 경우 사용
- finalizer를 통한 순서 제어
Prune 보호
의도하지 않은 삭제를 방지하기 위한 보호 메커니즘:
# 리소스에 Prune 방지 어노테이션 추가
metadata:
annotations:
argocd.argoproj.io/sync-options: Prune=false
# Application 수준에서 Prune 비활성화
spec:
syncPolicy:
automated:
prune: false # 자동 Prune 비활성화
Orphan 리소스 모니터링
ArgoCD는 관리 대상이 아닌 "고아(Orphan)" 리소스도 감지할 수 있습니다:
# AppProject에서 Orphan 리소스 모니터링 활성화
spec:
orphanedResources:
warn: true # 경고만 표시
# ignore: # 무시할 리소스 패턴
# - group: ""
# kind: ConfigMap
# name: "auto-*"
9. Retry 전략과 Backoff
Auto-Sync Retry
Sync가 실패하면 자동으로 재시도할 수 있습니다:
spec:
syncPolicy:
automated:
selfHeal: true
retry:
limit: 5 # 최대 재시도 횟수
backoff:
duration: 5s # 초기 대기 시간
factor: 2 # 대기 시간 증가 배수
maxDuration: 3m # 최대 대기 시간
Backoff 계산 예시
재시도 1: 5초 후
재시도 2: 10초 후 (5s * 2)
재시도 3: 20초 후 (10s * 2)
재시도 4: 40초 후 (20s * 2)
재시도 5: 80초 후 (40s * 2) -> 최대 3분으로 제한
Retry 트리거 조건
다음 상황에서 Retry가 트리거됩니다:
- 리소스 적용 실패 (API 서버 오류, 유효성 검사 실패 등)
- Health Check 타임아웃 (리소스가 시간 내에 Healthy가 되지 않음)
- Hook 실행 실패 (PreSync/PostSync Job 실패)
- 네트워크 일시적 오류
10. Sync 옵션
Application 수준 Sync 옵션
spec:
syncPolicy:
automated:
prune: true # Git에서 삭제된 리소스 자동 정리
selfHeal: true # 수동 변경 자동 교정
allowEmpty: false # 빈 매니페스트 허용 여부
syncOptions:
- CreateNamespace=true # 네임스페이스 자동 생성
- PrunePropagationPolicy=foreground # 삭제 전파 정책
- PruneLast=true # 다른 리소스 동기화 후 Prune
- Replace=false # apply 대신 replace 사용 여부
- ServerSideApply=true # Server-Side Apply 사용
- ApplyOutOfSyncOnly=true # OutOfSync 리소스만 적용
- Validate=true # 매니페스트 유효성 검사
- RespectIgnoreDifferences=true # ignoreDifferences 설정 존중
리소스 수준 Sync 옵션
개별 리소스에 어노테이션으로 설정할 수 있습니다:
metadata:
annotations:
argocd.argoproj.io/sync-options: Prune=false,Replace=true
Server-Side Apply
Server-Side Apply는 Kubernetes 1.22+에서 권장되는 적용 방식입니다:
장점:
- 필드 소유권(Field Ownership) 추적
- 여러 컨트롤러 간 충돌 방지
- 더 정확한 3-way merge
- 대규모 리소스에서 성능 향상
설정:
syncOptions:
- ServerSideApply=true
11. Sync Window (동기화 시간대)
Sync Window 개념
AppProject에서 동기화를 허용하거나 금지하는 시간대를 설정할 수 있습니다:
spec:
syncWindows:
# 평일 업무시간에만 Sync 허용
- kind: allow
schedule: '0 9 * * 1-5' # 월-금 09:00
duration: 9h # 9시간 동안
applications:
- '*'
namespaces:
- 'production'
# 주말에는 Sync 금지
- kind: deny
schedule: '0 0 * * 0,6' # 토,일 00:00
duration: 24h
applications:
- '*'
# 수동 Sync만 허용하는 시간대
- kind: allow
schedule: '0 18 * * 1-5' # 월-금 18:00
duration: 15h
manualSync: true
applications:
- 'critical-*'
Window 유형
| 유형 | 설명 |
|---|---|
| allow | 지정된 시간에만 Sync를 허용 |
| deny | 지정된 시간에는 Sync를 금지 |
우선순위 규칙
1. deny가 allow보다 우선
2. 동일 우선순위면 더 구체적인 규칙이 우선
3. manualSync=true면 수동 Sync만 허용
12. 실전 Sync 전략
안전한 프로덕션 배포 전략
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: production-app
spec:
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true
- PruneLast=true
- ServerSideApply=true
- ApplyOutOfSyncOnly=true
retry:
limit: 3
backoff:
duration: 10s
factor: 2
maxDuration: 5m
ignoreDifferences:
- group: apps
kind: Deployment
jsonPointers:
- /spec/replicas # HPA 관리
- group: autoscaling
kind: HorizontalPodAutoscaler
jqPathExpressions:
- .status
Hook을 활용한 완전한 배포 파이프라인
# Wave -2: PreSync - DB 백업
apiVersion: batch/v1
kind: Job
metadata:
name: db-backup
annotations:
argocd.argoproj.io/hook: PreSync
argocd.argoproj.io/hook-delete-policy: BeforeHookCreation
argocd.argoproj.io/sync-wave: '-2'
spec:
template:
spec:
containers:
- name: backup
image: backup-tool:latest
command: ['./backup.sh']
restartPolicy: Never
---
# Wave -1: PreSync - DB 마이그레이션
apiVersion: batch/v1
kind: Job
metadata:
name: db-migrate
annotations:
argocd.argoproj.io/hook: PreSync
argocd.argoproj.io/hook-delete-policy: BeforeHookCreation
argocd.argoproj.io/sync-wave: '-1'
spec:
template:
spec:
containers:
- name: migrate
image: myapp/migration:v2
command: ['./migrate', 'up']
restartPolicy: Never
---
# Wave 0: Sync - 메인 애플리케이션
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp
annotations:
argocd.argoproj.io/sync-wave: '0'
spec:
replicas: 3
selector:
matchLabels:
app: myapp
template:
metadata:
labels:
app: myapp
spec:
containers:
- name: app
image: myapp:v2
---
# Wave 1: PostSync - 스모크 테스트
apiVersion: batch/v1
kind: Job
metadata:
name: smoke-test
annotations:
argocd.argoproj.io/hook: PostSync
argocd.argoproj.io/hook-delete-policy: BeforeHookCreation
argocd.argoproj.io/sync-wave: '1'
spec:
template:
spec:
containers:
- name: test
image: curlimages/curl:latest
command: ['curl', '-f', 'http://myapp:8080/health']
restartPolicy: Never
13. 정리
ArgoCD Sync 엔진의 핵심 요소를 정리합니다:
- Phase: PreSync, Sync, PostSync, SyncFail로 배포 단계를 구조화
- Hook: Job이나 Pod로 각 Phase에서 커스텀 작업 실행
- Wave: 리소스 간 적용 순서를 세밀하게 제어
- Diff Engine: 3-Way Merge 기반의 정규화된 상태 비교
- Health Check: 내장 + Lua 커스텀으로 리소스 건강 상태 평가
- Pruning: Git에서 제거된 리소스의 안전한 정리
- Retry: 지수 백오프를 통한 자동 재시도
- Sync Window: 시간대 기반 동기화 제어
이러한 메커니즘을 적절히 조합하면 안전하고 예측 가능한 GitOps 배포 파이프라인을 구축할 수 있습니다.