Kubernetes 클러스터에 애플리케이션을 배포할 때, kubectl apply나 helm upgrade를 사람이 직접 실행하는 방식은 ‘누가, 언제, 무엇을’ 변경했는지 추적하기 어렵습니다. ArgoCD는 Git 저장소를 단일 진실의 원천(Single Source of Truth)으로 삼아, 선언된 상태와 클러스터 실제 상태를 자동으로 동기화하는 GitOps 도구입니다.
이 글에서는 ArgoCD의 핵심 개념부터, Application 리소스 설정, Sync Policy와 자동/수동 동기화 전략, 멀티 환경 배포 패턴, 그리고 운영에서 반드시 알아야 할 트러블슈팅 포인트까지 정리합니다.
1. GitOps란 무엇이고, 왜 ArgoCD인가
GitOps는 인프라와 애플리케이션의 원하는 상태(Desired State)를 Git에 선언하고, 자동화 도구가 실제 상태(Live State)를 맞추는 운영 모델입니다. 핵심 원칙은 네 가지입니다.
| 원칙 | 의미 | ArgoCD 구현 |
|---|---|---|
| 선언적 설정 | YAML/Helm/Kustomize로 원하는 상태를 코드화 | Application CRD에서 source 지정 |
| Git = 진실의 원천 | 모든 변경은 Git 커밋으로 추적 | repoURL + targetRevision으로 커밋/브랜치 추적 |
| 자동 동기화 | Git과 클러스터의 차이를 자동 감지·반영 | Sync Policy automated + self-heal |
| 감사 추적 | 누가 언제 무엇을 변경했는지 Git 이력으로 확인 | Git log + ArgoCD Audit 이벤트 |
ArgoCD는 Kubernetes 네이티브(CRD 기반)이고, Web UI·CLI·API를 모두 제공하며, Helm·Kustomize·plain YAML을 모두 지원합니다. CNCF Graduated 프로젝트로 커뮤니티 성숙도가 높습니다.
2. ArgoCD 아키텍처 핵심 컴포넌트
┌─────────────┐ ┌──────────────────┐ ┌─────────────────┐
│ Git Repo │────▶│ ArgoCD Server │────▶│ K8s Cluster │
│ (Source) │ │ (API + UI) │ │ (Destination) │
└─────────────┘ └──────────────────┘ └─────────────────┘
│
┌──────┴──────┐
│ │
┌─────▼─────┐ ┌────▼──────┐
│ Repo Server│ │App Controller│
│ (Git clone │ │(Sync loop, │
│ manifest │ │ diff, health)│
│ render) │ └─────────────┘
└───────────┘
- API Server: Web UI, CLI, gRPC API를 제공하는 진입점
- Repo Server: Git 저장소를 clone하고 Helm/Kustomize 매니페스트를 렌더링
- Application Controller: 주기적으로(기본 3분) Git 상태와 클러스터 상태를 비교하고, 동기화 수행
3. Application 리소스 설정 실전
ArgoCD에서 배포 단위는 Application CRD입니다. 하나의 Application이 하나의 Git 경로(또는 Helm 차트)를 하나의 클러스터 네임스페이스에 매핑합니다.
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: my-app
namespace: argocd
spec:
project: default
source:
repoURL: https://github.com/my-org/k8s-manifests.git
targetRevision: main
path: apps/my-app/overlays/production
destination:
server: https://kubernetes.default.svc
namespace: my-app
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true
- ApplyOutOfSyncOnly=true
retry:
limit: 3
backoff:
duration: 5s
factor: 2
maxDuration: 1m
주요 필드 설명
| 필드 | 설명 | 실무 권장값 |
|---|---|---|
targetRevision |
추적할 브랜치, 태그, 커밋 SHA | 프로덕션은 태그, 개발은 브랜치 |
prune |
Git에서 삭제된 리소스를 클러스터에서도 삭제 | true (미설정 시 고아 리소스 누적) |
selfHeal |
수동 kubectl 변경을 Git 상태로 되돌림 | true (GitOps 원칙 강제) |
ApplyOutOfSyncOnly |
변경된 리소스만 apply | true (대규모 앱 동기화 시간 단축) |
4. Helm 차트 배포: ArgoCD + Helm
ArgoCD에서 Helm 차트를 배포할 때는 source에 chart 또는 path를 지정하고, values 파일을 오버라이드합니다.
# Helm 레포지토리의 차트 배포
spec:
source:
repoURL: https://charts.bitnami.com/bitnami
chart: postgresql
targetRevision: 13.2.24
helm:
releaseName: my-postgres
valuesObject:
primary:
persistence:
size: 50Gi
auth:
existingSecret: pg-credentials
# Git 저장소 내 Helm 차트 배포
spec:
source:
repoURL: https://github.com/my-org/helm-charts.git
targetRevision: main
path: charts/my-app
helm:
valueFiles:
- values-production.yaml
parameters:
- name: image.tag
value: "1.3.0"
주의: ArgoCD가 Helm 차트를 렌더링할 때 helm template을 사용합니다. Helm의 릴리스 관리(helm list, helm rollback)는 ArgoCD와 별개이므로, ArgoCD를 쓰면 Helm CLI로 직접 배포하지 않는 것이 원칙입니다.
5. 멀티 환경 배포: App of Apps 패턴
여러 Application을 하나의 부모 Application이 관리하는 패턴입니다. 환경별로 디렉터리를 나누고, 부모 앱이 하위 앱들을 자동으로 생성합니다.
# 디렉터리 구조
k8s-manifests/
├── apps/
│ ├── root-app.yaml # 부모 Application
│ ├── dev/
│ │ ├── my-app.yaml # dev Application
│ │ └── monitoring.yaml
│ └── production/
│ ├── my-app.yaml # prod Application
│ └── monitoring.yaml
└── base/
└── my-app/
├── deployment.yaml
├── service.yaml
└── kustomization.yaml
# root-app.yaml (부모 Application)
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: root-app
namespace: argocd
spec:
project: default
source:
repoURL: https://github.com/my-org/k8s-manifests.git
targetRevision: main
path: apps/production
destination:
server: https://kubernetes.default.svc
namespace: argocd
syncPolicy:
automated:
prune: true
selfHeal: true
이 구조에서 apps/production/ 디렉터리에 새 Application YAML을 추가하면, root-app이 자동으로 감지하고 해당 Application을 생성합니다. 마이크로서비스가 늘어날 때마다 ArgoCD UI에서 수동 등록할 필요가 없습니다.
6. Sync Waves와 Hooks: 배포 순서 제어
데이터베이스 마이그레이션을 앱 배포 전에 실행하거나, 배포 후 알림을 보내야 할 때 Sync Wave와 Hook을 사용합니다.
# DB 마이그레이션 Job (wave -1: 앱보다 먼저 실행)
apiVersion: batch/v1
kind: Job
metadata:
name: db-migrate
annotations:
argocd.argoproj.io/hook: PreSync
argocd.argoproj.io/hook-delete-policy: HookSucceeded
spec:
template:
spec:
containers:
- name: migrate
image: my-app:1.3.0
command: ["npm", "run", "migrate"]
restartPolicy: Never
# 배포 완료 후 Slack 알림
apiVersion: batch/v1
kind: Job
metadata:
name: notify-deploy
annotations:
argocd.argoproj.io/hook: PostSync
argocd.argoproj.io/hook-delete-policy: HookSucceeded
spec:
template:
spec:
containers:
- name: notify
image: curlimages/curl
command: ["curl", "-X", "POST", "https://hooks.slack.com/..."]
restartPolicy: Never
| Hook 타입 | 실행 시점 | 용도 |
|---|---|---|
| PreSync | 동기화 전 | DB 마이그레이션, 스키마 변경 |
| Sync | 메인 리소스와 동시 | 일반 배포 (기본값) |
| PostSync | 동기화 성공 후 | 알림, 스모크 테스트, 캐시 워밍 |
| SyncFail | 동기화 실패 시 | 장애 알림, 자동 롤백 트리거 |
7. 운영에서 자주 하는 실수 5가지
- selfHeal 없이 automated sync만 켜기 — 누군가 kubectl로 직접 변경하면 Git과 클러스터가 영구적으로 불일치 상태가 됩니다. selfHeal을 반드시 함께 켜세요.
- prune 미설정 — Git에서 리소스를 삭제해도 클러스터에 남아 고아 리소스가 됩니다. 프로덕션에서 prune: true가 무섭다면,
argocd.argoproj.io/sync-options: Prune=false어노테이션으로 특정 리소스만 보호하세요. - 앱 코드와 매니페스트를 같은 Git 저장소에 두기 — 코드 커밋마다 ArgoCD가 불필요한 동기화를 트리거합니다. 앱 코드 저장소와 K8s 매니페스트 저장소는 분리하는 것이 표준 패턴입니다.
- targetRevision을 HEAD로 고정 — 프로덕션에서 main 브랜치 HEAD를 추적하면, 실수 커밋이 즉시 배포됩니다. 프로덕션은 Git 태그를 추적하고, PR 머지 후 태그를 생성하는 워크플로를 쓰세요.
- Secret을 Git에 평문으로 커밋 — GitOps의 치명적 함정입니다. Sealed Secrets, External Secrets Operator, 또는 Vault를 사용해 암호화된 형태로만 Git에 저장하세요.
마무리
ArgoCD는 Git을 중심으로 Kubernetes 배포를 선언적으로 관리하고, 자동 동기화·롤백·감사 추적을 제공하는 GitOps 도구입니다. Application CRD 설정, Sync Policy, Helm 연동, App of Apps 패턴, 그리고 Sync Hooks를 조합하면 팀 규모와 상관없이 안정적이고 추적 가능한 배포 파이프라인을 구축할 수 있습니다.
Kubernetes 배포 자동화를 더 깊이 다루고 싶다면, Helm Chart 실전 가이드와 GitHub Actions CI/CD 파이프라인 설계 가이드도 함께 참고해보세요.
ArgoCD Application 설정 템플릿이 필요하신가요?
이 글에서 다룬 Sync Policy, Helm values 연동, App of Apps 구조를 바로 쓸 수 있는 YAML 템플릿 세트를 준비했습니다. 아래 댓글로 “ArgoCD 템플릿”이라고 남겨주시면 보내드립니다.