📋 요약
이 글에서는 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로 전환하는 방법](https://blog.kakaocdn.net/dna/d3GBEk/dJMcagFNPXu/AAAAAAAAAAAAAAAAAAAAANtLp0-8tmDLkd1EDIJEw1AQNUeqqC7Z7bCNwtHANwry/img.png?credential=yqXZFxpELC7KVnFOS48ylbz2pIh7yKj8&expires=1782831599&allow_ip=&allow_referer=&signature=ILxS9rJOujMi%2BbQ9YYCdu6EaKkY%3D)
이번 전환의 핵심은 "ArgoCD를 어떻게 배포하느냐"가 아니라, 플랫폼 인프라 자체도 동일한 GitOps 원칙으로 관리할 수 있다는 것을 확인한 데 있습니다.
values 변경은 해당 파일만 수정하고 커밋하면 끝이고, 버전 업그레이드는 HelmRelease의 version 한 줄만 바꾸면 FluxCD가 나머지를 처리합니다. PR diff에는 실제로 바뀐 내용만 잡히고, 렌더링 결과물 전체가 노이즈로 따라오는 일도 없습니다.
물론 처음 전환할 때는 ConfigMap 순서 문제, disableNameSuffixHash 설정, tracking 어노테이션 정리 등 작은 함정들이 있었지만, 한 번 정리해두면 다음 앱을 전환할 때는 같은 패턴을 그대로 가져다 쓸 수 있습니다.
저희 팀은 이 패턴을 ArgoCD에 적용한 뒤, 동일한 방식으로 클러스터 내 다른 인프라 컴포넌트들로 점진적으로 확산하고 있습니다. "배포 도구도 코드로 관리한다"는 원칙이 팀 안에 자리잡히는 과정이기도 합니다.
❓ 자주 묻는 질문 (FAQ)
'Tech Story > DevOps & Container' 카테고리의 다른 글
| [기술분석] Kubernetes Gateway API에서 트래픽을 세밀하게 제어하는 Policy 객체 파헤치기 (0) | 2026.06.05 |
|---|---|
| [운영가이드] Kubernetes 기반 Fault-Tolerant GPU 클러스터 유지 관리 (0) | 2026.06.04 |
| [기술 분석] kubernetes Ingress API의 중단. 그 뒤를 잇는 Gateway API 파헤치기 (0) | 2026.05.22 |
| [분석] Kubernetes v1.35 Timbernetes: 6년 만의 GA, AI 스케줄링, 기술 부채 개선 (0) | 2026.05.08 |
| [트러블슈팅] Kubernetes StatefulSet 스토리지 확장: Non-cascade 전략으로 무중단 Immutable 제약 극복 (0) | 2026.04.23 |