본문 바로가기

Devops

ArgoCD - Application GitOps로 선언 & 자동화하기 (ApplicationSet)

개요

2025.11.05 - [Devops] - Argocd - GitOps 활용하기(App of Apps 패턴)

 

지난 글에선 Application을 GitOps로 관리할 수 있는 App of Apps를 소개했는데 장점도 있지만 명확한 한계가 존재했었고 그 한계를 해결해 주는 ApplicationSet을 소개해드리겠습니다.

 

ApplicationSet은 App of Apps를 이해했던 것 처럼 맥락은 비슷하게 Application을 Git으로 선언해 관리하는 장점들은 똑같이 가진 것뿐 아니라 더 많은 장점을 가지고 있고 ArgoCD가 관리하는 CR인 만큼 단점은 go 문법을 기반으로 한 템플릿과 랜더링 등으로 해결한 것에 있습니다.

 

유일한 단점이라고 하면 ArgoCD를 처음 구축하고 적용해보고자 하는 사람에겐 ApplicationSet이란 이해가 어려우며 아직 미숙한 사람에겐 그를 이루고 있는 많은 부분이 어렵게 느껴지는 러닝커브 때문에 쉽게 적용하기 어렵다는 것입니다.

 

정리하면, ApplicationSet의 가장 큰 진입 장벽은 “처음에 한 번에 이해해야 할 개념이 많다”는 점입니다. 그렇다면 ApplicationSet은 정확히 무엇이고, App of Apps의 어떤 한계를 어떤 방식으로 보완하는지부터 차근히 짚어보겠습니다.

 

ApplicationSet이란?

 

ApplicationSet은 ApplicationSet 커스텀 리소스(CR)(= ApplicationSet CRD로 정의됨)와 이를 처리하는 전용 컨트롤러로 구성됩니다.

 

이 컨트롤러는 하나의 ApplicationSet CR로부터 규칙에 따라 여러 개의 Argo CD Application을 자동 생성·갱신·정리합니다.

 

주요 특징

  • 다중 클러스터/다중 환경에 대해 Application을 일괄 생성·정리할 수 있습니다.
  • Application 정의를 수동으로 나열하는 대신, 규칙(제너레이터) + 공통 템플릿으로 Application동적으로 생성*관리합니다.
이 방식으로 멀티 클러스터·멀티 환경·멀티 서비스 배포를 단일 선언으로 관리합니다.

 

ApplicationSet의 컴포넌트

ApplicationSet은 크게 templategenerator라는 두 축으로 이해하면 흐름이 잡힙니다

 

template

  • 여러 Application에 공통으로 들어갈 **기본 골격(스펙)**을 정의합니다. 즉, “어떤 형태의 Application을 만들 것인가”를 고정합니다.

generator

  • Generator는 제공된 타입별로 Git/클러스터 목록/수동 리스트 같은 입력 소스에서 항목을 읽어 템플릿에 넣을 파라미터를 생성합니다. 이렇게 생성된 파라미터는 template렌더링렌더링 되어 최종적으로 Argo CD Application으로 만들어집니다. 

그럼 각 컴포넌트를 구체적으로 파악해 보겠습니다.

ApplicationSet의 컴포넌트 - Generator

ApplicationSet은 다양한 generator를 지원하며, generators 배열에 복수의 generator를 선언할 수 있습니다.

  • 각 generator의 산출은 기본적으로 합집합으로 취급되며, 필요시 matrix(조합) 또는 merge(키 기준 병합)로 결합할 수 있습니다.
  • 복수로 선언할 수 있고 다양한 generator 간의 특성을 조합해 파라미터들을 생성할 수 있다는 점이 중요합니다.

대표적인 generator 몇 가지와 제가 실무에서 주로 사용하고 있는 Generator를 중심으로 파악해 보겠습니다.

# Git Generator (directories 기반)
generators:
  - git:
      repoURL: https://github.com/<org>/<repo>.git
      revision: HEAD
      directories:
        - path: apps/*

# List Generator (고정 키-값 목록)
generators:
  - list:
      elements:
        - name: guestbook-dev
          namespace: guestbook
          path: apps/guestbook/dev
        - name: guestbook-prod
          namespace: guestbook
          path: apps/guestbook/prod

# Cluster Generator (Argo CD에 등록된 클러스터 기준)
generators:
  - clusters:
      selector:
        matchLabels:
          env: prod
  1. Git Generator
      • Git 리포지토리의 디렉터리 구조(Directories) 또는 파일 내용(Files)을 기준으로 템플릿에 넣을 파라미터를 생성합니다.
        • (예: 디렉토리 1개/파일 1개가 “배포 단위”가 되어, 그만큼 Application이 생성되는 형태)
  2. List Generator
      • elements에 적어둔 키-값 목록을 그대로 파라미터 세트로 사용합니다.
        즉, “이 값들로 Application을 만들겠다”는 고정된 리스트를 가장 직관적으로 선언하는 방식입니다.
  3. Cluster Generator
    • Argo CD에 등록된 클러스터(클러스터 Secret)를 기준으로, 클러스터별 파라미터를 자동 추출해 템플릿에 전달합니다.
      기본으로 아래 값을 제공합니다.
      • name / nameNormalized
      • server
      • project(Secret에 있으면 사용, 없으면 빈 값)
      • metadata.labels. <key> (Secret의 라벨을 키별로)
      • metadata.annotations. <key> (Secret의 어노테이션을 키별로)
  4. Matrix Generator
    • 두 generator가 만든 파라미터를 카테시안 곱(모든 조합)으로 결합합니다.
  5. Merge Generator
      • 둘 이상의 generator 결과를 키 기준으로 매칭해 병합합니다(매칭되지 않으면 제외).
        병합 시에는 뒤에 오는 generator의 값이 우선해, “기본값 + 환경별 덮어쓰기” 패턴에 주로 사용됩니다.

ApplicationSet의 컴포넌트 - Template

template은 ApplicationSet이 최종적으로 만들어낼 **Argo CD Application의 기본 스펙(틀)**을 정의하는 영역입니다. 즉, “생성될 Application이 어떤 형태여야 하는가”를 여기서 고정합니다.

  • template의 하위 필드는 Argo CD Application의 스펙과 직접 대응합니다. (project, source, destination, metadata 등)
  • generator가 만든 값(파라미터)은 template 내부의 {{ }}치환되어 렌더링 되고, 그 결과로 실제 Application 리소스가 생성·갱신됩니다.
spec:
  goTemplate: true
  goTemplateOptions: ["missingkey=error"]
  generators:
    - clusters:
        selector:
          matchLabels:
            env: prod
        template:
          spec:
            destination:
              namespace: addons-prod
  template:
    metadata:
      name: '{{.nameNormalized}}-addons'
    spec:
      project: default
      source:
        repoURL: https://github.com/argoproj/argocd-example-apps.git
        targetRevision: HEAD
        path: guestbook
      destination:
        server: '{{.server}}'
        namespace: addons

 

(참고) 필요하면 generator 내부에도 template를 둘 수 있고, 이 경우 generator 쪽 template가 spec.template보다 우선해 “기본 템플릿 + 부분 오버라이드” 패턴으로 활용할 수 있습니다.

 

Application은 실제로 어떻게 생성되게 되는가?

동작 흐름은 단순합니다. 제너레이터가 “대상 목록(또는 파라미터 집합)”을 만들고, 컨트롤러는 그 결과를 템플릿에 치환 Application들을 렌더링 한 뒤, 해당 Application 리소스를 생성/업데이트합니다. 이후 실제 배포 동기화는 Argo CD가 생성된 Application을 기준으로 수행합니다.

 

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: cluster-a-addons
  namespace: argocd
spec:
  project: default
  source:
    repoURL: https://github.com/argoproj/argocd-example-apps.git
    targetRevision: HEAD
    path: guestbook
  destination:
    server: https://cluster-a.example.com
    namespace: addons-prod
---
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: cluster-b-addons
  namespace: argocd
spec:
  project: default
  source:
    repoURL: https://github.com/argoproj/argocd-example-apps.git
    targetRevision: HEAD
    path: guestbook
  destination:
    server: https://cluster-b.example.com
    namespace: addons-prod

 

각 Generator를 어떤 상황에서 사용하고 어떻게 조합해서 사용하는가?

Git Generator

  • 실제 배포 리소스들의 구조가 git으로 관리되고 있고 애플리케이션 배포간 별다른 템플릿 로직이 필요하지 않은 경우 directory
  • Application 각각의 배포 구조에 대한 내용을 파일로 관리하고 git 기반으로 배포할 경우 files

Cluster Generator

  • ArgoCD가 여러 클러스터에 대한 접속 정보를 가지고 있고 (Deploy-Multi Cluster) 멀티 클러스터에 배포하려는 경우

List Generator

  • key-value 쌍을 기반으로 반복해 가며 template 등에 전달해 Application 배포구조를 찍어내려는 경우 
    • env:dev, destination: dev end: prd, destination: prd

Matrix Generator

  • 위의 generator들을 조합하여 멀티 클러스터에 git 파일들을 기반으로 한 번에 Applcation들을 배포하려는 경우
    • N개의 클러스터에 N개의 git 파일들을 조합하여 동시에 배포를 진행하려는 경우에 사용합니다.

Merge Generator

  • 동일한 Key를 기반으로 병합하여 환경별 파일을 생성해 배포간 파일도 효율적으로 관리하려는 경우 사용합니다.
  • 환경 간 Application 배포가 달라질 수 있는 경우 선택적으로 배포하기 위해 사용합니다.

실무에서 사용한 ApplicationSet의 조합과 예시

apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: ApplicationSet-example
  namespace: argocd
spec:
  goTemplate: true
  goTemplateOptions: ["missingkey=error"]
  syncPolicy:
    preserveResourcesOnDeletion: true

  generators:
    - matrix:
        generators:
          - merge:
              mergeKeys: ["app"]
              generators:
                - git:
                    repoURL: <git>
                    revision: <branch>
                    files:
                      - path: <선택적-app-path>
                      - path: <base-app-path>
                        exclude: true
                - git:
                    repoURL: <git>
                    revision: <branch>
                    files:
                      - path: <base-app-path>
  template:
    metadata:
      name: '{{ .app }}'
      labels:
          app.kubernetes.io/name: '{{ .app }}'
          app.kubernetes.io/instance: '{{ regexFind "[^/]+$" .env }}'
          app.kubernetes.io/component: application
          app.kubernetes.io/managed-by: argocd-applicationset
    spec:
      project: default
      destination:
        server: https://kubernetes.default.svc
        namespace: '{{ .app }}'
      sources: []
      # templatePatch에서 재정의
  • List Generator도 같이 썼었고 템플릿을 단순히 로딩하는 것 외에 파일 간 재정의, 로직등이 들어가 templatePatch를 사용해 go문법을 토대로 Application을 만들 때 썼던 부분들의 일부입니다.
  • Merge Generator를 사용해 환경별로 base Application을 정의하고 선택적으로 배포할 수 있게 환경별 git generator로 병합되는 파일만 배포하고 추가적인 속성, 환경별 특성은 templatePatch에서 정의, 병합되게 구성했었습니다.

ApplicationSet의 장단점

App of Apps의 장점을 그대로 갖고 있으며 그 외의 것들을 기술하겠습니다.

 

장점

  1. 여러 환경에 대해 한번에 Application 배포를 자동화할 수 있습니다.
    • App of Apps는 모든 환경마다 한 번은 배포해야 한다는 한계가 존재했지만 ApplicationSet은 이 한계를 극복했습니다.
  2. 보일러 플레이트 코드를 반복해서 생성하는 부분을 없애고 필요한 부분들을 변수 화하여 파라미터로 전달하는 형태로 Application 배포를 간소화할 수 있습니다.
    • 이 부분은 helm 등 템플릿 엔진을 사용한다면 해결될 수 있는 부분이지만 ApplicationSet이 지원하는 부분이기도 합니다.
  3. 단순 랜더링은 template으로 로직이나 환경별 특성을 고려하게 되는 부분들은 templatePatch를 통해 클러스터의 특성, 환경에 원하는 대로 맞춰서 구성이 가능합니다.
  4. Application 배포간 장애가 발생했을 경우 ApplicationSet 컨트롤러가 배포, 관리를 담당하는 만큼 로그를 통해 디버깅이 가능합니다.
    • App of Apps는 배포간 장애가 발생했을 경우 디버깅 수단이 존재하지 않지만 ApplicationSet은 컨트롤러라는 서버가 담당하는 만큼 디버깅이 가능하고 이를 통해 원인 분석 및 빠른 해결에 도움을 줍니다.

단점

러닝커브가 높다.

  • generator, template 등 Application을 만들어내는 부분들에 대한 이해가 필요하며 각각의 특성을 이해하고 상황별로 사용해야 하는 러닝커브가 존재합니다.
  • 단순 template은 Application을 만들어 봤던 분들이라면 template화 하는 건 어렵지 않지만 templatePatch는 go문법을 활용한 부분이기에 새로운 러닝커브가 존재합니다.
  • App of apps와 다르게 배포에 필요한 root app은 더 이상 UI로 확인할 수 없으며 CLI나 로그로 확인해야 하기에 UI에 친숙했던 분이라면 이 또한 러닝커브로 느껴질 수 있을 것 같습니다.
제가 생각하는 단점은 단 하나 러닝커브가 높다는 것이며 이것이 Application들을 생성하는 부분들에 대한 이해가 필요하다는 부분이지만 이 외에는 단점으로 느껴지는 것은 사용하면서 느껴지지 않았습니다.

정리/회고

Application을 자동화하여 배포하는 ApplicationSet의 개념, 컴포넌트, 동작원리, 실무에서 사용하는 형태에 대해 정리해 봤습니다.

 

저는 실제로도 App of Apps로 쓰던 패턴, 파일들은 모두 ApplicationSet으로 이관했으며 이전의 모든 파일들은 전부 삭제했고 그전과 비교하면 환경별로 배포할 때 최소 30% 이상 파일 개수도 줄어들기도 했습니다.

  • 파일의 콘텐츠로만 비교한다면 환경별로 base의 속성을 바꾸지 않을 땐 mergeKey만 기술하여 한 줄로도 배포했기에 몇십 줄에서 한 줄만 기술하여 배포하는 이 간소함은 이전과 비교할 수 없는 형태인 것 같습니다.

ApplicationSet의 장점 중 보일러 플레이트 코드의 중복 제거의 부분은 helm 같은 템플릿 엔진을 사용한다면 이것만의 장점이라고 할 순 없으나 helm은 Application Template, values.yml 등 파일 개수가 더 비대해지는 걸 고려하면 ApplicationSet이 최선의 선택이라고 생각합니다.

 

다만 ApplicationSet은 ArgoCD에 익숙해져 가는 처음 단계에선 Application을 만드는 과정, Application들을 찍어내는 것에 대한 이해, ArgoCD의 CR에 대한 학습, 왜 이것을 사용해야 하는지를 학습하기에 앞서 러닝커브가 크게 다가와 바로 사용하기엔 무리가 있을 수도 있다고는 생각합니다.

 

처음엔 App of Apps로 사용해 보며 Application들을 자동화하여 git으로 관리하는 것에 대한 필요성, 과정들 그리고 Application의 구성요소들을 이해한 뒤 ApplicationSet으로 전환한다면 더 빠르게 적용하고 이해할 수도 있지 않을까? 그렇게 단계별로 접근하는 것도 괜찮지 않을까 생각합니다.

 

ArgoCD에서 Application을 배포하는 ApplicationSet은 장점과 잠재력이 무궁무진한 컴포넌트와 배포형태라고 생각하며 모두가 이 것을 잘 활용할 수 있었으면 좋겠습니다.

 

Reference

https://argo-cd.readthedocs.io/en/stable/operator-manual/applicationset/Argo-CD-Integration/? utm_source=chatgpt.com