안녕하세요, 자바파커입니다.
"누가 언제 뭘 배포했는지 기억이 안 납니다.
kubectl apply명령을 터미널 히스토리에서 뒤져야 합니다."
솔직히 저도 그랬습니다. 소규모 프로젝트 하나 돌리는데도 수동 apply가 쌓이면, 클러스터 상태와 Git 레포의 YAML이 조용히 어긋납니다. "운영에 긴급으로 꽂은 핫픽스"가 Git에는 없고, 한 달 뒤 누가 그 YAML을 다시 apply하면 그 핫픽스가 증발합니다. 재현 불가능한 상태라는 게 이런 식으로 쌓입니다.
결론부터 말씀드리면 — ArgoCD는 "Git 레포를 진실의 원천으로 두고, 클러스터가 알아서 그 상태에 수렴하게 만드는" GitOps 컨트롤러입니다. 배포를 더 이상 kubectl apply로 하지 않고, Git에 push만 하면 ArgoCD가 감지해서 반영합니다. 핫픽스도 Git에 남고, 드리프트(drift)가 생기면 경고가 뜨거나 자동 복원됩니다. 오늘은 이 구조부터 실전 셋업·Sync 정책·Helm/Kustomize 조합·운영 팁까지 정리하겠습니다.
이전 편을 안 보셨다면 K8S에 대한 이해 · kubectl 실전 명령어 · k9s 완벽 가이드 · Helm 완벽 가이드부터 읽으시면 흐름이 이어집니다.
GitOps란? — 한 줄 정의와 기존 방식과의 차이
GitOps는 "시스템의 원하는 상태를 Git에 선언하고, 자동화 도구가 그 상태에 실제 시스템을 수렴시키는" 운영 방식입니다. 2017년 Weaveworks가 만든 용어지만 지금은 사실상 K8S 표준.
기존 CI/CD(Push 모델)와 GitOps(Pull 모델)의 차이:
| 항목 | 전통적 CD (Push) | GitOps (Pull) |
|---|---|---|
| 배포 트리거 | CI에서 kubectl apply 푸시 |
Git 변경을 클러스터 내 컨트롤러가 감지 |
| 자격 증명 | CI가 클러스터 권한 보유 → 외부 노출 | 컨트롤러가 클러스터 내부 → 외부 노출 X |
| 드리프트 감지 | 거의 불가능 | 자동 (원하는 상태 vs 실제 상태 비교) |
| 롤백 | 이전 이미지 재배포 수동 트리거 | Git revert 한 번 |
| 감사 로그 | CI 로그·명령 히스토리 조합 | Git 커밋 히스토리가 그대로 감사 로그 |
| 멀티 클러스터 | 환경별 CI 잡 중복 | 환경별 디렉토리·브랜치로 선언 |
핵심은 "클러스터가 Git을 구독한다"는 역전입니다.
ArgoCD란? — 한 줄 정의
ArgoCD는 쿠버네티스 전용 GitOps 컨트롤러입니다. CNCF Graduated 프로젝트(졸업 단계)로, 사실상 K8S GitOps 표준입니다.
- 선언: Git 레포에 K8S manifest(YAML·Helm·Kustomize) 저장
- 감지: ArgoCD가 주기적으로 레포를 풀(pull)
- 비교: 원하는 상태(Git) vs 실제 상태(클러스터) 차이 계산
- 수렴: 자동 또는 수동으로 Apply
CLI(argocd), 웹 UI, Kubernetes CRD(Application, AppProject) 세 가지 인터페이스를 모두 제공합니다.
ArgoCD 아키텍처 — 4개 컴포넌트
| 컴포넌트 | 역할 |
|---|---|
| API Server | 웹 UI·CLI 요청을 받는 gRPC/REST 서버, 인증·RBAC 처리 |
| Repository Server | Git 레포를 클론·캐시, manifest 렌더링 (Helm·Kustomize 포함) |
| Application Controller | 실제 동기화 엔진 — 비교·Apply·상태 추적 |
| Redis | 레퍼런스 데이터 캐시 (성능용) |
이 4개가 하나의 K8S 네임스페이스(argocd)에 Deployment로 돌고, 외부에서는 Ingress로 UI만 노출하는 게 일반적입니다.
핵심 개념 4가지 — Application, Project, Sync, Health
1) Application
"무엇을 어디에 배포할지" 선언한 CRD. ArgoCD에서 다루는 가장 작은 단위.
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: my-app-prod
namespace: argocd
spec:
project: default
source:
repoURL: https://github.com/javapark/k8s-manifests.git
targetRevision: main
path: apps/my-app/overlays/prod # Kustomize 오버레이
destination:
server: https://kubernetes.default.svc # 같은 클러스터
namespace: production
syncPolicy:
automated:
prune: true
selfHeal: true2) AppProject
RBAC·정책 경계. 여러 Application을 묶어서 "이 프로젝트는 이 Git 레포와 이 네임스페이스만 건드릴 수 있다"를 제한.
apiVersion: argoproj.io/v1alpha1
kind: AppProject
metadata:
name: platform
spec:
sourceRepos:
- https://github.com/javapark/k8s-manifests.git
destinations:
- server: https://kubernetes.default.svc
namespace: "production"
- server: https://kubernetes.default.svc
namespace: "staging"
clusterResourceWhitelist:
- group: ""
kind: "Namespace"팀·환경 단위로 권한 분리할 때 필수.
3) Sync
Git의 원하는 상태를 클러스터에 실제로 적용하는 동작. 수동 또는 자동.
- Manual Sync: 사용자가 UI/CLI에서
Sync클릭/명령 - Auto Sync: Git 변경 감지 시 자동 적용
prune: true— Git에서 지워진 리소스는 클러스터에서도 자동 삭제selfHeal: true— 클러스터에서 수동 수정된 내용을 Git 기준으로 자동 되돌림
4) Health / Sync Status
두 가지 상태를 별개로 추적합니다.
| 상태 종류 | 값 | 의미 |
|---|---|---|
| Sync Status | Synced |
클러스터 = Git |
OutOfSync |
차이 있음 (아직 Sync 전) | |
Unknown |
비교 불가 (초기 또는 오류) | |
| Health Status | Healthy |
모든 리소스 정상 |
Progressing |
배포 진행 중 | |
Degraded |
하나 이상 리소스 비정상 | |
Missing |
리소스 누락 |
실전 팁:
Synced + Degraded조합이 가장 위험합니다. "Git대로 적용했는데 앱이 죽어있다" → 이미지 태그 오류·리소스 부족 등 앱 자체 문제. 알림은 이 조합을 최우선으로 걸어두세요.
설치 — Helm 한 줄
# 네임스페이스 + Helm 설치
kubectl create namespace argocd
helm repo add argo https://argoproj.github.io/argo-helm
helm install argocd argo/argo-cd -n argocd
# 초기 admin 비밀번호 확인
kubectl -n argocd get secret argocd-initial-admin-secret \
-o jsonpath="{.data.password}" | base64 -d
# UI 접근 (port-forward로 임시 확인)
kubectl port-forward svc/argocd-server -n argocd 8080:443
# → https://localhost:8080 접속, 계정: adminCLI도 같이 설치:
# macOS
brew install argocd
# Linux (바이너리)
curl -sSL -o /usr/local/bin/argocd https://github.com/argoproj/argo-cd/releases/latest/download/argocd-linux-amd64
chmod +x /usr/local/bin/argocd
# 로그인
argocd login localhost:8080운영에서는 Helm values.yaml로 Ingress·SSO·노드셀렉터 등을 제대로 설정하세요. 기본 설치는 데모용입니다.
실전 — 첫 Application 배포까지
1단계: Git 레포 구조 준비
k8s-manifests/
└── apps/
└── my-app/
├── base/
│ ├── deployment.yaml
│ ├── service.yaml
│ └── kustomization.yaml
└── overlays/
├── staging/
│ ├── patch.yaml
│ └── kustomization.yaml
└── prod/
├── patch.yaml
└── kustomization.yaml2단계: Application 생성
argocd app create my-app-prod \
--repo https://github.com/javapark/k8s-manifests.git \
--path apps/my-app/overlays/prod \
--dest-server https://kubernetes.default.svc \
--dest-namespace production \
--sync-policy automated \
--auto-prune \
--self-heal또는 YAML(Application CRD)로 선언하고 kubectl apply — Application 자체도 GitOps로 관리하는 게 정석입니다 (이를 "App of Apps" 패턴이라 합니다).
3단계: 배포 확인
argocd app get my-app-prod
argocd app sync my-app-prod # 수동 sync (필요시)
argocd app logs my-app-prod # 해당 앱 Pod 로그
argocd app rollback my-app-prod 3 # 3번째 리비전으로 롤백UI(https://localhost:8080)에서는 트리 형태로 Deployment → ReplicaSet → Pod까지 시각화됩니다. k9s와는 다른 축의 시각화라 둘 다 쓰는 게 편합니다.
Helm / Kustomize 조합 — 실무의 80%
ArgoCD는 Git 레포 안에서 자동으로 Helm Chart·Kustomize를 감지합니다.
Helm Chart를 ArgoCD로 배포
spec:
source:
repoURL: https://github.com/javapark/k8s-manifests.git
targetRevision: main
path: charts/my-app
helm:
valueFiles:
- values.yaml
- values-prod.yaml
parameters:
- name: image.tag
value: v1.2.4외부 Helm 리포도 가능:
spec:
source:
repoURL: https://charts.bitnami.com/bitnami
chart: nginx
targetRevision: 15.4.4
helm:
valueFiles:
- $values/charts/nginx/values-prod.yaml
sources: # 멀티 소스 — chart는 bitnami, values는 내 레포
- repoURL: https://charts.bitnami.com/bitnami
chart: nginx
targetRevision: 15.4.4
- repoURL: https://github.com/javapark/k8s-manifests.git
targetRevision: main
ref: valuesKustomize
overlay 경로만 지정하면 끝:
spec:
source:
path: apps/my-app/overlays/prod
# ArgoCD가 kustomization.yaml을 자동 인식Helm vs Kustomize 선택 기준은 이전 Helm 편에서 다뤘습니다. ArgoCD는 둘 다 native 지원하므로 팀 취향대로 가시면 됩니다.
Sync 정책 상세 — Auto-Sync, Prune, Self-Heal
| 옵션 | 효과 | 운영 권장 |
|---|---|---|
automated |
Git 변경 감지 시 자동 Sync | dev/staging: ✓ / prod: 초기엔 manual, 익숙해지면 ✓ |
prune |
Git에서 삭제된 리소스를 클러스터에서도 삭제 | 실수 방지 위해 PR 병합 단계에서만 허용 |
selfHeal |
누군가 kubectl edit로 수동 변경한 걸 Git 상태로 자동 복원 |
prod 필수. "Git이 진실"을 강제하는 핵심 기능 |
selfHeal: true가 GitOps의 꽃입니다. 이게 있으면 "운영에서 kubectl edit으로 대충 고쳐놓고 Git에 반영 안 함" 패턴이 원천 차단됩니다.
Sync Waves — 순서가 중요한 경우
argocd.argoproj.io/sync-wave 애노테이션으로 리소스별 적용 순서를 지정:
metadata:
annotations:
argocd.argoproj.io/sync-wave: "-1" # 먼저 적용예: Namespace(wave -2) → ConfigMap(wave -1) → Deployment(wave 0) 순으로 보장.
Sync Hooks — DB 마이그레이션 등
Pre-Sync, Sync, Post-Sync, Sync-Fail 훅으로 Job을 끼워넣을 수 있습니다. DB 스키마 마이그레이션에 유용:
metadata:
annotations:
argocd.argoproj.io/hook: PreSync
argocd.argoproj.io/hook-delete-policy: HookSucceededApp of Apps — ArgoCD 자기 자신 관리하기
하나의 "부모" Application이 여러 자식 Application을 Git에서 관리하는 패턴.
k8s-manifests/
└── apps/
├── _bootstrap/
│ └── applications.yaml # 부모 App — apps/children/*.yaml 을 감시
└── children/
├── nginx.yaml # Application (nginx)
├── redis.yaml # Application (redis)
└── monitoring.yaml # Application (prometheus + grafana)장점:
- 새 서비스 추가 = YAML 한 개 PR. ArgoCD가 알아서 감지·배포
- ArgoCD 자체 설정도 Git으로 관리 (재설치·클러스터 이관 시 스크립트 재실행 X)
운영 클러스터 1개당 부모 App 1개 두는 게 표준 패턴입니다.
멀티 클러스터 운영
ArgoCD 한 인스턴스가 여러 클러스터를 관리할 수 있습니다.
# 클러스터 등록
argocd cluster add staging-cluster-context
argocd cluster add prod-cluster-context
# 확인
argocd cluster listApplication의 destination.server만 클러스터 URL로 지정하면:
destination:
server: https://staging-cluster.example.com
namespace: default관리 클러스터는 ArgoCD 없음, 중앙 ArgoCD가 푸시하는 구조 — 이걸 Hub-and-Spoke라고 합니다. 소규모에선 단일 클러스터 1:1이 충분하지만, 3개 이상 되면 Hub 구조가 관리 비용을 크게 낮춥니다.
보안·운영 팁 5가지
1) UI·API는 SSO 뒤에
기본 admin 계정은 로컬 전용. 운영에선 Google/GitHub/SAML OIDC 연동. argocd-cm ConfigMap에 설정:
data:
dex.config: |
connectors:
- type: oidc
id: google
name: Google
config:
issuer: https://accounts.google.com
clientID: ...2) RBAC는 AppProject로
팀별 Project 분리 + argocd-rbac-cm으로 역할 정의. "dev 팀은 dev namespace만" 같은 강제.
3) Notifications — Slack / Telegram 알림
argocd-notifications 컨트롤러로 Sync 실패·Degraded 시 알림.
# 예: Telegram
service.telegram: |
token: $telegram-token
chatIDs: ["-100123..."]4) Image Updater — 이미지 자동 갱신
argocd-image-updater 애드온. 컨테이너 레지스트리를 폴링해 새 이미지 태그를 Git에 자동 PR·커밋. Git push → ArgoCD sync가 연쇄로 일어나 완전 자동화 가능.
5) 진실의 원천은 Git 하나만
"긴급하니 kubectl edit" 유혹이 오는 순간이 반드시 옵니다. 그때마다 selfHeal이 되돌릴 것을 기억하세요. 진짜 긴급이면 Git에 핫픽스 커밋 후 sync — 1분이면 됩니다.
자주 겪는 이슈 3가지
1) "Sync는 됐는데 Health가 Degraded"
→ 앱 자체 문제. Pod logs·events 확인. ArgoCD는 "Git대로 뿌렸을 뿐" — 앱이 죽는 이유는 Git 상태 밖의 문제(이미지 손상·환경변수 오타·외부 의존성).
2) "Sync가 무한 반복된다"
→ 컨트롤러나 defaulting webhook이 자동으로 필드를 추가하는데 Git에 없어서 OutOfSync가 계속 뜸. ignoreDifferences로 특정 필드 제외:
spec:
ignoreDifferences:
- group: apps
kind: Deployment
jsonPointers:
- /spec/replicas # HPA가 관리하는 replicas 무시3) "Prune으로 중요한 리소스가 지워졌다"
→ automated.prune: true의 위험. 학습 단계에선 syncPolicy.syncOptions: [Validate=true, Prune=false] 로 끄고, 수동 sync 때만 --prune 명시. 익숙해지면 자동화.
FAQ
Q. Flux와 ArgoCD 중 뭘 써야 하나요?
둘 다 GitOps 표준, 기능 유사. 차이:
- ArgoCD: 강력한 UI, 멀티 테넌시 · 멀티 클러스터에 강함, 학습 곡선 완만
- Flux: UI 없음(별도 도구 연동), Helm 네이티브 통합, 경량, Kustomize 생태계에 밀착
입문은 ArgoCD 추천. UI가 있어서 감 잡기 쉽고, 팀에 공유하기도 편합니다.
Q. CI(GitHub Actions)와 역할 분담이 궁금합니다.
명확히 나뉩니다.
- CI: 빌드·테스트·이미지 푸시 → 성공 시 manifest 레포의 이미지 태그 업데이트 PR
- CD: ArgoCD가 manifest 레포 변경을 감지 → sync
CI가 더 이상 kubectl apply를 치지 않아서 클러스터 접근 권한을 CI에 줄 필요가 없어집니다. 보안 관점에서 큰 개선.
Q. 선언형 대신 CLI로만 배포해도 되나요?
argocd app create ...로 가능하지만 Application 자체를 Git에 YAML로 넣는 게 원칙입니다. 그래야 ArgoCD 재설치·백업 복원·클러스터 이관이 자동화됩니다. 처음엔 CLI로 실험하고 운영은 Application YAML로.
Q. Application 수가 많아지면?
ApplicationSet이라는 상위 CRD를 쓰세요. Git 디렉토리 패턴·클러스터 리스트·Pull Request 기반으로 Application을 자동 생성합니다. 마이크로서비스 수십 개 있는 조직에서 필수.
마무리 — 다음 단계
ArgoCD를 붙이면 K8S 운영의 질적 전환이 일어납니다. "Git에 뭔가 있는 것"과 "실제 돌고 있는 것"이 일치하는 상태가 기본값이 되고, 배포 실수의 대부분이 구조적으로 차단됩니다.
오늘 정리 핵심:
- GitOps는 "Git을 진실의 원천, 컨트롤러가 클러스터를 수렴" 시키는 운영 방식
- ArgoCD 핵심 CRD: Application · AppProject · (ApplicationSet)
- Sync Status와 Health Status는 별개 — Degraded + Synced 조합에 주목
selfHeal: true가 GitOps의 진짜 가치- Helm·Kustomize는 ArgoCD에서 native 지원 — 둘 중 하나 고르면 됨
- Application 자체도 Git으로 관리 (App of Apps) — 운영 성숙도의 지표
시리즈 다음 주제
- kustomize로 환경별 YAML 관리 (Helm과 비교·조합)
- HPA·VPA로 오토스케일링 구성
- Ingress + cert-manager로 HTTPS 자동화
- Prometheus + Grafana 모니터링 스택
- ArgoCD ApplicationSet 심화 — 멀티 클러스터 대규모 운영
여러분은 ArgoCD를 도입하면서 가장 큰 장벽이 뭐였나요? "운영에서 kubectl edit 습관 못 버리는 것"이 1위일 거라 예상합니다. 댓글로 공유해주시면 다음 편에 반영하겠습니다.