Ssoon
Argo CD - ApplicationSet 본문
✨ ApplicationSet이란?
- ApplicationSet은 Argo CD에 자동화된 Application 생성 기능을 더해주는 Kubernetes 컨트롤러입니다. (Argo CD)
- ApplicationSet 컨트롤러는 CRD(Custom Resource Definition)를 사용해서 여러 개의 Argo CD Application을 선언적으로 관리할 수 있게 해줍니다. (Argo CD)
- 이를 통해 멀티 클러스터, monorepo, 멀티 테넌트 환경에서 더 유연하고 자동화된 배포 구조를 설계할 수 있습니다. (Argo CD)
- Argo CD v2.3부터는 ApplicationSet 컨트롤러가 기본적으로 포함되어 별도 설치 없이 사용할 수 있습니다. (Argo CD)
"ApplicationSet은 한 번 정의하면
여러 Application을 자동으로 생성하고 유지해주는 GitOps 자동화의 핵심 도구이다."
⚙️ 핵심 구성 요소: Generators (생성기)
ApplicationSet의 가장 중요한 부분 중 하나는 생성기(generator) 입니다. 생성기는 파라미터를 생성하고, 이 파라미터들이 template 필드에 삽입되어 Application 리소스를 만든다. (Argo CD)
주요 generator 종류는 다음과 같습니다:
- List generator
고정된 리스트(예: 클러스터 이름 + URL)의 키/값 쌍을 사용. (Argo CD) - Cluster generator
Argo CD에 이미 등록된 클러스터 정보를 자동으로 파라미터로 생성. (Argo CD) - Git generator
Git 저장소의 파일 또는 디렉토리 구조를 사용해서 파라미터 생성. (Argo CD) - Matrix generator
두 개 이상의 생성기를 조합해서 가능한 모든 파라미터 조합을 만듦. (Argo CD) - 기타: Merge, SCM Provider, Pull Request 생성기 등도 가능. (Argo CD)
"생성기는 다양한 소스(리스트, 클러스터, Git 등)에서 파라미터를 생성하고,
이를 템플릿에 넣어 여러 Application을 만든다."
🧩 템플릿 (Template)
- spec.template 필드는 생성기로부터 받은 파라미터를 기반으로 실제 Argo CD Application의 정의를 생성하는 역할을 합니다. (Argo CD)
- 템플릿 안에서는 Go Template 문법({{ .parameter }})이나 FastTemplate(곧 Go Template로 대체 예정) 문법이 사용됩니다. (Argo CD)
- 템플릿에서 정의할 수 있는 주요 필드:
- metadata.name: Application 이름
- spec.project: 어느 Argo CD Project에 속할지
- spec.source: Git repo URL, revision, path 등
- spec.destination: 어느 클러스터(server)와 네임스페이스(namespace)에 배포할지 (Argo CD)
- 템플릿 외에도 각 generator별로 template을 오버라이드할 수 있는 generator.template 필드를 제공하여, 더 세밀하게 설정 가능. (Argo CD)
"템플릿은 생성기로 받은 파라미터를
실제 Application 리소스로 렌더링하는 설계도의 역할을 한다."
🔁 동기화 정책 (Sync Policy)
- ApplicationSet의 템플릿 내에 spec.template.syncPolicy를 정의해서 자동 동기화(automated sync)를 설정할 수 있습니다. (Argo CD)
- automated 동기화 옵션으로:
- prune: Git에 정의되지 않은 리소스를 클러스터에서 삭제할지 여부
- selfHeal: 클러스터에서 수동으로 변경된 리소트를 자동으로 되돌릴지 여부 (Argo CD)
- 삭제된 애플리케이션이 실제 클러스터 리소스를 “보존”하도록 하려면 preserveResourcesOnDeletion: true를 설정할 수 있습니다. (Argo CD)
- 단, ApplicationSet이 자동 생성한 애플리케이션의 sync 정책은 해당 애플리케이션 리소스를 직접 수정해도 덮어씌워질 수 있으므로 주의가 필요합니다. (GitHub)
"Sync Policy를 통해
자동화된 동기화와 리소스 보존 전략을 유연하게 설계할 수 있다."
🔧 리소스 제어 & 보존 (Controlling Resource Modification)
- ApplicationSet 컨트롤러는 ApplicationSet 스펙과 실제 Application의 스펙을 비교하고, 차이가 있으면 병합 패치를 생성해 업데이트합니다. (Argo CD)
- 기본적으로 ApplicationSet가 관리하는 애플리케이션이 삭제되면, 해당 애플리케이션이 만든 쿠버네티스 리소스도 삭제됩니다. (Argo CD)
- 하지만 syncPolicy.preserveResourcesOnDeletion을 true로 설정하면, 애플리케이션이 삭제될 때도 자식 리소스(예: Deployment, Service 등)를 보존할 수 있습니다. (Argo CD)
- 또한 어노테이션이나 레이블 중 일부를 ApplicationSet가 덮어쓰지 않도록 preservedFields 옵션을 사용할 수 있습니다. (Argo CD)
"ApplicationSet는
단순 생성을 넘어서 삭제나 수정 시에도 리소스 보존 전략을 제공한다."
🔐 보안 고려사항 (Security)
- ApplicationSet는 매우 강력한 기능이기 때문에 보안 리스크를 동반합니다. (Argo CD)
- 특히 git generator를 쓸 경우, 민감한 시크릿을 포함한 Git 접근 정보가 악의적으로 유출되거나 악용될 수 있습니다. (Argo CD)
- 권한 설정 시에는 관리자(admin) 에게만 ApplicationSet 생성/수정/삭제 권한을 주는 것이 권장됩니다. (Argo CD)
- Argo CD의 RBAC 설정에서도 applicationsets 리소스에 대한 권한 세분화가 가능합니다. (Argo CD)
"ApplicationSet를 사용할 땐 보안 권한을 엄격히 제한해야 한다.
생성/수정 권한은 관리자에게만 허용하는 것이 안전하다."
🛠️ 사용 시 유의점 & 베스트 프랙티스
- ApplicationSet 템플릿은 Go Template 등으로 작성할 때 편리하지만, 복잡한 조건이 많아지면 관리가 어려워질 수 있습니다.
- templatePatch 기능을 활용해 환경별로 다른 syncPolicy 또는 설정을 적용할 수 있습니다. (예: dev 환경은 자동 sync, prod는 수동 sync) (DevOps.dev)
- preserveResourcesOnDeletion 옵션을 적절히 활용하여, 애플리케이션 삭제 시에도 중요한 리소스가 실수로 사라지지 않게 설계할 수 있습니다.
- RBAC 정책에서 applicationsets 리소스에 대한 액세스를 제한하고, 템플릿 필드(예: project)를 평가할 때 의도치 않은 권한 상승이 없도록 주의하세요. (Argo CD)
- ApplicationSet 컨트롤러 설정(예: 정책 오버라이드)을 바꾸고 싶다면 argocd-applicationset-controller Deployment를 직접 수정하거나 설치 매니페스트를 업데이트할 수 있습니다. (Argo CD)
"ApplicationSet를 설계할 때는 자동화뿐 아니라
보안, 삭제 전략, 정책 오버라이딩까지 함께 고려하는 것이 중요하다."
📌 핵심 요약
- ApplicationSet은 여러 Argo CD Application을 자동으로 생성/관리할 수 있게 해주는 CRD 기반 컨트롤러입니다.
- 다양한 generator(List, Cluster, Git 등)로 파라미터를 생성하고, 템플릿에 적용해 애플리케이션을 동적으로 만들 수 있습니다.
- Sync Policy를 템플릿에 정의하여 자동 동기화, pruning, self-heal, 자원 보존 전략을 유연하게 적용할 수 있습니다.
- 보안 측면에서 매우 민감한 기능이기 때문에, ApplicationSet 생성/수정 권한은 관리자에게 제한하는 것이 중요합니다.
- 삭제 전략을 잘 설계하고, preserveResourcesOnDeletion 옵션을 이용해 실수로 리소스가 사라지는 것을 방지할 수 있습니다.
✅ ApplicationSet List 제네레이터 실습
- 환경 변수로 DEVK8SIP와 PRDK8SIP 설정
(⎈|kind-mgmt:N/A) ssoon@DESKTOP-72C919S:~$ docker network inspect kind | grep -E 'Name|IPv4Address'
"Name": "kind",
"Name": "dev-control-plane",
"IPv4Address": "172.19.0.2/16",
"Name": "prd-control-plane",
"IPv4Address": "172.19.0.4/16",
"Name": "mgmt-control-plane",
"IPv4Address": "172.19.0.3/16",
(⎈|kind-mgmt:N/A) ssoon@DESKTOP-72C919S:~$ DEVK8SIP=172.19.0.2
(⎈|kind-mgmt:N/A) ssoon@DESKTOP-72C919S:~$ PRDK8SIP=172.19.0.4
(⎈|kind-mgmt:N/A) ssoon@DESKTOP-72C919S:~$ echo $DEVK8SIP $PRDK8SIP
172.19.0.2 172.19.0.4
- argocd app 배포
(⎈|kind-mgmt:N/A) ssoon@DESKTOP-72C919S:~$ cat <<EOF | kubectl apply -f -
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: guestbook
namespace: argocd
spec:
goTemplate: true
goTemplateOptions: ["missingkey=error"]
generators:
- list:
elements:
- cluster: dev-k8s
url: https://$DEVK8SIP:6443
- cluster: prd-k8s
url: https://$PRDK8SIP:6443
template:
metadata:
name: '{{.cluster}}-guestbook'
labels:
environment: '{{.cluster}}'
managed-by: applicationset
spec:
project: default
source:
repoURL: https://github.com/gasida/cicd-study.git
targetRevision: HEAD
path: appset/list/{{.cluster}}
destination:
server: '{{.url}}'
namespace: guestbook
syncPolicy:
syncOptions:
- CreateNamespace=true
EOF
applicationset.argoproj.io/guestbook created
- ApplicationSet(guestbook)가 생성되어 각 클러스터(dev-k8s, prd-k8s) 에 대응하는 Application 두 개가 생성
- Application은 만들어졌지만, 실제 리소스가 아직 배포되지 않았거나, 네임스페이스/매니페스트 경로가 맞지 않아 동기화되지 않은 상태
(⎈|kind-mgmt:N/A) ssoon@DESKTOP-72C919S:~$ kubectl get applicationsets -n argocd
NAME AGE
guestbook 20s
(⎈|kind-mgmt:N/A) ssoon@DESKTOP-72C919S:~$ argocd appset list
NAME PROJECT SYNCPOLICY CONDITIONS REPO PATH TARGET
argocd/guestbook default nil [{ParametersGenerated Successfully generated parameters for all Applications 2025-11-20 20:44:41 +0900 KST True ParametersGenerated} {ResourcesUpToDate ApplicationSet up to date 2025-11-20 20:44:41 +0900 KST True ApplicationSetUpToDate}] https://github.com/gasida/cicd-study.git appset/list/{{.cluster}} HEAD
(⎈|kind-mgmt:N/A) ssoon@DESKTOP-72C919S:~$ argocd app list -l managed-by=applicationset
NAME CLUSTER NAMESPACE PROJECT STATUS HEALTH SYNCPOLICY CONDITIONS REPO PATH TARGET
argocd/dev-k8s-guestbook https://172.19.0.2:6443 guestbook default OutOfSync Missing Manual <none> https://github.com/gasida/cicd-study.git appset/list/dev-k8s HEAD
argocd/prd-k8s-guestbook https://172.19.0.4:6443 guestbook default OutOfSync Missing Manual <none> https://github.com/gasida/cicd-study.git appset/list/prd-k8s HEAD
(⎈|kind-mgmt:N/A) ssoon@DESKTOP-72C919S:~$ kubectl get applications -n argocd --show-labels
NAME SYNC STATUS HEALTH STATUS LABELS
dev-k8s-guestbook OutOfSync Missing environment=dev-k8s,managed-by=applicationset
prd-k8s-guestbook OutOfSync Missing environment=prd-k8s,managed-by=applicationset

- 두 클러스터(dev/prd)에 guestbook 앱이 동기화
(⎈|kind-mgmt:N/A) ssoon@DESKTOP-72C919S:~$ argocd app sync -l managed-by=applicationset
TIMESTAMP GROUP KIND NAMESPACE NAME STATUS HEALTH HOOK MESSAGE
2025-11-20T20:49:55+09:00 Service guestbook guestbook-ui OutOfSync Missing
2025-11-20T20:49:55+09:00 apps Deployment guestbook guestbook-ui OutOfSync Missing
2025-11-20T20:49:55+09:00 Namespace guestbook Running Synced namespace/guestbook created
Name: argocd/dev-k8s-guestbook
Project: default
Server: https://172.19.0.2:6443
Namespace: guestbook
...
Operation: Sync
...
Name: argocd/prd-k8s-guestbook
Project: default
Server: https://172.19.0.4:6443
Namespace: guestbook
...
Operation: Sync
...
- name: '{{.cluster}}-guestbook'
- environment: '{{.cluster}}'
- path: appset/list/{{.cluster}}
- server: '{{.url}}'
(⎈|kind-mgmt:N/A) ssoon@DESKTOP-72C919S:~$ kubectl get applications -n argocd dev-k8s-guestbook -o yaml | k neat | yq
{
"apiVersion": "argoproj.io/v1alpha1",
"kind": "Application",
"metadata": {
"labels": {
"environment": "dev-k8s",
"managed-by": "applicationset"
},
"name": "dev-k8s-guestbook",
"namespace": "argocd"
},
"spec": {
"destination": {
"namespace": "guestbook",
"server": "https://172.19.0.2:6443"
},
"project": "default",
"source": {
"path": "appset/list/dev-k8s",
"repoURL": "https://github.com/gasida/cicd-study.git",
"targetRevision": "HEAD"
},
"syncPolicy": {
"syncOptions": [
"CreateNamespace=true"
]
}
}
}
(⎈|kind-mgmt:N/A) ssoon@DESKTOP-72C919S:~$ kubectl get applications -n argocd prd-k8s-guestbook -o yaml | k neat | yq
{
"apiVersion": "argoproj.io/v1alpha1",
"kind": "Application",
"metadata": {
"labels": {
"environment": "prd-k8s",
"managed-by": "applicationset"
},
"name": "prd-k8s-guestbook",
"namespace": "argocd"
},
"spec": {
"destination": {
"namespace": "guestbook",
"server": "https://172.19.0.4:6443"
},
"project": "default",
"source": {
"path": "appset/list/prd-k8s",
"repoURL": "https://github.com/gasida/cicd-study.git",
"targetRevision": "HEAD"
},
"syncPolicy": {
"syncOptions": [
"CreateNamespace=true"
]
}
}
}
- 각 k8s 에 배포된 파드 정보 확인
(⎈|kind-mgmt:N/A) ssoon@DESKTOP-72C919S:~$ k8s2 get pod -n guestbook
NAME READY STATUS RESTARTS AGE
guestbook-ui-7cf4fd7cb9-hr9cw 1/1 Running 0 7m53s
(⎈|kind-mgmt:N/A) ssoon@DESKTOP-72C919S:~$ k8s3 get pod -n guestbook
NAME READY STATUS RESTARTS AGE
guestbook-ui-7cf4fd7cb9-rwzzv 1/1 Running 0 7m54s
guestbook-ui-7cf4fd7cb9-vl86m 1/1 Running 0 7m55s

- 삭제
(⎈|kind-mgmt:N/A) ssoon@DESKTOP-72C919S:~$ argocd appset delete guestbook --yes
applicationset 'guestbook' deleted
✅ ApplicationSet Cluster 제네레이터 실습
(⎈|kind-mgmt:N/A) ssoon@DESKTOP-72C919S:~$ cat <<EOF | kubectl apply -f -
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: guestbook
namespace: argocd
spec:
goTemplate: true
goTemplateOptions: ["missingkey=error"]
generators:
- clusters: {}
template:
metadata:
name: '{{.name}}-guestbook'
labels:
managed-by: applicationset
spec:
project: "default"
source:
repoURL: https://github.com/gasida/cicd-study
targetRevision: HEAD
path: guestbook
destination:
server: '{{.server}}'
namespace: guestbook
syncPolicy:
syncOptions:
- CreateNamespace=true
EOF
applicationset.argoproj.io/guestbook created
- ApplicationSet guestbook 는 정상적으로 생성 > 각 클러스터(dev, prd, in-cluster)에 대응하는 Application이 자동 생성 > STATUS = OutOfSync, HEALTH = Missing → 매니페스트가 적용되지 않은 상태
(⎈|kind-mgmt:N/A) ssoon@DESKTOP-72C919S:~$ argocd appset list
NAME PROJECT SYNCPOLICY CONDITIONS REPO PATH TARGET
argocd/guestbook default nil [{ParametersGenerated Successfully generated parameters for all Applications 2025-11-20 21:56:25 +0900 KST True ParametersGenerated} {ResourcesUpToDate ApplicationSet up to date 2025-11-20 21:56:25 +0900 KST True ApplicationSetUpToDate}] https://github.com/gasida/cicd-study guestbook HEAD
(⎈|kind-mgmt:N/A) ssoon@DESKTOP-72C919S:~$ argocd app list
NAME CLUSTER NAMESPACE PROJECT STATUS HEALTH SYNCPOLICY CONDITIONS REPO PATH TARGET
argocd/dev-k8s-guestbook https://172.19.0.2:6443 guestbook default OutOfSync Missing Manual <none> https://github.com/gasida/cicd-study guestbook HEAD
argocd/in-cluster-guestbook https://kubernetes.default.svc guestbook default OutOfSync Missing Manual <none> https://github.com/gasida/cicd-study guestbook HEAD
argocd/prd-k8s-guestbook https://172.19.0.4:6443 guestbook default OutOfSync Missing Manual <none> https://github.com/gasida/cicd-study guestbook HEAD
(⎈|kind-mgmt:N/A) ssoon@DESKTOP-72C919S:~$ kubectl get applications -n argocd --show-labels
NAME SYNC STATUS HEALTH STATUS LABELS
dev-k8s-guestbook OutOfSync Missing managed-by=applicationset
in-cluster-guestbook OutOfSync Missing managed-by=applicationset
prd-k8s-guestbook OutOfSync Missing managed-by=applicationset
- 세 클러스터(dev, prd, in-cluster) 모두 guestbook 앱이 정상적으로 Sync 작업을 수행, 리소스 생성
(⎈|kind-mgmt:N/A) ssoon@DESKTOP-72C919S:~$ argocd app sync -l managed-by=applicationset
TIMESTAMP GROUP KIND NAMESPACE NAME STATUS HEALTH HOOK MESSAGE
2025-11-20T21:58:52+09:00 Service guestbook guestbook-ui OutOfSync Missing
2025-11-20T21:58:52+09:00 apps Deployment guestbook guestbook-ui OutOfSync Missing
2025-11-20T21:58:52+09:00 Service guestbook guestbook-ui OutOfSync Missing service/guestbook-ui created
2025-11-20T21:58:52+09:00 apps Deployment guestbook guestbook-ui OutOfSync Missing deployment.apps/guestbook-ui created
2025-11-20T21:58:52+09:00 Service guestbook guestbook-ui Synced Healthy service/guestbook-ui created
2025-11-20T21:58:52+09:00 apps Deployment guestbook guestbook-ui Synced Progressing deployment.apps/guestbook-ui created
Name: argocd/dev-k8s-guestbook
Project: default
Server: https://172.19.0.2:6443
Namespace: guestbook
...
Operation: Sync
...
Name: argocd/in-cluster-guestbook
Project: default
Server: https://kubernetes.default.svc
Namespace: guestbook
...
Operation: Sync
...
Name: argocd/prd-k8s-guestbook
Project: default
Server: https://172.19.0.4:6443
Namespace: guestbook
...
Operation: Sync
...
- 매니페스트 확인
(⎈|kind-mgmt:N/A) ssoon@DESKTOP-72C919S:~$ kubectl get applications -n argocd in-cluster-guestbook -o yaml | k neat | yq
...
"name": "in-cluster-guestbook",
...
"server": "https://kubernetes.default.svc"
...
(⎈|kind-mgmt:N/A) ssoon@DESKTOP-72C919S:~$ kubectl get applications -n argocd dev-k8s-guestbook -o yaml | k neat | yq
...
"name": "dev-k8s-guestbook",
...
"server": "https://172.19.0.2:6443"
...
(⎈|kind-mgmt:N/A) ssoon@DESKTOP-72C919S:~$ kubectl get applications -n argocd prd-k8s-guestbook -o yaml | k neat | yq
...
"name": "prd-k8s-guestbook",
"namespace": "argocd"
...
"server": "https://172.19.0.4:6443"
...

- 삭제
(⎈|kind-mgmt:N/A) ssoon@DESKTOP-72C919S:~$ argocd appset delete guestbook --yes
applicationset 'guestbook' deleted
✅ dev k8s 만 배포
- Argo CD 네임스페이스(argocd)에서 클러스터 연결 정보가 담긴 Secret 조회
(⎈|kind-mgmt:N/A) ssoon@DESKTOP-72C919S:~$ kubectl get secret -n argocd -l argocd.argoproj.io/secret-type=cluster
NAME TYPE DATA AGE
cluster-172.19.0.2-4278303179 Opaque 3 100m
cluster-172.19.0.4-2977182201 Opaque 3 95m
- DEVK8S Secret 이름을 변수로 저장.
- argocd 네임스페이스의 해당 Secret에 env=stg 라벨을 부여
- env=stg 라벨이 있는 Secret만 필터링해서 확인
(⎈|kind-mgmt:N/A) ssoon@DESKTOP-72C919S:~$ DEVK8S=cluster-172.19.0.2-4278303179
(⎈|kind-mgmt:N/A) ssoon@DESKTOP-72C919S:~$ kubectl label secrets $DEVK8S -n argocd env=stg
secret/cluster-172.19.0.2-4278303179 labeled
(⎈|kind-mgmt:N/A) ssoon@DESKTOP-72C919S:~$ kubectl get secret -n argocd -l env=stg
NAME TYPE DATA AGE
cluster-172.19.0.2-4278303179 Opaque 3 101m
- Argo CD ApplicationSet을 정의하는 매니페스트
cat <<EOF | kubectl apply -f -
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: guestbook
namespace: argocd
spec:
goTemplate: true
goTemplateOptions: ["missingkey=error"]
generators: #env=stg 라벨이 있는 클러스터 Secret을 대상으로 애플리케이션 생성.
- clusters:
selector:
matchLabels:
env: "stg"
template:
metadata:
name: '{{.name}}-guestbook'
labels:
managed-by: applicationset
spec:
project: "default"
source:
repoURL: https://github.com/gasida/cicd-study
targetRevision: HEAD
path: guestbook
destination:
server: '{{.server}}'
namespace: guestbook
syncPolicy:
syncOptions:
- CreateNamespace=true
automated:
prune: true
selfHeal: true
EOF

- 삭제
(⎈|kind-mgmt:N/A) ssoon@DESKTOP-72C919S:~$ argocd appset delete guestbook --yes
applicationset 'guestbook' deleted'CICD Study [1기]' 카테고리의 다른 글
| HashiCorp Vault - Vault 란? (0) | 2025.11.27 |
|---|---|
| Argo CD - OpenLDAP + KeyCloak + Argo CD + Jenkins (0) | 2025.11.20 |
| Argo CD - Cluster Management (0) | 2025.11.20 |
| Argo Rollouts 설치 및 Sample 테스트 (0) | 2025.10.26 |
| Argo Rollouts - HPA & VPA (0) | 2025.10.19 |
Comments