01편에서 GitOps의 Pull 모델을 살펴봤습니다. 이제 이 패러다임을 실제로 돌리는 엔진인 ArgoCD의 내부를 열어볼 차례입니다. 겉보기엔 단일 제품이지만 안에는 각자 다른 일을 맡은 5개의 컴포넌트가 협업합니다. 각 컴포넌트가 왜 분리됐는지, 어디에서 병목이 생기는지 이해해두면 장애 대응이나 스케일링 설계가 훨씬 쉬워집니다
전체 그림
flowchart TB
USER["사용자·CLI·UI"]
GIT[("Git Repository")]
K8S[("Kubernetes API")]
subgraph argocd ["ArgoCD Namespace"]
SERVER["argocd-server<br/>(API·UI)"]
REPO["argocd-repo-server<br/>(Manifest 생성)"]
CTRL["application-controller<br/>(Reconcile Loop)"]
DEX["argocd-dex-server<br/>(SSO)"]
REDIS[("Redis<br/>(Cache)")]
end
USER -->|"HTTPS·gRPC"| SERVER
SERVER --> REDIS
SERVER --> DEX
SERVER --> REPO
CTRL --> REPO
CTRL --> REDIS
CTRL -->|"apply / patch"| K8S
REPO -.->|"git fetch"| GIT
classDef primary fill:#2563eb,stroke:#1e40af,color:#ffffff
classDef success fill:#059669,stroke:#047857,color:#ffffff
classDef info fill:#0891b2,stroke:#0e7490,color:#ffffff
classDef neutral fill:#475569,stroke:#334155,color:#ffffff
class USER primary
class SERVER,CTRL success
class REPO,DEX info
class REDIS,GIT,K8S neutral
요청 흐름은 크게 두 갈래입니다. 사용자 흐름은 argocd-server를 거쳐 UI·CLI를 처리하고, 조정 흐름은 application-controller가 주기적으로 repo-server에서 매니페스트를 뽑아 클러스터 상태와 비교합니다. Redis는 양쪽이 공유하는 캐시 레이어입니다
컴포넌트별 역할
| 컴포넌트 | 핵심 책임 | 주요 장애 증상 |
|---|---|---|
| argocd-server | REST·gRPC API, Web UI, 인증 프록시 | UI 접속 불가, CLI 타임아웃 |
| argocd-repo-server | Git clone, Helm·Kustomize 렌더링 | Sync 시 “manifest generation failed” |
| application-controller | Desired vs Live 비교, Sync 실행 | OutOfSync 상태가 해소되지 않음 |
| argocd-dex-server | OIDC·SAML·LDAP SSO 브로커 | SSO 로그인 실패 (로컬 로그인은 가능) |
| redis | 세션·매니페스트 캐시 | 전반적 응답 느려짐, 반복 git fetch |
argocd-server
API 게이트웨이이자 UI 호스트입니다. 자체적으로 권한 검사(RBAC)를 수행하고, 뒤에 있는 controller·repo-server로 요청을 중계합니다. stateless해서 수평 확장이 자유로운 유일한 컴포넌트입니다. 트래픽이 많으면 Deployment의 replicas만 늘리면 됩니다
argocd-repo-server
Git 리포지토리를 clone해서 최종 매니페스트를 만드는 빌더 역할입니다. Helm chart 렌더링, Kustomize overlay 적용, plain YAML 추출까지 전부 여기서 처리합니다. 무거운 연산이 집중되므로 대규모 환경에서는 이 컴포넌트가 가장 먼저 병목이 됩니다
application-controller
ArgoCD의 심장입니다. StatefulSet으로 배포되고, 각 Application 리소스를 감시하면서 다음 루프를 무한히 돌립니다
stateDiagram-v2
[*] --> Watching
Watching --> Comparing: 주기(default 3분) 또는 웹훅
Comparing --> InSync: Desired == Live
Comparing --> OutOfSync: 차이 감지
OutOfSync --> Syncing: auto-sync 또는 수동 Sync
Syncing --> Healthy: apply 성공
Syncing --> Degraded: apply 실패
Healthy --> Watching
Degraded --> Watching
InSync --> Watching
컨트롤러가 클러스터 kube-apiserver에 실제로 변경을 가하는 유일한 주체라는 점이 중요합니다. server나 repo-server는 쓰기 권한이 없습니다
argocd-dex-server
기업 환경에서는 로컬 계정 대신 Google Workspace·Okta·Keycloak 같은 IdP를 붙이는 게 일반적인데, 그걸 중계하는 어댑터입니다. SSO를 안 쓰면 꺼도 되는 유일한 컴포넌트입니다
Redis
세션 토큰, git 매니페스트 캐시, 애플리케이션 상태 캐시를 담습니다. controller와 server가 직접 Kubernetes API를 반복 호출하지 않도록 완충하는 역할입니다. HA 구성에서는 Redis도 Sentinel·Cluster 모드로 이중화해야 합니다 — 여기가 단일 장애점이 되면 전체 UI·CLI가 먹통이 됩니다
데이터 흐름으로 다시 보기
사용자가 UI에서 “Sync” 버튼을 눌렀을 때 내부에서 벌어지는 일을 시간 순으로 따라가 보겠습니다
sequenceDiagram
participant U as 사용자
participant S as argocd-server
participant C as application-controller
participant R as repo-server
participant G as Git
participant K as K8s API
U->>S: Sync 요청 (gRPC)
S->>C: Sync 작업 위임
C->>R: 최신 매니페스트 요청
R->>G: git fetch
G-->>R: commit SHA · files
R-->>C: 렌더링된 YAML
C->>K: 현재 Live 상태 조회
K-->>C: Live manifests
C->>C: Diff 계산
C->>K: kubectl apply (변경분만)
K-->>C: apply 결과
C-->>S: Sync 완료 이벤트
S-->>U: UI 업데이트
여기서 눈여겨볼 점은 argocd-server가 직접 변경을 가하지 않고 controller에 위임만 한다는 것입니다. 이 분리 덕분에 server가 재시작되어도 진행 중인 Sync는 controller에서 그대로 이어집니다
HA 구성 시 주의점
프로덕션에서는 기본 설치 매니페스트만으론 부족합니다. 각 컴포넌트마다 확장 전략이 달라서, 한 곳만 늘려도 병목이 다른 데로 옮겨갑니다
| 컴포넌트 | 확장 방식 | 주의점 |
|---|---|---|
| argocd-server | Deployment replicas 증가 | stateless라 자유로움 |
| repo-server | Deployment replicas 증가 | 대형 Helm 차트가 있으면 메모리 여유 필요 |
| application-controller | Sharding (0.9+) | replicas만 늘리면 안 됨, controller.sharding.replicas 설정 |
| redis | HA 모드 (Sentinel) | 단일 노드면 SPOF |
정리
ArgoCD의 컴포넌트 구성은 “누가 읽고, 누가 쓰고, 누가 결정하는가”를 철저히 분리한 설계입니다. 이 분리 덕분에 특정 컴포넌트가 느려지거나 죽어도 전체 기능이 한꺼번에 멈추지 않습니다
- argocd-server: 외부 창구 (stateless)
- repo-server: 매니페스트 빌더 (scale-out 대상)
- application-controller: 조정 엔진 (sharding 필요)
- dex-server: SSO 선택 컴포넌트
- redis: 공유 캐시 (HA 필수)
다음 글에서는 이 아키텍처 위에서 실제 배포 단위인 Application 리소스와 동기화 전략을 다룹니다. manual·auto sync, self-heal, sync wave 같은 옵션들이 어떻게 맞물리는지 보여드릴게요