Skip to content

필사 모드: GitOps 실전 가이드: ArgoCD vs FluxCD 아키텍처 비교와 프로덕션 배포 전략

한국어
0%
정확도 0%
💡 왼쪽 원문을 읽으면서 오른쪽에 따라 써보세요. Tab 키로 힌트를 받을 수 있습니다.
원문 렌더가 준비되기 전까지 텍스트 가이드로 표시합니다.

들어가며

현대 클라우드 네이티브 환경에서 Kubernetes 배포를 관리하는 방법은 크게 **Push 기반**과 **Pull 기반**으로 나뉜다. 전통적인 CI/CD 파이프라인은 Push 방식으로 빌드 완료 후 `kubectl apply`나 `helm upgrade`를 실행하여 클러스터에 변경을 밀어넣는다. 이 방식은 CI 서버에 클러스터 접근 권한을 부여해야 하고, 수동 변경(kubectl edit, 콘솔 수정)으로 인한 드리프트를 감지하기 어렵다는 근본적인 한계가 있다.

**GitOps**는 이 문제를 해결하는 운영 패러다임으로, Git 저장소를 **단일 진실 소스(Single Source of Truth)**로 삼고, 클러스터 내부의 에이전트가 Git의 원하는 상태와 실제 상태를 지속적으로 비교하여 **자동으로 동기화(Reconciliation)**한다. OpenGitOps 프로젝트가 정의한 핵심 원칙은 다음과 같다.

1. **선언적(Declarative)**: 시스템의 원하는 상태를 선언적으로 기술한다

2. **버전 관리(Versioned and Immutable)**: Git에 모든 변경 이력이 남아 감사 추적이 가능하다

3. **자동 적용(Pulled Automatically)**: 에이전트가 자동으로 원하는 상태를 클러스터에 적용한다

4. **지속적 조정(Continuously Reconciled)**: 드리프트를 자동으로 감지하고 수정한다

이 글에서는 GitOps를 구현하는 대표적인 두 가지 도구인 **ArgoCD**와 **FluxCD**의 아키텍처를 심층 비교하고, 실제 프로덕션 환경에서의 배포 전략, 시크릿 관리, CI/CD 통합, 장애 사례와 복구, 운영 체크리스트까지 종합적으로 다룬다.

ArgoCD 아키텍처 심층 분석

핵심 구성 요소

ArgoCD는 CNCF Graduated 프로젝트로, Kubernetes 전용 GitOps 지속적 배포 도구이다. 기본적으로 웹 UI, CLI, gRPC/REST API를 제공한다.

ArgoCD Application 리소스 예시

apiVersion: argoproj.io/v1alpha1

kind: Application

metadata:

name: my-app

namespace: argocd

spec:

project: default

source:

repoURL: https://github.com/org/k8s-manifests.git

targetRevision: main

path: apps/my-app/overlays/production

destination:

server: https://kubernetes.default.svc

namespace: production

syncPolicy:

automated:

prune: true

selfHeal: true

allowEmpty: false

syncOptions:

- CreateNamespace=true

- PrunePropagationPolicy=foreground

- PruneLast=true

retry:

limit: 5

backoff:

duration: 5s

factor: 2

maxDuration: 3m

ArgoCD의 주요 컴포넌트는 다음과 같다.

- **API Server**: 웹 UI, CLI, CI/CD 시스템이 사용하는 gRPC/REST API를 제공한다

- **Repo Server**: Git 저장소를 클론하고 매니페스트를 생성한다. Helm, Kustomize, Jsonnet 등을 지원한다

- **Application Controller**: Application 리소스를 감시하고 조정 루프를 실행한다

- **Redis**: UI 세션과 캐시를 저장한다

- **Dex**: SSO(Single Sign-On) 인증을 담당한다

- **Notifications Controller**: Slack, 이메일 등으로 동기화 상태 알림을 전송한다

App of Apps 패턴

대규모 환경에서는 **App of Apps** 패턴을 사용하여 여러 Application을 하나의 부모 Application으로 관리한다.

부모 Application (root-app)

apiVersion: argoproj.io/v1alpha1

kind: Application

metadata:

name: root-app

namespace: argocd

spec:

project: default

source:

repoURL: https://github.com/org/k8s-manifests.git

targetRevision: main

path: apps

destination:

server: https://kubernetes.default.svc

namespace: argocd

syncPolicy:

automated:

prune: true

selfHeal: true

apps 디렉토리 안에 각 서비스의 Application YAML 파일을 배치하면, root-app이 이를 자동으로 생성하고 관리한다.

ApplicationSet 컨트롤러

ApplicationSet은 하나의 템플릿으로 여러 Application을 동적으로 생성한다. 멀티 클러스터, 멀티 테넌트, 모노레포 환경에서 매우 유용하다.

apiVersion: argoproj.io/v1alpha1

kind: ApplicationSet

metadata:

name: cluster-apps

namespace: argocd

spec:

generators:

- clusters:

selector:

matchLabels:

environment: production

template:

metadata:

name: 'app-{{name}}'

spec:

project: default

source:

repoURL: https://github.com/org/k8s-manifests.git

targetRevision: main

path: 'apps/{{metadata.labels.region}}/production'

destination:

server: '{{server}}'

namespace: production

syncPolicy:

automated:

prune: true

selfHeal: true

이 ApplicationSet은 `environment: production` 레이블이 있는 모든 클러스터에 대해 자동으로 Application을 생성한다.

Sync Waves와 Hooks

ArgoCD의 Sync Wave는 리소스 배포 순서를 정밀하게 제어한다.

Wave 0: Namespace와 RBAC 먼저 생성

apiVersion: v1

kind: Namespace

metadata:

name: production

annotations:

argocd.argoproj.io/sync-wave: '0'

Wave 1: ConfigMap과 Secret

apiVersion: v1

kind: ConfigMap

metadata:

name: app-config

namespace: production

annotations:

argocd.argoproj.io/sync-wave: '1'

data:

DATABASE_HOST: 'postgres.production.svc'

LOG_LEVEL: 'info'

Wave 2: Deployment

apiVersion: apps/v1

kind: Deployment

metadata:

name: api-server

namespace: production

annotations:

argocd.argoproj.io/sync-wave: '2'

spec:

replicas: 3

selector:

matchLabels:

app: api-server

template:

metadata:

labels:

app: api-server

spec:

containers:

- name: api-server

image: myregistry/api-server:v2.1.0

ports:

- containerPort: 8080

PreSync Hook: DB 마이그레이션

apiVersion: batch/v1

kind: Job

metadata:

name: db-migration

namespace: production

annotations:

argocd.argoproj.io/hook: PreSync

argocd.argoproj.io/hook-delete-policy: HookSucceeded

spec:

template:

spec:

containers:

- name: migrate

image: myregistry/db-migrate:v2.1.0

command: ['./migrate', 'up']

restartPolicy: Never

FluxCD 아키텍처 심층 분석

핵심 구성 요소

FluxCD는 CNCF Graduated 프로젝트로, Kubernetes 네이티브 GitOps 툴킷이다. 여러 개의 독립적인 컨트롤러로 구성되어 있다.

- **Source Controller**: Git 저장소, Helm 저장소, OCI 아티팩트, S3 버킷 등 소스를 관리한다

- **Kustomize Controller**: Kustomization 리소스를 감시하고 클러스터에 매니페스트를 적용한다

- **Helm Controller**: HelmRelease 리소스를 감시하고 Helm 차트를 관리한다

- **Notification Controller**: 이벤트 알림 및 외부 웹훅 수신을 처리한다

- **Image Reflector/Automation Controllers**: 컨테이너 레지스트리의 새 이미지를 감지하고 자동으로 Git을 업데이트한다

GitRepository와 Kustomization

FluxCD의 기본 워크플로우는 GitRepository로 소스를 정의하고 Kustomization으로 적용 방법을 기술하는 것이다.

소스 정의

apiVersion: source.toolkit.fluxcd.io/v1

kind: GitRepository

metadata:

name: k8s-manifests

namespace: flux-system

spec:

interval: 1m

url: https://github.com/org/k8s-manifests.git

ref:

branch: main

secretRef:

name: git-credentials

ignore: |

불필요한 파일 제외

docs/

README.md

적용 정의

apiVersion: kustomize.toolkit.fluxcd.io/v1

kind: Kustomization

metadata:

name: production-apps

namespace: flux-system

spec:

interval: 5m

retryInterval: 2m

timeout: 3m

sourceRef:

kind: GitRepository

name: k8s-manifests

path: ./apps/production

prune: true

force: false

targetNamespace: production

healthChecks:

- apiVersion: apps/v1

kind: Deployment

name: api-server

namespace: production

postBuild:

substituteFrom:

- kind: ConfigMap

name: cluster-vars

HelmRelease 컨트롤러

FluxCD의 Helm Controller는 HelmRelease CRD를 통해 Helm 차트의 라이프사이클을 선언적으로 관리한다.

apiVersion: source.toolkit.fluxcd.io/v1

kind: HelmRepository

metadata:

name: bitnami

namespace: flux-system

spec:

interval: 30m

url: https://charts.bitnami.com/bitnami

apiVersion: helm.toolkit.fluxcd.io/v2

kind: HelmRelease

metadata:

name: postgresql

namespace: production

spec:

interval: 10m

chart:

spec:

chart: postgresql

version: '15.x'

sourceRef:

kind: HelmRepository

name: bitnami

namespace: flux-system

values:

primary:

persistence:

size: 50Gi

resources:

requests:

memory: 512Mi

cpu: 250m

metrics:

enabled: true

upgrade:

remediation:

retries: 3

remediateLastFailure: true

rollback:

cleanupOnFail: true

timeout: 5m

FluxCD 의존성 관리

Kustomization 리소스 간 의존성을 선언하여 배포 순서를 제어할 수 있다.

apiVersion: kustomize.toolkit.fluxcd.io/v1

kind: Kustomization

metadata:

name: infrastructure

namespace: flux-system

spec:

interval: 10m

sourceRef:

kind: GitRepository

name: k8s-manifests

path: ./infrastructure

prune: true

apiVersion: kustomize.toolkit.fluxcd.io/v1

kind: Kustomization

metadata:

name: applications

namespace: flux-system

spec:

interval: 10m

dependsOn:

- name: infrastructure

sourceRef:

kind: GitRepository

name: k8s-manifests

path: ./applications

prune: true

infrastructure Kustomization이 성공적으로 적용된 후에만 applications가 적용된다.

ArgoCD vs FluxCD 비교표

| 항목 | ArgoCD | FluxCD |

| ------------------------ | --------------------------------------- | -------------------------------------------- |

| **CNCF 등급** | Graduated | Graduated |

| **웹 UI** | O (내장, 풍부한 기능) | X (별도 Weave GitOps UI 사용) |

| **CLI** | argocd CLI | flux CLI |

| **아키텍처** | 모놀리식 (여러 컴포넌트가 하나로) | 마이크로서비스 (독립 컨트롤러) |

| **CRD** | Application, ApplicationSet, AppProject | GitRepository, Kustomization, HelmRelease 등 |

| **멀티 클러스터** | 허브-스포크 모델 | 클러스터별 Flux 설치 |

| **Helm 지원** | O (소스로 직접 참조) | O (HelmRelease CRD) |

| **Kustomize** | O | O (네이티브) |

| **RBAC** | 자체 RBAC + SSO 통합 | Kubernetes 네이티브 RBAC |

| **알림** | Notification Controller | Notification Controller |

| **이미지 자동 업데이트** | Image Updater (별도 설치) | Image Automation Controller |

| **드리프트 감지** | O (실시간 UI 표시) | O (이벤트 기반) |

| **Sync Wave/순서** | Sync Wave + Hook | dependsOn 의존성 |

| **SSO 지원** | O (Dex 내장) | X (Kubernetes RBAC 위임) |

| **멀티 테넌시** | AppProject 기반 | 네임스페이스 기반 |

| **Git 지원** | GitHub, GitLab, Bitbucket 등 | GitHub, GitLab, Bitbucket, S3, OCI 등 |

| **학습 곡선** | 중간 (UI가 도움) | 높음 (CLI 중심) |

| **리소스 사용량** | 상대적으로 높음 | 상대적으로 낮음 |

배포 전략

Blue-Green 배포 (Argo Rollouts)

ArgoCD와 함께 Argo Rollouts를 사용하면 Blue-Green 배포를 선언적으로 구현할 수 있다.

apiVersion: argoproj.io/v1alpha1

kind: Rollout

metadata:

name: api-server

namespace: production

spec:

replicas: 5

strategy:

blueGreen:

activeService: api-server-active

previewService: api-server-preview

autoPromotionEnabled: false

prePromotionAnalysis:

templates:

- templateName: success-rate

args:

- name: service-name

value: api-server-preview

scaleDownDelaySeconds: 30

selector:

matchLabels:

app: api-server

template:

metadata:

labels:

app: api-server

spec:

containers:

- name: api-server

image: myregistry/api-server:v2.2.0

ports:

- containerPort: 8080

readinessProbe:

httpGet:

path: /healthz

port: 8080

initialDelaySeconds: 10

periodSeconds: 5

apiVersion: argoproj.io/v1alpha1

kind: AnalysisTemplate

metadata:

name: success-rate

namespace: production

spec:

args:

- name: service-name

metrics:

- name: success-rate

interval: 30s

count: 5

successCondition: result[0] >= 0.95

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]))

Canary 배포 (Flagger + FluxCD)

FluxCD 환경에서는 Flagger를 사용하여 Canary 배포를 자동화한다.

apiVersion: flagger.app/v1beta1

kind: Canary

metadata:

name: api-server

namespace: production

spec:

targetRef:

apiVersion: apps/v1

kind: Deployment

name: api-server

service:

port: 8080

targetPort: 8080

analysis:

interval: 1m

threshold: 5

maxWeight: 50

stepWeight: 10

metrics:

- name: request-success-rate

thresholdRange:

min: 99

interval: 1m

- name: request-duration

thresholdRange:

max: 500

interval: 1m

webhooks:

- name: load-test

type: rollout

url: http://flagger-loadtester.production/

metadata:

cmd: 'hey -z 1m -q 10 -c 2 http://api-server-canary.production:8080/'

시크릿 관리

SOPS (Secrets OPerationS)

SOPS는 파일 레벨에서 시크릿을 암호화하여 Git에 안전하게 저장하는 도구이다. FluxCD는 SOPS를 네이티브로 지원한다.

.sops.yaml (저장소 루트에 배치)

creation_rules:

- path_regex: .*.enc.yaml

encrypted_regex: '^(data|stringData)$'

age: age1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

시크릿 암호화

sops --encrypt --in-place secrets/production/db-credentials.enc.yaml

FluxCD Kustomization에서 SOPS 복호화 활성화

flux create kustomization production-secrets \

--source=GitRepository/k8s-manifests \

--path="./secrets/production" \

--prune=true \

--interval=10m \

--decryption-provider=sops \

--decryption-secret=sops-age

Sealed Secrets

Sealed Secrets는 비대칭 암호화를 사용하여 시크릿을 Git에 안전하게 저장한다.

SealedSecret 생성

kubectl create secret generic db-credentials \

--from-literal=username=admin \

--from-literal=password=supersecret \

--dry-run=client -o yaml | \

kubeseal --controller-name=sealed-secrets \

--controller-namespace=kube-system \

--format=yaml > sealed-db-credentials.yaml

apiVersion: bitnami.com/v1alpha1

kind: SealedSecret

metadata:

name: db-credentials

namespace: production

spec:

encryptedData:

username: AgBy3i4OJSWK+PiTySYZZA9rO43cGDEq...

password: AgBy3i4OJSWK+PiTySYZZA9rO43cGDEq...

template:

type: Opaque

metadata:

name: db-credentials

namespace: production

Vault 통합 (ArgoCD Vault Plugin)

HashiCorp Vault와 ArgoCD를 통합하여 시크릿을 동적으로 주입한다.

apiVersion: v1

kind: Secret

metadata:

name: db-credentials

namespace: production

annotations:

avp.kubernetes.io/path: 'secret/data/production/database'

type: Opaque

stringData:

username: <username>

password: <password>

위 매니페스트에서 `<username>`과 `<password>`는 ArgoCD Vault Plugin이 Vault에서 값을 조회하여 실제 시크릿 값으로 대체한다.

CI/CD 통합 패턴

GitHub Actions + ArgoCD

.github/workflows/deploy.yml

name: Build and Deploy

on:

push:

branches: [main]

jobs:

build:

runs-on: ubuntu-latest

steps:

- uses: actions/checkout@v4

- name: Build and Push Image

run: |

docker build -t myregistry/api-server:$GITHUB_SHA .

docker push myregistry/api-server:$GITHUB_SHA

- name: Update Kubernetes Manifests

run: |

git clone https://github.com/org/k8s-manifests.git

cd k8s-manifests

kustomize edit set image myregistry/api-server=myregistry/api-server:$GITHUB_SHA

git add .

git commit -m "chore: update api-server image to $GITHUB_SHA"

git push

이 패턴에서 CI(GitHub Actions)는 이미지 빌드와 매니페스트 저장소 업데이트만 담당하고, 실제 배포는 ArgoCD가 Git 변경을 감지하여 자동으로 수행한다.

장애 사례와 복구 절차

사례 1: Sync Loop (무한 동기화 루프)

**상황**: ArgoCD Application이 Sync 완료 후 즉시 OutOfSync 상태로 전환되어 무한 동기화 루프에 빠졌다. 원인은 Admission Webhook이 리소스에 기본값을 주입하면서 Git의 매니페스트와 차이가 발생한 것이었다.

**증상**:

- Application 상태가 Synced와 OutOfSync를 반복

- ArgoCD API Server CPU 사용량 급증

- Repo Server 메모리 사용량 증가

**복구 절차**:

1. 자동 동기화 일시 중단

argocd app set my-app --sync-policy none

2. 드리프트 원인 분석

argocd app diff my-app --local ./manifests/

3. ignoreDifferences 설정으로 Webhook 주입 필드 무시

argocd app set my-app --ignore-differences \

'group=apps, kind=Deployment, jsonPointers=[/spec/template/metadata/annotations]'

4. 매니페스트에 Webhook이 주입하는 기본값을 명시적으로 추가

5. 자동 동기화 재활성화

argocd app set my-app --sync-policy automated

사례 2: 드리프트 감지 실패

**상황**: FluxCD의 Kustomization이 성공 상태를 보고하지만, 실제 클러스터에서 수동으로 변경된 리소스가 복원되지 않았다. force 옵션이 비활성화되어 있었고, 수동 변경이 FluxCD가 관리하지 않는 필드에서 발생했다.

**증상**:

- Kustomization 상태는 Ready

- 실제 리소스의 설정이 Git과 다름

- kubectl diff로 차이 확인 가능

**복구 절차**:

1. FluxCD 강제 조정 트리거

flux reconcile kustomization production-apps --with-source

2. force 옵션 활성화 (server-side apply 사용)

flux create kustomization production-apps \

--source=GitRepository/k8s-manifests \

--path="./apps/production" \

--prune=true \

--force=true \

--interval=5m

3. 수동 변경 방지를 위한 OPA 정책 추가

(kubectl edit, kubectl patch 등을 제한)

사례 3: Helm Release 롤백 실패

**상황**: FluxCD HelmRelease의 업그레이드가 실패했으나 자동 롤백이 동작하지 않았다. remediation 설정에서 remediateLastFailure가 false로 되어 있었다.

**증상**:

- HelmRelease 상태가 Failed

- 이전 버전의 릴리스도 손상됨

- Helm history에 failed 릴리스가 누적

**복구 절차**:

1. HelmRelease 상태 확인

flux get helmrelease -n production

2. Helm 릴리스 히스토리 확인

helm history postgresql -n production

3. 수동 롤백

helm rollback postgresql 3 -n production

4. HelmRelease 설정에 자동 복구 추가

flux create helmrelease postgresql \

--source=HelmRepository/bitnami \

--chart=postgresql \

--chart-version="15.x" \

--target-namespace=production \

--values=values/postgresql.yaml \

--remediation-retries=3

프로덕션 배포 체크리스트

사전 준비

- [ ] Git 저장소 구조 설계 (모노레포 vs 폴리레포 결정)

- [ ] 브랜치 전략 수립 (main -> staging -> production)

- [ ] RBAC 정책 설계 (어떤 팀이 어떤 Application/Kustomization을 관리할지)

- [ ] 시크릿 관리 방법 결정 (SOPS, Sealed Secrets, Vault 중 선택)

ArgoCD 설정

- [ ] HA(고가용성) 모드로 배포 (최소 3개 레플리카)

- [ ] Redis Sentinel 또는 Redis Cluster 구성

- [ ] Dex 또는 OIDC를 통한 SSO 설정

- [ ] AppProject별 소스 저장소와 대상 클러스터 제한

- [ ] Resource Exclusions/Inclusions 설정으로 관리 범위 명확화

FluxCD 설정

- [ ] 각 클러스터에 독립적인 FluxCD 설치

- [ ] Source Controller의 Git 폴링 간격 최적화 (기본 1분)

- [ ] Kustomization의 헬스체크 대상 리소스 지정

- [ ] Notification Controller로 Slack/Teams 알림 구성

운영 주의사항

- [ ] Git 저장소의 write 권한을 최소화 (PR 기반 변경)

- [ ] 프로덕션 배포는 반드시 PR 리뷰 후 머지

- [ ] 동기화 간격과 타임아웃을 워크로드 특성에 맞게 조정

- [ ] 대규모 매니페스트 변경 시 Sync Wave나 dependsOn으로 순서 보장

- [ ] Helm 차트 버전을 범위가 아닌 고정 버전으로 지정

- [ ] 롤백을 위한 Git revert 프로세스 문서화

모니터링

- [ ] ArgoCD: Application 동기화 상태 메트릭 수집 (`argocd_app_info`)

- [ ] FluxCD: Kustomization/HelmRelease 상태 메트릭 수집

- [ ] 동기화 실패 시 자동 알림 설정 (PagerDuty, OpsGenie 연동)

- [ ] 정기적인 드리프트 감사 리포트 생성

마치며

GitOps는 Kubernetes 배포 관리의 표준으로 자리 잡았다. ArgoCD와 FluxCD 모두 CNCF Graduated 프로젝트로서 성숙한 생태계를 갖추고 있으며, 어떤 도구를 선택하든 GitOps의 핵심 원칙을 충실히 구현할 수 있다.

ArgoCD는 풍부한 웹 UI와 ApplicationSet을 통한 멀티 클러스터 관리, Argo Rollouts와의 통합을 강점으로 한다. FluxCD는 Kubernetes 네이티브한 마이크로서비스 아키텍처, 가벼운 리소스 사용량, SOPS 네이티브 지원을 강점으로 한다.

중요한 것은 도구의 선택보다 **GitOps 문화의 정착**이다. 모든 변경이 Git을 통해 이루어지도록 프로세스를 수립하고, 수동 변경을 방지하는 가드레일을 구축하며, 드리프트를 지속적으로 감지하고 수정하는 자동화 체계를 갖추는 것이 진정한 GitOps의 완성이다.

참고자료

- [ArgoCD 공식 문서](https://argo-cd.readthedocs.io/en/stable/)

- [FluxCD 공식 문서](https://fluxcd.io/docs/)

- [OpenGitOps 프로젝트](https://opengitops.dev/)

- [ArgoCD vs Flux in 2025: The GitOps War Is Over](https://aws.plainenglish.io/argocd-vs-flux-in-2025-the-gitops-war-is-over-and-you-won-d22e084929a5)

- [Flux vs ArgoCD - Spacelift Blog](https://spacelift.io/blog/flux-vs-argo-cd)

현재 단락 (1/517)

현대 클라우드 네이티브 환경에서 Kubernetes 배포를 관리하는 방법은 크게 **Push 기반**과 **Pull 기반**으로 나뉜다. 전통적인 CI/CD 파이프라인은 Push ...

작성 글자: 0원문 글자: 13,969작성 단락: 0/517