[전환가이드] ArgoCD·FluxCD GitOps 배포를 HelmRelease로 전환하는 방법

Tech Story/DevOps & Container

[전환가이드] ArgoCD·FluxCD GitOps 배포를 HelmRelease로 전환하는 방법

 

 
[ kt cloud Foundation플랫폼팀 이지은 님 ]

📋 요약

이 글에서는 ArgoCD와 FluxCD 기반 GitOps 배포를 HelmRelease 방식으로 전환하는 과정과 운영 시 고려사항을 다룹니다.

인프라 배포를 선언적으로 관리해 변경 추적과 운영 안정성을 높이는 방향을 정리합니다.

#ArgoCD #FluxCD #GitOps #HelmRelease #Kubernetes

 


안녕하세요. 지난 글에서 OpenStack Helm 배포를 FluxCD HelmRelease 방식으로 전환한 경험을 공유드렸는데요.

이번에는 그 연장선으로 ArgoCD 자체를 동일한 방식으로 전환한 이야기입니다.

 

"배포 도구인 ArgoCD를 ArgoCD+FluxCD로 관리한다"는 다소 순환적으로 들릴 수 있지만, 실제로 해보면 명확한 이유와 이점이 있습니다.

1. 왜 ArgoCD 자체를 전환했나?

기존 방식은 이렇습니다.

helm template argocd -n argocd argo/argo-cd \
  --version 8.3.1 \
  --values argocd-helm-overrides-ktcloud.yaml \
  --namespace=argocd > argocd.yaml

 

Helm Chart를 미리 렌더링해 정적 YAML을 만들고, ArgoCD가 그 파일을 Git에서 읽어 배포합니다. 단순하지만 문제가 있습니다.

  • 버전을 업그레이드할 때마다 렌더링을 다시 돌려 argocd.yaml을 새로 커밋해야 합니다.
  • values 하나 바꿔도 렌더링 결과물 전체가 diff에 잡혀 비교가 어렵습니다.
  • ArgoCD values가 길어질수록 파일 하나에 모든 설정이 몰려 가독성이 떨어집니다.

FluxCD HelmRelease 방식으로 전환하면 이 문제가 깔끔하게 해결됩니다.


2. 전환 후 아키텍처

Git (HelmRelease + ConfigMap)
  └─ ArgoCD → HelmRelease 오브젝트 sync
      └─ FluxCD → Harbor OCI에서 Chart pull → 실제 배포

 

ArgoCD는 선언(HelmRelease)을 동기화하고, FluxCD가 Helm 라이프사이클(install/upgrade/rollback)을 수행합니다. ArgoCD 자체가 FluxCD에 의해 관리되는 구조입니다.

 

[배포 흐름도]

┌─────────────┐    sync     ┌──────────────────┐
│   ArgoCD    │ ──────────▶ │   HelmRelease    │
│  (Git 감시)  │             │  (FluxCD 오브젝트)  │
└─────────────┘             └────────┬─────────┘
                                     │ chart pull
                                     ▼
                            ┌──────────────────┐
                            │  Harbor OCI      │
                            │  (에어갭 레지스트리)  │
                            └────────┬─────────┘
                                     │ helm install/upgrade
                                     ▼
                            ┌──────────────────┐
                            │  실제 ArgoCD 리소스 │
                            │  (Deployment 등)  │
                            └──────────────────┘

3. 에어갭 환경: Harbor에 Chart 먼저 올리기

내부망이 차단된 환경에서는 외부 Chart를 Harbor OCI 레지스트리에 미리 업로드해야 합니다.

# 외부 인터넷 환경에서 다운로드
helm repo add argo https://argoproj.github.io/argo-helm
helm pull argo/argo-cd --version 8.3.1

# 내부 Harbor에 push
helm registry login harbor.ktcloud.com \
  --username <USERNAME> --password <PASSWORD>

helm push argo-cd-8.3.1.tgz oci://harbor.ktcloud.com/charts
# 결과: harbor.ktcloud.com/charts/argo-cd:8.3.1

 

⚠️ helm push 시 차트명과 버전을 직접 지정하지 않습니다. .tgz 파일명에서 자동으로 읽어 태그로 붙습니다.


4. values 관리: 인라인 vs 파일 분리

ArgoCD의 values는 양이 많고, 권한 관리로 수정이 자주 일어나 파일 분리 방식을 권장합니다. 기존 patches 구조처럼 역할별로 나눕니다.

argocd/
├── kustomization.yaml
├── namespace.yaml
├── argocd-helmrelease.yaml
├── argocd-httproute.yaml
├── appproject.yaml
├── values-cm.yaml                    # argocd-cm 관련
├── values-rbac-cm.yaml               # argocd-rbac-cm 관련 (200줄 수준)
├── values-notifications-cm.yaml      # argocd-notifications-cm 관련
└── values-notifications-secret.yaml  # argocd-notifications-secret 관련

 

HelmRelease에서 valuesFrom으로 참조:

apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
  name: argocd
  namespace: argocd
  annotations:
    argocd.argoproj.io/sync-wave: "1"  # ConfigMap 생성 후 배포
spec:
  interval: 1h
  chart:
    spec:
      chart: argo-cd
      version: "8.3.1"
      sourceRef:
        kind: HelmRepository
        name: registry-ys-stack-chart-repo
        namespace: flux-system
      interval: 1h
  install:
    remediation:
      retries: 3
  upgrade:
    remediation:
      retries: 3
  valuesFrom:
    - kind: ConfigMap
      name: argocd-values-cm
      valuesKey: values-cm.yaml
    - kind: ConfigMap
      name: argocd-values-rbac-cm
      valuesKey: values-rbac-cm.yaml
    - kind: ConfigMap
      name: argocd-values-notifications-cm
      valuesKey: values-notifications-cm.yaml
    - kind: ConfigMap
      name: argocd-values-notifications-secret
      valuesKey: values-notifications-secret.yaml

 

kustomization.yaml에서 ConfigMap 생성:

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

sortOptions:
  order: fifo

resources:
  - namespace.yaml
  - argocd-helmrelease.yaml
  - argocd-httproute.yaml
  - appproject.yaml

generatorOptions:
  disableNameSuffixHash: true     # 고정 이름으로 참조하므로 필수

configMapGenerator:
  - name: argocd-values-cm
    files:
      - values-cm.yaml
  - name: argocd-values-rbac-cm
    files:
      - values-rbac-cm.yaml
  - name: argocd-values-notifications-cm
    files:
      - values-notifications-cm.yaml
  - name: argocd-values-notifications-secret
    files:
      - values-notifications-secret.yaml

ℹ️ disableNameSuffixHash: true를 반드시 설정해야 합니다. Kustomize는 기본적으로 ConfigMap 이름 뒤에 해시를 붙이는데, valuesFrom에서 고정 이름으로 참조하기 때문에 해시가 붙으면 참조가 깨집니다.


5. 핵심 함정: ConfigMap → HelmRelease 배포 순서

valuesFrom으로 ConfigMap을 참조하는 HelmRelease는 ConfigMap이 먼저 존재해야 합니다. ArgoCD Sync를 한 번에 날리면 HelmRelease가 ConfigMap보다 먼저 생성되어 실패할 수 있습니다.

 

해결 방법은 sync-wave입니다.

wave 0: ConfigMap 생성 (argocd-values-cm 등)
wave 1: HelmRelease 생성 → ConfigMap 참조 성공

sync-wave는 Application 내부의 배포 리소스에만 적용되므로, ConfigMap Generator로 생성된 ConfigMap에는 직접 줄 수 없습니다. 대신 HelmRelease에 sync-wave: "1"을 부여하면, ConfigMap(기본 wave 0)이 먼저 생성된 뒤 HelmRelease가 배포되는 순서가 자동으로 보장됩니다.


6. 전환 시 기존 리소스 보호: PRUNE 설정

기존에 렌더링 YAML로 배포된 리소스를 삭제하지 않으려면 반드시 확인이 필요합니다.

kubectl get application <APP_NAME> -n argocd -o yaml | grep prune

수동 Sync 시에도 UI에서 PRUNE 체크박스를 해제한 상태로 진행합니다. FluxCD가 Helm 라이프사이클을 가져가면 변경사항이 없는 한 기존 Pod는 재시작 없이 소유권만 이전됩니다.

 

전환 완료 후 리소스에 붙는 라벨:

labels:
  helm.toolkit.fluxcd.io/name: argocd
  helm.toolkit.fluxcd.io/namespace: argocd

7. ArgoCD UI에서 달라진 점

전환 후 ArgoCD UI에 🗑️ 아이콘이 보이는 리소스들이 생깁니다. 당황하지 않아도 됩니다.

표시 의미
🗑️ + 💚 클러스터에 살아있음 + ArgoCD Git에는 없음 (FluxCD가 관리 중) → 정상
🗑️ 클러스터에도 없음 + ArgoCD Git에도 없음 → 이미 삭제된 리소스
 

6번에서 확인한 FluxCD 라벨(helm.toolkit.fluxcd.io/name)이 정상적으로 붙어 있다면, ArgoCD의 tracking 어노테이션을 제거해 소유권을 완전히 FluxCD로 이전해야 합니다.

 

ArgoCD 버전별 제거 대상:

ArgoCD 버전 tracking 방식 제거 대상
2.2 미만 label app.kubernetes.io/instance
2.2 이상 ~ 3.0 미만 annotation (옵션) argocd.argoproj.io/tracking-id
3.0 이상 annotation (기본값) argocd.argoproj.io/tracking-id
 

FluxCD가 완전히 관리하게 되면 해당 리소스는 ArgoCD에서 점차 보이지 않게 됩니다.


8. 배포 상태 확인

# HelmRelease 상태
flux get helmreleases -n argocd

# 전체 리소스
flux get all -n argocd

# 이벤트 확인
flux events -n argocd

 


결론

[전환가이드] ArgoCD·FluxCD GitOps 배포를 HelmRelease로 전환하는 방법

이번 전환의 핵심은 "ArgoCD를 어떻게 배포하느냐"가 아니라, 플랫폼 인프라 자체도 동일한 GitOps 원칙으로 관리할 수 있다는 것을 확인한 데 있습니다.

 

values 변경은 해당 파일만 수정하고 커밋하면 끝이고, 버전 업그레이드는 HelmRelease의 version 한 줄만 바꾸면 FluxCD가 나머지를 처리합니다. PR diff에는 실제로 바뀐 내용만 잡히고, 렌더링 결과물 전체가 노이즈로 따라오는 일도 없습니다.

 

물론 처음 전환할 때는 ConfigMap 순서 문제, disableNameSuffixHash 설정, tracking 어노테이션 정리 등 작은 함정들이 있었지만, 한 번 정리해두면 다음 앱을 전환할 때는 같은 패턴을 그대로 가져다 쓸 수 있습니다.

 

저희 팀은 이 패턴을 ArgoCD에 적용한 뒤, 동일한 방식으로 클러스터 내 다른 인프라 컴포넌트들로 점진적으로 확산하고 있습니다. "배포 도구도 코드로 관리한다"는 원칙이 팀 안에 자리잡히는 과정이기도 합니다.

 

kt cloud 플랫폼 바로가기

❓ 자주 묻는 질문 (FAQ)

Q. ArgoCD가 자기 자신을 관리하는 게 가능한가요? 닭이 먼저냐 달걀이 먼저냐 문제 아닌가요?
A. ArgoCD가 자기 자신을 관리하는 게 가능합니다. ArgoCD가 먼저 설치된 상태에서 HelmRelease를 sync하면, FluxCD가 이후 Helm 라이프사이클을 가져갑니다. 초기 부트스트랩은 기존 방식으로 하고, 이후 운영은 FluxCD가 담당하는 구조입니다. "자기 자신을 업그레이드"하는 상황도 FluxCD가 처리하므로 실제 운영에서 문제가 없었습니다.
Q. ConfigMap Generator를 쓰면 sync-wave를 ConfigMap에 못 주는데, 순서 보장이 진짜 되나요?
A. 됩니다. sync-wave는 Application 내부 배포 리소스에만 적용되고, ConfigMap Generator의 ConfigMap은 wave 어노테이션을 무시합니다. 대신 HelmRelease에 sync-wave: "1"을 주면 ArgoCD가 wave 0(ConfigMap 포함)을 먼저 처리한 뒤 wave 1(HelmRelease)을 처리하므로 순서가 자동 보장됩니다.
Q. 에어갭 환경에서 Chart 업데이트가 필요하면 어떻게 하나요?
A. 외부 인터넷이 되는 환경에서 새 버전을 helm pull한 뒤 내부 레지스트리에 다시 helm push하고, HelmRelease의 version만 변경하면 됩니다. Chart 업로드와 버전 선언이 분리되어 있어 관리가 깔끔합니다.