ArgoCD ApplicationSet으로 멀티 클러스터 GitOps 자동화하기
클러스터가 3개를 넘어가면서 ArgoCD Application 매니페스트를 하나하나 만들어 관리하는 게 현실적으로 불가능해진 경험이 있을 것이다. dev, staging, production에 각각 마이크로서비스 10개만 배포해도 Application YAML이 30개다. 여기에 리전별 클러스터까지 추가되면 관리 포인트가 기하급수적으로 늘어난다.
ArgoCD ApplicationSet Controller는 이 문제를 정면으로 해결한다. 템플릿 하나로 여러 클러스터, 여러 환경에 Application을 자동 생성하고 라이프사이클까지 관리할 수 있다. 이 글에서는 실무에서 바로 적용할 수 있는 ApplicationSet 패턴들을 다룬다.
ApplicationSet이 필요한 이유
기존 방식에서는 새 클러스터를 추가할 때마다 다음 작업이 필요했다:
- 클러스터를 ArgoCD에 등록
- 해당 클러스터용 Application YAML을 서비스 수만큼 생성
- values 파일에 클러스터별 설정 반영
- PR 올리고 리뷰 받고 머지
ApplicationSet을 사용하면 클러스터 등록만 하면 나머지가 자동으로 처리된다. Generator가 클러스터 목록을 감지하고, 템플릿에 따라 Application을 자동 생성한다.
Cluster Generator: 등록된 클러스터 자동 감지
가장 기본적이면서 강력한 패턴이다. ArgoCD에 등록된 모든 클러스터에 동일한 앱을 배포한다.
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: monitoring-stack
namespace: argocd
spec:
goTemplate: true
goTemplateOptions: ["missingkey=error"]
generators:
- clusters:
selector:
matchLabels:
env: production
template:
metadata:
name: 'monitoring-{{.name}}'
spec:
project: infrastructure
source:
repoURL: https://github.com/my-org/k8s-manifests.git
targetRevision: main
path: 'monitoring/overlays/{{.metadata.labels.region}}'
destination:
server: '{{.server}}'
namespace: monitoring
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true
핵심 포인트는 clusters generator가 ArgoCD에 등록된 클러스터의 Secret 리소스를 읽어서 자동으로 목록을 만든다는 것이다. selector로 라벨 기반 필터링이 가능하므로, 클러스터 등록 시 env: production, region: ap-northeast-2 같은 라벨을 붙여두면 된다.
Git Generator: 디렉토리 구조 기반 자동 생성
모노레포에서 디렉토리 하나가 서비스 하나를 의미하는 구조라면 Git Generator가 적합하다.
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: microservices
namespace: argocd
spec:
goTemplate: true
goTemplateOptions: ["missingkey=error"]
generators:
- git:
repoURL: https://github.com/my-org/k8s-manifests.git
revision: main
directories:
- path: 'services/*'
- path: 'services/deprecated-*'
exclude: true
template:
metadata:
name: '{{.path.basename}}'
spec:
project: default
source:
repoURL: https://github.com/my-org/k8s-manifests.git
targetRevision: main
path: '{{.path.path}}'
destination:
server: https://kubernetes.default.svc
namespace: '{{.path.basename}}'
syncPolicy:
automated:
prune: true
selfHeal: true
services/ 하위에 order-api/, payment-api/ 같은 디렉토리를 만들기만 하면 Application이 자동 생성된다. exclude 패턴으로 deprecated 서비스를 제외할 수도 있다.
Matrix Generator: 클러스터 × 서비스 조합
실무에서 가장 많이 쓰는 패턴이다. 여러 클러스터에 여러 서비스를 배포할 때 두 Generator의 카테시안 곱을 만든다.
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: platform-services
namespace: argocd
spec:
goTemplate: true
goTemplateOptions: ["missingkey=error"]
generators:
- matrix:
generators:
- clusters:
selector:
matchLabels:
tier: platform
- git:
repoURL: https://github.com/my-org/k8s-manifests.git
revision: main
directories:
- path: 'platform/*'
template:
metadata:
name: '{{.name}}-{{.path.basename}}'
labels:
cluster: '{{.name}}'
service: '{{.path.basename}}'
spec:
project: platform
source:
repoURL: https://github.com/my-org/k8s-manifests.git
targetRevision: main
path: '{{.path.path}}'
helm:
valueFiles:
- 'values.yaml'
- 'values-{{.metadata.labels.env}}.yaml'
destination:
server: '{{.server}}'
namespace: '{{.path.basename}}'
syncPolicy:
automated:
prune: true
selfHeal: true
retry:
limit: 3
backoff:
duration: 5s
factor: 2
maxDuration: 3m
클러스터 3개 × 서비스 5개면 Application 15개가 자동 생성된다. 클러스터나 서비스를 추가할 때 별도 작업 없이 자동 반영된다.
운영 시 주의사항
syncPolicy.automated.prune 설정에 주의하라. Generator에서 클러스터나 디렉토리가 빠지면 해당 Application이 삭제되고, prune이 켜져 있으면 배포된 리소스까지 삭제된다. 실수로 Git 디렉토리를 지웠다가 프로덕션 서비스가 내려가는 사고가 발생할 수 있다. 프로덕션 환경에서는 preserveResourcesOnDeletion: true를 반드시 설정하자.
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true
preserveResourcesOnDeletion: true # Application 삭제 시 리소스 보존
Progressive Sync를 활용하라. ApplicationSet v0.14+에서는 롤링 업데이트처럼 순차적 동기화가 가능하다.
spec:
strategy:
type: RollingSync
rollingSync:
steps:
- matchExpressions:
- key: env
operator: In
values:
- staging
- matchExpressions:
- key: env
operator: In
values:
- production
maxUpdate: 25%
staging 클러스터를 먼저 동기화하고, 성공 후 production을 25%씩 순차 배포한다. 카나리 배포와 유사한 안전장치를 클러스터 레벨에서 구현할 수 있다.
리소스 이름 충돌을 방지하라. ApplicationSet이 생성하는 Application 이름이 기존 Application과 겹치면 충돌이 발생한다. 네이밍 컨벤션을 {cluster}-{service} 또는 {env}-{region}-{service} 형태로 통일하고, metadata.name 템플릿에 반영하자.
마무리
ApplicationSet은 멀티 클러스터 GitOps의 복잡도를 획기적으로 줄여주는 도구다. Cluster Generator로 클러스터 자동 감지, Git Generator로 서비스 자동 등록, Matrix Generator로 조합 자동화까지 — 규모가 커질수록 효과가 극대화된다.
다만 자동화 범위가 넓은 만큼 prune 정책과 Progressive Sync를 반드시 함께 설정해 안전장치를 마련해야 한다. 시작은 dev 환경에서 Cluster Generator 하나로 시작하고, 점차 Matrix Generator와 Progressive Sync로 확장해 나가는 것을 권장한다.
추가 리소스: