Skip to content
Published on

ArgoCD ApplicationSet과 Progressive Rollout: GitOps 멀티클러스터 배포 실전 가이드

Authors

이 글은 이 시리즈의 멀티클러스터 운영 편이다. Blue-Green과 Canary의 전체 의사결정 프레임, 자동 롤백, Istio 기반 트래픽 제어를 먼저 훑고 싶다면 ArgoCD + Argo Rollouts로 구현하는 GitOps 배포 전략 — Blue-Green, Canary 완벽 가이드부터 읽는 편이 좋다. 여기서는 ApplicationSet, Generator, Progressive Sync, 환경 fan-out 운영을 중심으로 본다.


1. ArgoCD ApplicationSet이란

ApplicationSet은 ArgoCD의 확장 리소스로, 하나의 템플릿에서 여러 Application을 자동 생성한다. 멀티클러스터, 멀티테넌트, 모노레포 환경에서 수십~수백 개의 Application을 수동으로 관리하는 대신 선언적으로 자동화할 수 있다.

이 글이 답하려는 질문은 "Canary를 어떻게 하느냐"보다 "클러스터와 환경이 늘어났을 때 GitOps 배포를 어떻게 운영 가능한 구조로 유지하느냐"에 더 가깝다. 즉, 배포 전략의 큰 그림은 허브 글이 담당하고, 여기서는 그 전략을 여러 환경에 안전하게 퍼뜨리는 운영 장치에 집중한다.

1.1 왜 ApplicationSet인가?

기존 방식:
  app-dev.yamlApplication (dev)
  app-staging.yamlApplication (staging)
  app-prod.yamlApplication (prod)
  ... × 50개 서비스 = 150YAML 수동 관리 😱

ApplicationSet:
  appset.yaml → 하나의 템플릿으로 150개 자동 생성 ✅

2. ApplicationSet Generator 유형

2.1 List Generator

가장 단순한 형태. 명시적 파라미터 목록에서 Application 생성:

apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: myapp-envs
  namespace: argocd
spec:
  generators:
    - list:
        elements:
          - cluster: dev
            url: https://dev-k8s.example.com
            namespace: myapp-dev
          - cluster: staging
            url: https://staging-k8s.example.com
            namespace: myapp-staging
          - cluster: prod
            url: https://prod-k8s.example.com
            namespace: myapp-prod
  template:
    metadata:
      name: 'myapp-{{cluster}}'
    spec:
      project: default
      source:
        repoURL: https://github.com/org/myapp.git
        targetRevision: HEAD
        path: 'k8s/overlays/{{cluster}}'
      destination:
        server: '{{url}}'
        namespace: '{{namespace}}'
      syncPolicy:
        automated:
          prune: true
          selfHeal: true

2.2 Git Generator (Directory)

모노레포 구조에서 디렉토리 기반 자동 검색:

apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: cluster-addons
  namespace: argocd
spec:
  generators:
    - git:
        repoURL: https://github.com/org/cluster-addons.git
        revision: HEAD
        directories:
          - path: addons/*
          - path: addons/exclude-this
            exclude: true
  template:
    metadata:
      name: '{{path.basename}}'
    spec:
      project: addons
      source:
        repoURL: https://github.com/org/cluster-addons.git
        targetRevision: HEAD
        path: '{{path}}'
      destination:
        server: https://kubernetes.default.svc
        namespace: '{{path.basename}}'

2.3 Cluster Generator

ArgoCD에 등록된 모든 클러스터에 자동 배포:

apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: monitoring-stack
  namespace: argocd
spec:
  generators:
    - clusters:
        selector:
          matchLabels:
            env: production
  template:
    metadata:
      name: 'monitoring-{{name}}'
    spec:
      project: infrastructure
      source:
        repoURL: https://github.com/org/monitoring.git
        path: helm-chart
        helm:
          valueFiles:
            - 'values-{{metadata.labels.region}}.yaml'
      destination:
        server: '{{server}}'
        namespace: monitoring

2.4 Matrix Generator (조합)

두 Generator를 교차 결합:

spec:
  generators:
    - matrix:
        generators:
          - git:
              repoURL: https://github.com/org/apps.git
              revision: HEAD
              directories:
                - path: apps/*
          - clusters:
              selector:
                matchLabels:
                  env: production

3. Progressive Sync: 단계적 롤아웃

3.1 개념

Progressive Sync는 ApplicationSet이 생성한 Application들을 한꺼번에 배포하지 않고 단계적으로 배포하는 전략이다. QA → Staging → Production 순서로 검증하면서 진행할 수 있다.

3.2 설정

apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: myapp-progressive
  namespace: argocd
spec:
  generators:
    - list:
        elements:
          - cluster: qa
            url: https://qa-k8s.example.com
          - cluster: staging
            url: https://staging-k8s.example.com
          - cluster: prod-east
            url: https://prod-east-k8s.example.com
          - cluster: prod-west
            url: https://prod-west-k8s.example.com
  strategy:
    type: RollingSync
    rollingSync:
      steps:
        - matchExpressions:
            - key: cluster
              operator: In
              values:
                - qa
          # QA 먼저 배포 → 자동 Sync
        - matchExpressions:
            - key: cluster
              operator: In
              values:
                - staging
          maxUpdate: 100%
          # QA 성공 후 staging 자동
        - matchExpressions:
            - key: cluster
              operator: In
              values:
                - prod-east
                - prod-west
          maxUpdate: 50%
          # prod는 50%씩 단계적으로
  template:
    metadata:
      name: 'myapp-{{cluster}}'
      labels:
        cluster: '{{cluster}}'
    spec:
      project: default
      source:
        repoURL: https://github.com/org/myapp.git
        targetRevision: HEAD
        path: 'k8s/overlays/{{cluster}}'
      destination:
        server: '{{url}}'
        namespace: myapp
      syncPolicy:
        automated:
          prune: true

4. Argo Rollouts: Canary와 Blue-Green

4.1 Canary 배포

apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
  name: myapp
spec:
  replicas: 10
  strategy:
    canary:
      steps:
        - setWeight: 10
        - pause: { duration: 5m }
        - setWeight: 30
        - pause: { duration: 5m }
        - analysis:
            templates:
              - templateName: success-rate
            args:
              - name: service-name
                value: myapp
        - setWeight: 60
        - pause: { duration: 10m }
        - setWeight: 100
      canaryService: myapp-canary
      stableService: myapp-stable
      trafficRouting:
        istio:
          virtualServices:
            - name: myapp-vsvc
              routes:
                - primary
  selector:
    matchLabels:
      app: myapp
  template:
    metadata:
      labels:
        app: myapp
    spec:
      containers:
        - name: myapp
          image: myapp:v2
          ports:
            - containerPort: 8080

4.2 AnalysisTemplate (자동 롤백)

apiVersion: argoproj.io/v1alpha1
kind: AnalysisTemplate
metadata:
  name: success-rate
spec:
  args:
    - name: service-name
  metrics:
    - name: success-rate
      interval: 30s
      count: 10
      successCondition: result[0] >= 0.95
      failureLimit: 3
      provider:
        prometheus:
          address: http://prometheus.monitoring:9090
          query: |
            sum(rate(http_requests_total{
              service="{{args.service-name}}",
              status=~"2.."
            }[5m])) /
            sum(rate(http_requests_total{
              service="{{args.service-name}}"
            }[5m]))

4.3 Blue-Green 배포

apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
  name: myapp-bluegreen
spec:
  replicas: 5
  strategy:
    blueGreen:
      activeService: myapp-active
      previewService: myapp-preview
      autoPromotionEnabled: false
      prePromotionAnalysis:
        templates:
          - templateName: success-rate
      scaleDownDelaySeconds: 300
  selector:
    matchLabels:
      app: myapp
  template:
    metadata:
      labels:
        app: myapp
    spec:
      containers:
        - name: myapp
          image: myapp:v2

5. 실전: ApplicationSet + Rollouts 통합

5.1 디렉토리 구조

repo/
├── apps/
│   ├── frontend/
│   │   ├── base/
│   │   │   ├── rollout.yaml
│   │   │   ├── service.yaml
│   │   │   └── kustomization.yaml
│   │   └── overlays/
│   │       ├── dev/
│   │       ├── staging/
│   │       └── prod/
│   └── backend/
│       ├── base/
│       └── overlays/
└── appsets/
    └── all-apps.yaml

5.2 통합 ApplicationSet

apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: all-apps
  namespace: argocd
spec:
  generators:
    - matrix:
        generators:
          - git:
              repoURL: https://github.com/org/gitops.git
              revision: HEAD
              directories:
                - path: apps/*
          - list:
              elements:
                - env: dev
                  cluster: https://dev-k8s.example.com
                - env: staging
                  cluster: https://staging-k8s.example.com
                - env: prod
                  cluster: https://prod-k8s.example.com
  strategy:
    type: RollingSync
    rollingSync:
      steps:
        - matchExpressions:
            - key: env
              operator: In
              values: [dev]
        - matchExpressions:
            - key: env
              operator: In
              values: [staging]
        - matchExpressions:
            - key: env
              operator: In
              values: [prod]
  template:
    metadata:
      name: '{{path.basename}}-{{env}}'
      labels:
        app: '{{path.basename}}'
        env: '{{env}}'
    spec:
      project: default
      source:
        repoURL: https://github.com/org/gitops.git
        targetRevision: HEAD
        path: '{{path}}/overlays/{{env}}'
      destination:
        server: '{{cluster}}'
        namespace: '{{path.basename}}'
      syncPolicy:
        automated:
          prune: true
          selfHeal: true
        syncOptions:
          - CreateNamespace=true

6. ArgoCD CLI 운영 명령어

# ApplicationSet 상태 확인
argocd appset list
argocd appset get myapp-progressive

# 특정 Application Sync 상태
argocd app get myapp-prod --refresh

# 수동 Sync (Progressive에서 수동 승인 필요 시)
argocd app sync myapp-staging

# Rollout 상태 확인 (Argo Rollouts kubectl plugin)
kubectl argo rollouts status myapp -n myapp
kubectl argo rollouts get rollout myapp -n myapp -w

# Canary 수동 승인
kubectl argo rollouts promote myapp -n myapp

# 롤백
kubectl argo rollouts undo myapp -n myapp

7. 모범 사례

  1. Progressive Sync 필수: prod 배포 시 반드시 단계적 롤아웃
  2. AnalysisTemplate 연동: 메트릭 기반 자동 롤백 설정
  3. App of Apps 대신 ApplicationSet: 관리 복잡도 대폭 감소
  4. Matrix Generator 활용: 앱 × 환경 조합 자동화
  5. Sync Wave 활용: 의존성 있는 리소스 순서 제어
  6. Notification 연동: Slack/Telegram으로 배포 상태 알림

이 시리즈에서 다음에 읽을 글

8. 퀴즈

Q1. ApplicationSet의 핵심 역할은?

하나의 템플릿에서 여러 ArgoCD Application을 자동 생성. 멀티클러스터/멀티환경 배포 자동화.

Q2. Matrix Generator는 어떻게 동작하는가?

두 Generator의 결과를 **교차 결합(Cartesian product)**하여 모든 조합에 대해 Application을 생성한다.

Q3. Progressive Sync의 maxUpdate: 50%는 무엇을 의미하는가?

해당 단계의 Application 중 50%만 동시에 Sync하고, 성공 후 나머지 50%를 진행한다.

Q4. Argo Rollouts의 AnalysisTemplate 실패 시 어떻게 되는가?

자동으로 롤백된다. failureLimit을 초과하면 Rollout이 Degraded 상태가 되고 이전 버전으로 복원.

Q5. Blue-Green에서 autoPromotionEnabled: false의 의미는?

Preview 환경 검증 후 수동으로 promote해야 Active로 전환된다. kubectl argo rollouts promote 명령 필요.

Q6. Canary 배포에서 trafficRouting을 설정하는 이유는?

실제 트래픽의 비율을 정밀하게 제어하기 위함. Istio/Nginx/ALB 등과 연동하여 Pod 수가 아닌 트래픽 비율 기반 Canary를 구현.

Q7. App of Apps 패턴 대비 ApplicationSet의 장점은?

(1) 단일 리소스로 관리 (2) Generator를 통한 자동 검색 (3) Progressive Sync 지원 (4) 코드 중복 제거