- Authors

- Name
- Youngju Kim
- @fjvbn20031
- 1. ApplicationSet 개요
- 2. Generator 유형 상세
- 3. 템플릿 렌더링 엔진
- 4. Progressive Sync (단계적 동기화)
- 5. Cluster Decision Resource
- 6. Reconciliation Loop
- 7. Application 생명주기 관리
- 8. 실전 패턴
- 9. 트러블슈팅
- 10. 정리
1. ApplicationSet 개요
ApplicationSet은 ArgoCD의 확장 컨트롤러로, 하나의 ApplicationSet 리소스에서 여러 ArgoCD Application을 자동으로 생성하고 관리합니다. 대규모 멀티클러스터, 멀티테넌트 환경에서 수백 개의 Application을 효율적으로 관리할 수 있습니다.
핵심 구성 요소
ApplicationSet Controller
|
+-- Generator: Application 목록 생성을 위한 데이터 소스
|
+-- Template: Application 리소스의 템플릿
|
+-- Sync Policy: Application 생성/삭제/업데이트 정책
ApplicationSet 기본 구조
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: my-appset
namespace: argocd
spec:
generators:
- list:
elements:
- cluster: staging
url: https://staging.example.com
- cluster: production
url: https://production.example.com
template:
metadata:
name: 'myapp-{{cluster}}'
spec:
project: default
source:
repoURL: https://github.com/org/myapp.git
targetRevision: HEAD
path: 'overlays/{{cluster}}'
destination:
server: '{{url}}'
namespace: myapp
2. Generator 유형 상세
List Generator
가장 단순한 Generator로, 정적 목록에서 파라미터를 생성합니다:
spec:
generators:
- list:
elements:
- cluster: staging
url: https://staging.example.com
revision: develop
- cluster: production
url: https://production.example.com
revision: main
사용 사례: 소수의 명시적 환경을 관리할 때
Cluster Generator
ArgoCD에 등록된 클러스터를 기반으로 Application을 생성합니다:
spec:
generators:
- clusters:
selector:
matchLabels:
env: production
region: ap-northeast-2
Cluster Generator의 파라미터:
| 파라미터 | 설명 |
|---|---|
| name | 클러스터 이름 |
| server | 클러스터 API 서버 URL |
| metadata.labels | 클러스터에 설정된 레이블 |
| metadata.annotations | 클러스터에 설정된 어노테이션 |
로컬 클러스터(in-cluster) 처리:
# 로컬 클러스터를 포함하려면 명시적으로 설정
spec:
generators:
- clusters:
selector:
matchLabels:
env: production
# 값이 비어있는 셀렉터는 모든 클러스터 매칭 (로컬 포함)
Git Generator - Directory
Git 저장소의 디렉토리 구조를 스캔하여 Application을 생성합니다:
spec:
generators:
- git:
repoURL: https://github.com/org/gitops-config.git
revision: HEAD
directories:
- path: apps/*
- path: apps/excluded-app
exclude: true
생성되는 파라미터:
| 파라미터 | 예시 |
|---|---|
| path | apps/frontend |
| path.basename | frontend |
| path[0] | apps |
| path[1] | frontend |
| path.basenameNormalized | frontend (RFC 1123 호환) |
디렉토리 구조 예시:
gitops-config/
apps/
frontend/
kustomization.yaml
backend/
kustomization.yaml
database/
kustomization.yaml
각 디렉토리에 대해 별도의 Application이 자동 생성됩니다.
Git Generator - File
Git 저장소의 JSON/YAML 파일에서 파라미터를 읽어 Application을 생성합니다:
spec:
generators:
- git:
repoURL: https://github.com/org/gitops-config.git
revision: HEAD
files:
- path: 'clusters/*/config.json'
config.json 파일 예시:
{
"cluster": {
"name": "production-east",
"server": "https://prod-east.example.com",
"environment": "production",
"region": "us-east-1"
}
}
템플릿에서 중첩 필드 참조:
template:
metadata:
name: 'app-{{cluster.name}}'
spec:
destination:
server: '{{cluster.server}}'
Matrix Generator
두 Generator를 결합하여 카테시안 곱(Cartesian Product)을 생성합니다:
spec:
generators:
- matrix:
generators:
# Generator 1: 클러스터 목록
- clusters:
selector:
matchLabels:
env: production
# Generator 2: 앱 디렉토리 목록
- git:
repoURL: https://github.com/org/apps.git
revision: HEAD
directories:
- path: apps/*
결과 예시:
(cluster=prod-east, path=apps/frontend)
(cluster=prod-east, path=apps/backend)
(cluster=prod-west, path=apps/frontend)
(cluster=prod-west, path=apps/backend)
각 조합에 대해 Application이 생성됩니다.
Merge Generator
여러 Generator의 결과를 공통 키로 병합합니다:
spec:
generators:
- merge:
mergeKeys:
- server
generators:
# 기본 Generator: 모든 클러스터
- clusters:
values:
replicas: '3'
env: default
# 오버라이드 Generator: 특정 클러스터 설정
- list:
elements:
- server: https://production.example.com
values.replicas: '5'
values.env: production
server 키가 일치하는 항목에 대해 오버라이드 값이 적용됩니다.
PullRequest Generator
Git 호스팅 서비스의 PR을 감지하여 프리뷰 환경을 자동 생성합니다:
spec:
generators:
- pullRequest:
github:
owner: myorg
repo: myapp
labels:
- preview
requeueAfterSeconds: 60
template:
metadata:
name: 'preview-{{branch}}-{{number}}'
spec:
source:
repoURL: https://github.com/myorg/myapp.git
targetRevision: '{{head_sha}}'
path: deploy/preview
destination:
server: https://kubernetes.default.svc
namespace: 'preview-{{number}}'
PullRequest Generator 파라미터:
| 파라미터 | 설명 |
|---|---|
| number | PR 번호 |
| branch | 소스 브랜치 이름 |
| branch_slug | URL 안전한 브랜치 이름 |
| head_sha | HEAD 커밋 SHA |
| head_short_sha | 짧은 HEAD SHA |
| labels | PR에 부여된 레이블 |
SCMProvider Generator
SCM(Source Code Management) 프로바이더에서 저장소를 자동 발견합니다:
spec:
generators:
- scmProvider:
github:
organization: myorg
allBranches: false
filters:
- repositoryMatch: '^gitops-.*'
pathsExist:
- deploy/kustomization.yaml
지원 SCM 프로바이더:
- GitHub
- GitLab
- Bitbucket Server
- Azure DevOps
- Gitea
3. 템플릿 렌더링 엔진
기본 템플릿 문법
ApplicationSet은 이중 중괄호 문법으로 파라미터를 참조합니다. 이 문법은 Generator가 제공하는 값으로 치환됩니다.
template:
metadata:
name: 'app-{{cluster}}-{{path.basename}}'
labels:
env: '{{values.env}}'
spec:
source:
repoURL: '{{url}}'
path: '{{path}}'
destination:
server: '{{server}}'
namespace: '{{namespace}}'
Go 템플릿 모드
더 복잡한 로직이 필요한 경우 Go 템플릿을 사용할 수 있습니다:
spec:
goTemplate: true
goTemplateOptions: ['missingkey=error']
template:
metadata:
name: 'app-{{ .cluster | lower }}'
spec:
source:
path: '{{ if eq .env "production" }}overlays/prod{{ else }}overlays/dev{{ end }}'
Go 템플릿에서 사용 가능한 함수:
| 함수 | 설명 | 예시 |
|---|---|---|
| lower | 소문자 변환 | {{ .name | lower }} |
| upper | 대문자 변환 | {{ .name | upper }} |
| normalize | RFC 1123 정규화 | {{ .name | normalize }} |
| toJson | JSON으로 변환 | {{ .data | toJson }} |
| default | 기본값 설정 | {{ .value | default "3" }} |
fasttemplate vs Go 템플릿 비교
| 특성 | fasttemplate (기본) | Go 템플릿 |
|---|---|---|
| 문법 | 이중 중괄호 (변수 치환만) | Go template 전체 문법 |
| 조건문 | 불가 | 가능 (if/else) |
| 반복문 | 불가 | 가능 (range) |
| 함수 | 불가 | Sprig 함수 사용 가능 |
| 성능 | 빠름 | 상대적으로 느림 |
| 설정 | 기본값 | goTemplate: true 필요 |
4. Progressive Sync (단계적 동기화)
Rolling Sync 전략
ApplicationSet은 여러 Application을 단계적으로 동기화하는 기능을 제공합니다:
spec:
strategy:
type: RollingSync
rollingSync:
steps:
- matchExpressions:
- key: env
operator: In
values:
- staging
maxUpdate: 100% # staging 환경 먼저 전부 업데이트
- matchExpressions:
- key: env
operator: In
values:
- production
maxUpdate: 25% # production은 25%씩 업데이트
Progressive Sync 동작 원리
Step 1: staging 레이블이 있는 모든 Application 동기화
-> 모든 Application이 Healthy가 될 때까지 대기
Step 2: production 레이블이 있는 Application 중 25%만 동기화
-> Healthy 확인 후 다음 25% 진행
-> 모든 production Application이 완료될 때까지 반복
maxUpdate 옵션
| 값 | 설명 |
|---|---|
| 100% | 매칭되는 모든 Application을 동시에 업데이트 |
| 25% | 매칭되는 Application의 25%만 업데이트 |
| 1 | 한 번에 1개만 업데이트 |
| 0 | 자동 업데이트 없음 (수동으로 진행) |
5. Cluster Decision Resource
개요
Cluster Decision Resource는 외부 컨트롤러가 Application의 대상 클러스터를 결정하도록 위임하는 메커니즘입니다:
spec:
generators:
- clusterDecisionResource:
configMapRef: my-placement-decision
name: placement-decision
requeueAfterSeconds: 180
사용 사례
- Open Cluster Management (OCM)의 Placement Decision 연동
- 커스텀 클러스터 선택 로직 구현
- 외부 정책 엔진 기반의 클러스터 라우팅
6. Reconciliation Loop
ApplicationSet Controller의 Reconciliation
반복:
1. 모든 ApplicationSet 리소스 감시 (Informer)
2. 각 ApplicationSet에 대해:
a. Generator 실행하여 파라미터 집합 생성
b. 템플릿을 렌더링하여 원하는 Application 목록 생성
c. 현재 존재하는 Application 목록 조회
d. 비교하여:
- 새로 추가할 Application 생성
- 변경된 Application 업데이트
- 제거 대상 Application 삭제 (정책에 따라)
3. requeueAfterSeconds 후 재실행
Requeue 메커니즘
spec:
generators:
- pullRequest:
github:
owner: myorg
repo: myapp
requeueAfterSeconds: 60 # 60초마다 PR 상태를 다시 확인
requeueAfterSeconds는 Generator의 데이터 소스가 변경되었는지 주기적으로 확인합니다. Webhook을 사용할 수 없는 경우에 특히 유용합니다.
Event-Driven Reconciliation
ApplicationSet Controller는 다음 이벤트에 반응하여 즉시 reconciliation을 수행합니다:
- ApplicationSet 리소스 변경
- ArgoCD 클러스터 Secret 변경
- Git Webhook 수신 (Git Generator)
7. Application 생명주기 관리
생성 정책
spec:
syncPolicy:
preserveResourcesOnDeletion: false # ApplicationSet 삭제 시 Application도 삭제
업데이트 정책
ApplicationSet은 다음 상황에서 Application을 업데이트합니다:
- Generator 파라미터가 변경된 경우
- 템플릿이 변경된 경우
- ApplicationSet 자체가 수정된 경우
삭제 정책
spec:
syncPolicy:
preserveResourcesOnDeletion: true # ApplicationSet 삭제해도 Application 유지
| 옵션 | 동작 |
|---|---|
| preserveResourcesOnDeletion: false | ApplicationSet 삭제 시 모든 Application도 삭제 |
| preserveResourcesOnDeletion: true | ApplicationSet 삭제해도 Application은 유지 |
Orphan Application 처리
Generator가 더 이상 특정 Application을 생성하지 않으면:
- 기본: 해당 Application을 삭제
preserveResourcesOnDeletion: true: Application 유지
8. 실전 패턴
멀티클러스터 배포
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: platform-services
namespace: argocd
spec:
generators:
- matrix:
generators:
- clusters:
selector:
matchLabels:
tier: production
- git:
repoURL: https://github.com/org/platform.git
revision: HEAD
directories:
- path: services/*
template:
metadata:
name: '{{name}}-{{path.basename}}'
spec:
project: platform
source:
repoURL: https://github.com/org/platform.git
targetRevision: HEAD
path: '{{path}}'
destination:
server: '{{server}}'
namespace: '{{path.basename}}'
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true
PR 프리뷰 환경
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: preview-envs
namespace: argocd
spec:
generators:
- pullRequest:
github:
owner: myorg
repo: myapp
labels:
- deploy-preview
requeueAfterSeconds: 30
template:
metadata:
name: 'preview-{{number}}'
annotations:
preview-url: 'https://pr-{{number}}.preview.example.com'
spec:
project: previews
source:
repoURL: https://github.com/myorg/myapp.git
targetRevision: '{{head_sha}}'
path: deploy/preview
helm:
parameters:
- name: ingress.host
value: 'pr-{{number}}.preview.example.com'
- name: image.tag
value: '{{head_short_sha}}'
destination:
server: https://kubernetes.default.svc
namespace: 'preview-{{number}}'
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true
환경별 값 오버라이드 (Merge Generator)
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: app-with-overrides
namespace: argocd
spec:
generators:
- merge:
mergeKeys:
- name
generators:
- clusters:
values:
replicas: '2'
logLevel: info
- list:
elements:
- name: production-cluster
values.replicas: '5'
values.logLevel: warn
template:
metadata:
name: 'myapp-{{name}}'
spec:
project: default
source:
repoURL: https://github.com/org/myapp.git
targetRevision: HEAD
path: deploy
helm:
parameters:
- name: replicas
value: '{{values.replicas}}'
- name: logLevel
value: '{{values.logLevel}}'
destination:
server: '{{server}}'
namespace: myapp
9. 트러블슈팅
일반적인 문제와 해결
Application이 생성되지 않는 경우:
- Generator의 selector가 올바른지 확인
- Git 경로가 존재하는지 확인
- ApplicationSet Controller 로그 확인
Application이 예상과 다르게 삭제되는 경우:
- preserveResourcesOnDeletion 설정 확인
- Generator의 출력이 변경되었는지 확인
- ApplicationSet의 소유권 관리 확인
템플릿 렌더링 오류:
- 파라미터 이름이 Generator 출력과 일치하는지 확인
- Go 템플릿 사용 시 goTemplate: true 설정 확인
- goTemplateOptions에서 missingkey 처리 방식 확인
디버깅 명령
# ApplicationSet 상태 확인
kubectl get applicationset -n argocd
# ApplicationSet 상세 정보 확인
kubectl describe applicationset my-appset -n argocd
# ApplicationSet Controller 로그 확인
kubectl logs -n argocd deployment/argocd-applicationset-controller
# 생성된 Application 확인
argocd app list
10. 정리
ApplicationSet Controller의 핵심 요소:
- Generator: 다양한 데이터 소스(클러스터, Git, PR, SCM)에서 파라미터 생성
- Matrix/Merge: Generator를 조합하여 복잡한 배포 토폴로지 구현
- Template Engine: fasttemplate 또는 Go 템플릿으로 Application 리소스 렌더링
- Progressive Sync: Rolling 업데이트 전략으로 안전한 대규모 배포
- Reconciliation: Event-driven + 주기적 polling으로 상태 동기화
- 생명주기 관리: 생성/업데이트/삭제 정책으로 Application 자동 관리
ApplicationSet을 효과적으로 활용하면 수백 개의 Application을 하나의 리소스로 관리할 수 있어, 대규모 GitOps 환경의 운영 복잡도를 크게 줄일 수 있습니다.