Backend

GitOps 심화 시리즈 #3: Flux CD - GitOps Toolkit과 컨트롤러 아키텍처

2026-01-0511 min read

GitOps 심화 시리즈 #3: Flux CD - GitOps Toolkit과 컨트롤러 아키텍처

시리즈 개요

#주제핵심 내용
1GitOps 개요철학과 원칙, Push vs Pull 배포, Reconciliation
2ArgoCD Deep Dive아키텍처, Application CRD, Sync 전략
3Flux CD & GitOps Toolkit컨트롤러 아키텍처, GitRepository, Kustomization
4환경별 설정 관리Kustomize vs Helm, 전략 선택 기준
5Secrets ManagementSealed Secrets, External Secrets, SOPS
6CI/CD 파이프라인 통합Image Updater, Progressive Delivery

Flux란?

Flux는 Kubernetes를 위한 GitOps 도구 집합입니다. 2019년 Weaveworks에서 시작하여 2022년 CNCF Graduated 프로젝트가 되었습니다.

ArgoCD가 단일 애플리케이션이라면, Flux는 GitOps Toolkit이라는 독립적인 컨트롤러들의 집합입니다.

핵심 특징

  • CNCF Graduated 프로젝트: 프로덕션 검증 완료
  • 모듈러 아키텍처: 필요한 컨트롤러만 선택적으로 설치 가능
  • Kubernetes Native: 모든 설정이 CRD로 관리됨
  • Image Automation 내장: 컨테이너 이미지 자동 업데이트 지원
  • Multi-tenancy 지원: 네임스페이스 기반의 팀 격리

[!NOTE] Weaveworks가 2024년 폐업했지만, Flux는 CNCF Graduated 프로젝트로서 커뮤니티와 CNCF의 지원 하에 활발히 개발되고 있습니다.


Flux vs ArgoCD: 철학의 차이

본격적으로 들어가기 전에, 두 도구의 근본적인 설계 철학 차이를 이해해야 합니다.

관점ArgoCDFlux
아키텍처모놀리식 (단일 바이너리)마이크로서비스 (독립 컨트롤러)
UI내장 Web UICLI 중심, UI는 별도 (Weave GitOps)
설치한 번에 전체 설치필요한 컨트롤러만 선택 설치
멀티 클러스터중앙 집중 (Hub-Spoke)분산 (각 클러스터에 Flux 설치)
학습 곡선낮음 (UI 친화적)중간 (CRD 이해 필요)
리소스 사용높음낮음

[!NOTE] 선택 기준: 화려한 UI와 중앙 집중 관리가 필요하면 ArgoCD, 경량화와 유연성이 중요하면 Flux가 적합합니다.


GitOps Toolkit 아키텍처

Flux v2는 GitOps Toolkit이라는 컨트롤러 집합으로 구성됩니다.

컨트롤러 역할

컨트롤러역할CRD
Source ControllerGit, Helm, OCI에서 아티팩트 가져오기GitRepository, HelmRepository, OCIRepository, Bucket
Kustomize ControllerKustomize 매니페스트 적용Kustomization
Helm ControllerHelm 릴리스 관리HelmRelease
Notification Controller이벤트 알림Alert, Provider, Receiver
Image Automation컨테이너 이미지 업데이트 자동화ImageRepository, ImagePolicy, ImageUpdateAutomation

Source Controller

Source Controller는 외부 소스에서 아티팩트를 가져와 클러스터 내에서 사용 가능하게 만듭니다.

GitRepository

가장 기본적인 소스. Git 저장소에서 매니페스트를 가져옵니다:

apiVersion: source.toolkit.fluxcd.io/v1
kind: GitRepository
metadata:
  name: my-app
  namespace: flux-system
spec:
  # 동기화 주기
  interval: 1m
  
  # Git 저장소 URL
  url: https://github.com/myorg/my-app.git
  
  # 브랜치/태그/커밋
  ref:
    branch: main
    # 또는
    # tag: v1.0.0
    # commit: abc123
  
  # 인증 (필요시)
  secretRef:
    name: git-credentials
  
  # 특정 경로만 가져오기
  ignore: |
    # 전체 제외
    /*
    # 특정 디렉토리만 포함
    !/deploy/

인증 설정:

# HTTPS 인증
apiVersion: v1
kind: Secret
metadata:
  name: git-credentials
  namespace: flux-system
type: Opaque
stringData:
  username: git
  password: ghp_xxxxxxxxxxxx  # GitHub PAT

---
# SSH 인증
apiVersion: v1
kind: Secret
metadata:
  name: git-ssh-key
  namespace: flux-system
type: Opaque
stringData:
  identity: |
    -----BEGIN OPENSSH PRIVATE KEY-----
    ...
    -----END OPENSSH PRIVATE KEY-----
  known_hosts: |
    github.com ssh-rsa AAAA...

HelmRepository

Helm Chart Repository에서 차트를 가져옵니다:

apiVersion: source.toolkit.fluxcd.io/v1
kind: HelmRepository
metadata:
  name: bitnami
  namespace: flux-system
spec:
  interval: 1h
  url: https://charts.bitnami.com/bitnami
  
  # OCI Registry도 지원
  # type: oci
  # url: oci://ghcr.io/myorg/charts

OCIRepository

OCI Registry에서 아티팩트를 가져옵니다 (Helm 차트 뿐 아니라 Kustomize 매니페스트도 가능):

apiVersion: source.toolkit.fluxcd.io/v1beta2
kind: OCIRepository
metadata:
  name: podinfo
  namespace: flux-system
spec:
  interval: 5m
  url: oci://ghcr.io/stefanprodan/manifests/podinfo
  ref:
    tag: latest

[!TIP] OCI 아티팩트는 컨테이너 레지스트리에 Kubernetes 매니페스트를 저장하는 방식입니다. Git 없이도 GitOps가 가능해집니다.


Kustomize Controller

Kustomize Controller는 GitRepository에서 가져온 Kustomize 매니페스트를 클러스터에 적용합니다.

Kustomization CRD

apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
  name: my-app
  namespace: flux-system
spec:
  # 동기화 주기
  interval: 10m
  
  # 재시도 주기 (실패 시)
  retryInterval: 2m
  
  # 소스 참조
  sourceRef:
    kind: GitRepository
    name: my-app
  
  # 매니페스트 경로
  path: ./deploy/production
  
  # 타겟 네임스페이스 (모든 리소스에 적용)
  targetNamespace: production
  
  # Git에서 삭제된 리소스 정리
  prune: true
  
  # 타임아웃
  timeout: 5m
  
  # Health Check 대기
  wait: true
  healthChecks:
    - apiVersion: apps/v1
      kind: Deployment
      name: my-app
      namespace: production

Kustomization 간 의존성

Flux의 강력한 기능 중 하나는 의존성 관리입니다:

apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
  name: infrastructure
  namespace: flux-system
spec:
  interval: 10m
  sourceRef:
    kind: GitRepository
    name: infra
  path: ./infrastructure
  prune: true

---
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
  name: apps
  namespace: flux-system
spec:
  interval: 10m
  # infrastructure가 Ready 상태가 된 후에만 적용
  dependsOn:
    - name: infrastructure
  sourceRef:
    kind: GitRepository
    name: apps
  path: ./apps
  prune: true

변수 치환 (Post-build Substitution)

Kustomize 적용 후 변수를 치환할 수 있습니다:

apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
  name: my-app
  namespace: flux-system
spec:
  # ...
  postBuild:
    substitute:
      ENVIRONMENT: production
      REPLICAS: "3"
    substituteFrom:
      - kind: ConfigMap
        name: cluster-config
      - kind: Secret
        name: cluster-secrets
# deployment.yaml (치환 대상)
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app
spec:
  replicas: ${REPLICAS}
  template:
    spec:
      containers:
      - name: app
        env:
        - name: ENVIRONMENT
          value: ${ENVIRONMENT}

Helm Controller

Helm Controller는 Helm 릴리스를 선언적으로 관리합니다.

HelmRelease CRD

apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
  name: nginx
  namespace: default
spec:
  # 동기화 주기
  interval: 10m
  
  # Helm Chart 소스
  chart:
    spec:
      chart: nginx
      version: "15.x"  # SemVer 범위 지원
      sourceRef:
        kind: HelmRepository
        name: bitnami
        namespace: flux-system
  
  # Values 설정
  values:
    replicaCount: 3
    service:
      type: ClusterIP
  
  # Values 파일 참조
  valuesFrom:
    - kind: ConfigMap
      name: nginx-values
      valuesKey: values.yaml
    - kind: Secret
      name: nginx-secrets
      valuesKey: credentials
  
  # Upgrade 설정
  upgrade:
    remediation:
      retries: 3
      remediateLastFailure: true
  
  # Rollback 설정
  rollback:
    recreate: true
    cleanupOnFail: true

Git에서 Helm Chart 사용

HelmRepository 대신 GitRepository에서 직접 차트를 가져올 수도 있습니다:

apiVersion: source.toolkit.fluxcd.io/v1
kind: GitRepository
metadata:
  name: my-charts
  namespace: flux-system
spec:
  interval: 5m
  url: https://github.com/myorg/helm-charts.git
  ref:
    branch: main

---
apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
  name: my-app
  namespace: default
spec:
  interval: 10m
  chart:
    spec:
      chart: ./charts/my-app  # Git 내 경로
      sourceRef:
        kind: GitRepository
        name: my-charts
        namespace: flux-system

Image Automation

Flux의 차별화된 기능: 컨테이너 이미지 버전 자동 업데이트

ImageRepository

컨테이너 레지스트리에서 이미지 태그를 스캔합니다:

apiVersion: image.toolkit.fluxcd.io/v1beta2
kind: ImageRepository
metadata:
  name: my-app
  namespace: flux-system
spec:
  # 스캔할 이미지
  image: ghcr.io/myorg/my-app
  
  # 스캔 주기
  interval: 5m
  
  # 인증 (필요시)
  secretRef:
    name: ghcr-auth

ImagePolicy

어떤 태그를 선택할지 정책을 정의합니다:

apiVersion: image.toolkit.fluxcd.io/v1beta2
kind: ImagePolicy
metadata:
  name: my-app
  namespace: flux-system
spec:
  imageRepositoryRef:
    name: my-app
  
  # 정책: SemVer 범위
  policy:
    semver:
      range: ">=1.0.0"
  
  # 또는: 알파벳순 최신
  # policy:
  #   alphabetical:
  #     order: asc
  
  # 또는: 숫자순 최신
  # policy:
  #   numerical:
  #     order: asc

ImageUpdateAutomation

Git 저장소의 매니페스트를 자동 업데이트합니다:

apiVersion: image.toolkit.fluxcd.io/v1beta2
kind: ImageUpdateAutomation
metadata:
  name: my-app
  namespace: flux-system
spec:
  interval: 5m
  
  # 업데이트할 Git 저장소
  sourceRef:
    kind: GitRepository
    name: my-app
  
  # Git 설정
  git:
    checkout:
      ref:
        branch: main
    commit:
      author:
        name: Flux
        email: flux@myorg.com
      messageTemplate: |
        Update images
        
        {{range .Changed.Changes -}}
        - {{.OldValue}} -> {{.NewValue}}
        {{end}}
    push:
      branch: main
  
  # 업데이트 대상 파일
  update:
    path: ./deploy
    strategy: Setters  # 마커 기반 업데이트

마커 기반 업데이트:

# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app
spec:
  template:
    spec:
      containers:
      - name: app
        image: ghcr.io/myorg/my-app:v1.0.0  # {"$imagepolicy": "flux-system:my-app"}

[!IMPORTANT] ArgoCD는 Image Updater가 별도 프로젝트인 반면, Flux는 Image Automation이 핵심 기능으로 내장되어 있습니다.


Notification Controller

배포 이벤트를 외부 시스템으로 알립니다.

Alert

어떤 이벤트를 알릴지 정의:

apiVersion: notification.toolkit.fluxcd.io/v1beta3
kind: Alert
metadata:
  name: on-call-alerts
  namespace: flux-system
spec:
  # 심각도 필터
  eventSeverity: error
  
  # 모니터링 대상
  eventSources:
    - kind: Kustomization
      name: '*'
    - kind: HelmRelease
      name: '*'
  
  # 알림 대상
  providerRef:
    name: slack

Provider

알림을 보낼 채널:

apiVersion: notification.toolkit.fluxcd.io/v1beta3
kind: Provider
metadata:
  name: slack
  namespace: flux-system
spec:
  type: slack
  channel: devops-alerts
  secretRef:
    name: slack-webhook

---
apiVersion: v1
kind: Secret
metadata:
  name: slack-webhook
  namespace: flux-system
stringData:
  address: https://hooks.slack.com/services/T00/B00/XXX

지원 Provider: Slack, Discord, Microsoft Teams, GitHub, GitLab, PagerDuty, Datadog, Sentry 등

Receiver

외부에서 Flux로 Webhook 수신:

apiVersion: notification.toolkit.fluxcd.io/v1
kind: Receiver
metadata:
  name: github-webhook
  namespace: flux-system
spec:
  type: github
  events:
    - push
  secretRef:
    name: github-webhook-secret
  resources:
    - kind: GitRepository
      name: my-app

Flux Bootstrap

Flux 설치의 권장 방법은 Bootstrap입니다. Flux 자체를 GitOps로 관리합니다:

# GitHub 저장소로 Bootstrap
flux bootstrap github \
  --owner=myorg \
  --repository=fleet-infra \
  --branch=main \
  --path=clusters/production \
  --personal

# 생성되는 구조
fleet-infra/
└── clusters/
    └── production/
        └── flux-system/
            ├── gotk-components.yaml  # Flux 컴포넌트
            ├── gotk-sync.yaml        # 자기 자신을 관리하는 Kustomization
            └── kustomization.yaml

Multi-tenancy 패턴

Flux는 네임스페이스 기반 격리를 지원합니다:

# 팀 A 전용 소스와 Kustomization
apiVersion: source.toolkit.fluxcd.io/v1
kind: GitRepository
metadata:
  name: team-a-apps
  namespace: team-a  # 팀 네임스페이스
spec:
  url: https://github.com/myorg/team-a-apps.git
  # ...

---
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
  name: team-a-apps
  namespace: team-a
spec:
  # 해당 팀 네임스페이스로 제한
  targetNamespace: team-a
  serviceAccountName: team-a-reconciler  # 제한된 권한의 SA
  # ...

ArgoCD vs Flux 상세 비교

기능ArgoCDFlux
설치 복잡도helm install 한 줄flux bootstrap
리소스 사용~400MB 메모리~100MB 메모리
Web UI강력한 내장 UIWeave GitOps (별도)
멀티 클러스터중앙 ArgoCD가 관리각 클러스터에 Flux
이미지 자동화Image Updater (별도)내장
Helm 지원Application에서 처리HelmRelease CRD
OCI 지원지원네이티브 지원
Health Check내장 (강력)wait/healthChecks
WebhookGitHub, GitLab 등Receiver로 다양한 소스
SOPS 지원제한적네이티브

언제 ArgoCD를 선택할까?

  • UI가 중요할 때 (운영팀에서 시각적 모니터링 선호)
  • 중앙 집중 관리가 필요할 때 (한 곳에서 모든 클러스터 관리)
  • 복잡한 Sync 전략이 필요할 때 (Sync Waves, Hooks)
  • 학습 곡선을 줄이고 싶을 때

언제 Flux를 선택할까?

  • 경량화가 중요할 때 (Edge, 리소스 제한 환경)
  • 이미지 자동 업데이트가 핵심 요구사항일 때
  • SOPS로 Secrets 관리할 때
  • 각 클러스터의 독립성이 중요할 때
  • Kubernetes Native 접근을 선호할 때

정리

컴포넌트역할
Source ControllerGit, Helm, OCI에서 아티팩트 가져오기
Kustomize ControllerKustomize 매니페스트 적용, 의존성 관리
Helm ControllerHelm 릴리스 생명주기 관리
Image Automation컨테이너 이미지 자동 업데이트
Notification Controller이벤트 알림 송수신

다음 편 예고

4편: 환경별 설정 관리에서는 다음을 다룹니다:

  • Kustomize Base/Overlays 패턴 심화
  • Helm values 관리 전략
  • Kustomize vs Helm 선택 기준
  • 하이브리드 접근: Helm + Kustomize post-rendering

참고 자료

Share

Related Articles

Comments

이 블로그는 제가 알고 있는 것들을 잊지 않기 위해 기록하는 공간입니다.
직접 작성한 글도 있고, AI의 도움을 받아 정리한 글도 있습니다.
정확하지 않은 내용이 있을 수 있으니 참고용으로 봐주세요.

© 2026 Seogyu Kim