반응형
Flux: GitOps의 선구자
들어가며
Flux는 Kubernetes를 위한 GitOps 도구의 선구자입니다. 2016년 Weaveworks가 개발하여 GitOps라는 개념을 처음 정의했으며, 2019년 CNCF 샌드박스 프로젝트로, 2021년 인큐베이팅 프로젝트로 승격되었습니다. Flux는 Git 저장소를 단일 진실 공급원(Single Source of Truth)으로 사용하여 Kubernetes 클러스터를 자동으로 동기화합니다. "Git에 푸시하면 자동 배포"라는 GitOps의 핵심을 구현한 Flux의 모든 것을 깊이 있게 탐구해봅시다.
1. Flux의 본질
1.1 Flux란?
Flux = GitOps for Kubernetes
GitOps 원칙:
1. 선언적 (Declarative)
- 원하는 상태를 선언
- Kubernetes YAML
2. 버전 관리 (Versioned)
- Git이 진실의 원천
- 모든 변경 이력 추적
3. 자동 적용 (Automated)
- Git → Cluster 자동 동기화
- 수동 작업 최소화
4. 지속적 조정 (Reconciled)
- 실제 상태 vs 원하는 상태
- Drift 자동 수정
전통적 배포:
Developer → CI → kubectl apply → Cluster
↑
(Push 모델)
GitOps (Flux):
Developer → Git → Flux → Cluster
↑
(Pull 모델)
핵심 개념:
Source (소스):
- GitRepository: Git 저장소
- HelmRepository: Helm 차트
- Bucket: S3, GCS 등
Kustomization:
- Kubernetes 매니페스트 적용
- Kustomize 지원
- 배포 전략
HelmRelease:
- Helm 차트 배포
- 값 오버라이드
- 업그레이드 전략
ImageRepository:
- 컨테이너 이미지 스캔
- 새 태그 감지
ImagePolicy:
- 이미지 업데이트 정책
- Semantic versioning
- Regex 필터
ImageUpdateAutomation:
- Git에 자동 커밋
- 이미지 태그 업데이트
1.2 왜 Flux인가?
장점:
✓ GitOps 네이티브
- Git이 진실의 원천
- 선언적 구성
- 버전 관리
✓ Kubernetes 네이티브
- CRD 기반
- kubectl로 관리
- RBAC 통합
✓ 멀티 테넌시
- Namespace 격리
- RBAC 기반 권한
- 팀별 GitOps
✓ 프로그레시브 배포
- Canary
- Blue-Green
- A/B Testing
- Flagger 통합
✓ CNCF 프로젝트
- 커뮤니티 지원
- 벤더 중립
- 장기 지원
단점:
✗ Kubernetes 전용
- VM, 서버리스 불가
- K8s 필수
✗ 학습 곡선
- GitOps 개념
- CRD 이해
- Kustomize/Helm
✗ Git 중심
- Git 저장소 필수
- Git 워크플로우 의존
vs ArgoCD:
- UI: ArgoCD 강력 > Flux 기본
- 멀티 클러스터: ArgoCD 중앙집중 vs Flux 분산
- 복잡도: ArgoCD 높음 > Flux 낮음
- CNCF: 둘 다 인큐베이팅
vs Jenkins/GitLab CI:
- 배포 모델: Flux Pull vs CI/CD Push
- K8s 통합: Flux 네이티브 > CI/CD 플러그인
- Drift 감지: Flux 자동 vs CI/CD 수동
- 범위: Flux K8s 전용 vs CI/CD 범용
선택 기준:
Kubernetes 중심 → Flux
GitOps 도입 → Flux
프로그레시브 배포 → Flux + Flagger
중앙 관리 UI 필요 → ArgoCD
VM 배포 포함 → CI/CD
1.3 Flux 아키텍처
Flux 컴포넌트:
┌─────────────────────────────────────┐
│ Git Repository │
│ ┌───────────────────────────────┐ │
│ │ manifests/ │ │
│ │ ├─ deployment.yaml │ │
│ │ ├─ service.yaml │ │
│ │ └─ ingress.yaml │ │
│ └───────────────────────────────┘ │
└─────────────────────────────────────┘
↓ (Pull)
┌─────────────────────────────────────┐
│ Kubernetes Cluster │
│ │
│ ┌────────────────────────────┐ │
│ │ source-controller │ │
│ │ - Git 저장소 모니터링 │ │
│ │ - 변경 감지 │ │
│ └────────────────────────────┘ │
│ ↓ │
│ ┌────────────────────────────┐ │
│ │ kustomize-controller │ │
│ │ - Kustomization 적용 │ │
│ │ - Reconcile │ │
│ └────────────────────────────┘ │
│ ↓ │
│ ┌────────────────────────────┐ │
│ │ helm-controller │ │
│ │ - HelmRelease 적용 │ │
│ │ - 차트 배포 │ │
│ └────────────────────────────┘ │
│ ↓ │
│ ┌────────────────────────────┐ │
│ │ notification-controller │ │
│ │ - Slack, Discord 알림 │ │
│ │ - Webhook │ │
│ └────────────────────────────┘ │
│ ↓ │
│ ┌────────────────────────────┐ │
│ │ image-reflector-controller│ │
│ │ - 이미지 스캔 │ │
│ │ - 새 태그 감지 │ │
│ └────────────────────────────┘ │
│ ↓ │
│ ┌────────────────────────────┐ │
│ │ image-automation-controller│ │
│ │ - Git 자동 커밋 │ │
│ │ - 이미지 업데이트 │ │
│ └────────────────────────────┘ │
└─────────────────────────────────────┘
Reconciliation Loop:
1. Source-controller: Git 저장소 폴링
2. 변경 감지 → 아티팩트 다운로드
3. Kustomize/Helm-controller: 적용
4. 클러스터 상태 조정
5. 성공/실패 알림
6. 5분마다 반복 (기본값)
2. Flux 설치
2.1 Flux CLI 설치
bash
# macOS
brew install fluxcd/tap/flux
# Linux
curl -s https://fluxcd.io/install.sh | sudo bash
# Windows (PowerShell)
choco install flux
# 버전 확인
flux --version
# Kubernetes 클러스터 체크
flux check --pre
# 출력:
# ► checking prerequisites
# ✔ Kubernetes 1.28.0 >=1.25.0-0
# ✔ prerequisites checks passed
2.2 GitHub Personal Access Token 생성
bash
# GitHub → Settings → Developer settings → Personal access tokens
# 필요한 권한:
# - repo (전체)
# - workflow (GitHub Actions 사용 시)
# 환경 변수 설정
export GITHUB_TOKEN=<your-token>
export GITHUB_USER=<your-username>
export GITHUB_REPO=<your-repo-name>
2.3 Flux 부트스트랩
bash
# GitHub 저장소에 부트스트랩
flux bootstrap github \
--owner=$GITHUB_USER \
--repository=$GITHUB_REPO \
--branch=main \
--path=./clusters/production \
--personal
# 실행 내용:
# 1. GitHub 저장소 생성 (없으면)
# 2. Flux 컴포넌트 설치
# 3. SSH 키 생성 및 Deploy Key 등록
# 4. GitRepository 및 Kustomization 생성
# 5. Git에 Flux 매니페스트 커밋
# 상태 확인
flux get sources git
# 출력:
# NAME REVISION SUSPENDED READY
# flux-system main@sha1:abc False True
flux get kustomizations
# 출력:
# NAME REVISION SUSPENDED READY
# flux-system main@sha1:abc False True
# Flux 컴포넌트 확인
kubectl get pods -n flux-system
# 출력:
# NAME READY STATUS
# source-controller-xxx 1/1 Running
# kustomize-controller-xxx 1/1 Running
# helm-controller-xxx 1/1 Running
# notification-controller-xxx 1/1 Running
# image-reflector-controller-xxx 1/1 Running
# image-automation-controller-xxx 1/1 Running
2.4 다른 Git 제공자 (GitLab, Bitbucket)
bash
# GitLab
flux bootstrap gitlab \
--owner=$GITLAB_USER \
--repository=$GITLAB_REPO \
--branch=main \
--path=./clusters/production \
--token-auth \
--personal
# Generic Git
flux bootstrap git \
--url=ssh://git@gitlab.com/$GITLAB_USER/$GITLAB_REPO \
--branch=main \
--path=./clusters/production \
--private-key-file=./identity
# Azure DevOps
flux bootstrap git \
--url=https://dev.azure.com/org/project/_git/repo \
--branch=main \
--path=./clusters/production \
--username=git \
--password=$AZURE_DEVOPS_TOKEN
3. 기본 사용법
3.1 GitRepository 생성
yaml
# clusters/production/sources/app-repo.yaml
apiVersion: source.toolkit.fluxcd.io/v1
kind: GitRepository
metadata:
name: app-repo
namespace: flux-system
spec:
interval: 1m # 1분마다 확인
url: https://github.com/user/app-repo
ref:
branch: main
secretRef:
name: github-token # Private 저장소
ignore: |
# .gitignore 형식
*.md
docs/
---
# Secret (Private 저장소)
apiVersion: v1
kind: Secret
metadata:
name: github-token
namespace: flux-system
type: Opaque
stringData:
username: git
password: ghp_xxx # GitHub Token
3.2 Kustomization 생성
yaml
# clusters/production/apps/app-kustomization.yaml
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
name: app
namespace: flux-system
spec:
interval: 5m
path: ./manifests
prune: true # 삭제된 리소스 정리
sourceRef:
kind: GitRepository
name: app-repo
healthChecks:
- apiVersion: apps/v1
kind: Deployment
name: app
namespace: default
timeout: 2m
retryInterval: 1m
3.3 애플리케이션 매니페스트
yaml
# manifests/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: app
namespace: default
spec:
replicas: 3
selector:
matchLabels:
app: myapp
template:
metadata:
labels:
app: myapp
spec:
containers:
- name: app
image: registry.example.com/myapp:1.0.0
ports:
- containerPort: 8080
---
# manifests/service.yaml
apiVersion: v1
kind: Service
metadata:
name: app
namespace: default
spec:
selector:
app: myapp
ports:
- port: 80
targetPort: 8080
type: LoadBalancer
3.4 배포 확인
bash
# Git에 푸시
git add .
git commit -m "Deploy app v1.0.0"
git push
# Flux 동기화 대기 (또는 강제)
flux reconcile source git app-repo
flux reconcile kustomization app
# 상태 확인
flux get sources git
flux get kustomizations
# 로그 확인
flux logs --level=info --follow
# 이벤트 확인
kubectl get events -n flux-system --sort-by='.lastTimestamp'
# 애플리케이션 확인
kubectl get pods -n default
kubectl get svc -n default
4. Helm 통합
4.1 HelmRepository
yaml
# clusters/production/sources/helm-repo.yaml
apiVersion: source.toolkit.fluxcd.io/v1beta2
kind: HelmRepository
metadata:
name: bitnami
namespace: flux-system
spec:
interval: 30m
url: https://charts.bitnami.com/bitnami
---
# Private Helm Repository
apiVersion: source.toolkit.fluxcd.io/v1beta2
kind: HelmRepository
metadata:
name: private-charts
namespace: flux-system
spec:
interval: 10m
url: https://charts.example.com
secretRef:
name: helm-auth
type: oci # OCI Registry
---
apiVersion: v1
kind: Secret
metadata:
name: helm-auth
namespace: flux-system
type: Opaque
stringData:
username: myuser
password: mypassword
4.2 HelmRelease
yaml
# clusters/production/apps/nginx-helm.yaml
apiVersion: helm.toolkit.fluxcd.io/v2beta1
kind: HelmRelease
metadata:
name: nginx
namespace: default
spec:
interval: 30m
chart:
spec:
chart: nginx
version: '>=13.0.0 <14.0.0' # Semantic versioning
sourceRef:
kind: HelmRepository
name: bitnami
namespace: flux-system
interval: 12h
values:
replicaCount: 3
service:
type: LoadBalancer
port: 80
resources:
limits:
cpu: 200m
memory: 256Mi
requests:
cpu: 100m
memory: 128Mi
ingress:
enabled: true
hostname: app.example.com
tls: true
# 값 오버라이드 (ConfigMap/Secret)
valuesFrom:
- kind: ConfigMap
name: nginx-values
valuesKey: values.yaml
- kind: Secret
name: nginx-secrets
valuesKey: secrets.yaml
# 업그레이드 전략
install:
remediation:
retries: 3
upgrade:
remediation:
retries: 3
remediateLastFailure: true
cleanupOnFail: true
# 롤백
rollback:
recreate: true
force: true
# 테스트
test:
enable: true
# 대기 시간
timeout: 5m
4.3 Helm 차트 의존성
yaml
# Chart.yaml
apiVersion: v2
name: myapp
version: 1.0.0
dependencies:
- name: postgresql
version: 12.x.x
repository: https://charts.bitnami.com/bitnami
- name: redis
version: 17.x.x
repository: https://charts.bitnami.com/bitnami
---
# HelmRelease
apiVersion: helm.toolkit.fluxcd.io/v2beta1
kind: HelmRelease
metadata:
name: myapp
namespace: default
spec:
interval: 30m
chart:
spec:
chart: ./charts/myapp
sourceRef:
kind: GitRepository
name: app-repo
namespace: flux-system
dependsOn:
- name: postgresql
namespace: default
- name: redis
namespace: default
values:
postgresql:
enabled: true
auth:
username: myuser
password: mypassword
database: mydb
redis:
enabled: true
auth:
enabled: false
5. 이미지 자동 업데이트
5.1 ImageRepository
yaml
# clusters/production/images/image-repo.yaml
apiVersion: image.toolkit.fluxcd.io/v1beta2
kind: ImageRepository
metadata:
name: myapp
namespace: flux-system
spec:
image: registry.example.com/myapp
interval: 1m
secretRef:
name: docker-registry-credentials
---
apiVersion: v1
kind: Secret
metadata:
name: docker-registry-credentials
namespace: flux-system
type: kubernetes.io/dockerconfigjson
data:
.dockerconfigjson: <base64-encoded-docker-config>
5.2 ImagePolicy
yaml
# clusters/production/images/image-policy.yaml
apiVersion: image.toolkit.fluxcd.io/v1beta2
kind: ImagePolicy
metadata:
name: myapp
namespace: flux-system
spec:
imageRepositoryRef:
name: myapp
# Semantic versioning
policy:
semver:
range: 1.x.x
# 또는 Numerical (최신 태그)
# policy:
# numerical:
# order: asc
# 또는 Alphabetical
# policy:
# alphabetical:
# order: asc
# 필터 (정규식)
filterTags:
pattern: '^main-[a-f0-9]+-(?P<ts>[0-9]+)'
extract: '$ts'
5.3 ImageUpdateAutomation
yaml
# clusters/production/images/image-update.yaml
apiVersion: image.toolkit.fluxcd.io/v1beta1
kind: ImageUpdateAutomation
metadata:
name: myapp-update
namespace: flux-system
spec:
interval: 1m
sourceRef:
kind: GitRepository
name: app-repo
git:
checkout:
ref:
branch: main
commit:
author:
name: fluxbot
email: flux@example.com
messageTemplate: |
Update image to {{range .Updated.Images}}{{println .}}{{end}}
push:
branch: main
update:
path: ./manifests
strategy: Setters
---
# manifests/deployment.yaml (마커 추가)
apiVersion: apps/v1
kind: Deployment
metadata:
name: app
namespace: default
spec:
template:
spec:
containers:
- name: app
image: registry.example.com/myapp:1.0.0 # {"$imagepolicy": "flux-system:myapp"}
# Flux가 자동으로 업데이트:
# image: registry.example.com/myapp:1.2.3
5.4 이미지 업데이트 확인
bash
# ImageRepository 확인
flux get image repository myapp
# ImagePolicy 확인
flux get image policy myapp
# 최신 이미지 확인
kubectl get imagepolicy myapp -n flux-system -o yaml
# spec.latestImage 확인
# latestImage: registry.example.com/myapp:1.2.3
# Git 커밋 확인
git log --oneline
# abc1234 Update image to registry.example.com/myapp:1.2.3
6. 멀티 클러스터 & 멀티 테넌시
6.1 멀티 클러스터 구조
Git Repository:
├── clusters/
│ ├── production/
│ │ ├── flux-system/
│ │ │ ├── gotk-components.yaml
│ │ │ └── gotk-sync.yaml
│ │ └── apps/
│ │ └── app-kustomization.yaml
│ ├── staging/
│ │ ├── flux-system/
│ │ └── apps/
│ └── development/
│ ├── flux-system/
│ └── apps/
└── apps/
├── base/
│ ├── deployment.yaml
│ ├── service.yaml
│ └── kustomization.yaml
└── overlays/
├── production/
│ └── kustomization.yaml
├── staging/
│ └── kustomization.yaml
└── development/
└── kustomization.yaml
6.2 Base 구성
yaml
# apps/base/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: app
spec:
replicas: 1 # 오버레이에서 변경
selector:
matchLabels:
app: myapp
template:
metadata:
labels:
app: myapp
spec:
containers:
- name: app
image: registry.example.com/myapp:latest
resources:
limits:
cpu: 100m
memory: 128Mi
---
# apps/base/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- deployment.yaml
- service.yaml
6.3 Overlay 구성
yaml
# apps/overlays/production/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ../../base
namespace: production
replicas:
- name: app
count: 5
images:
- name: registry.example.com/myapp
newTag: v1.2.3
configMapGenerator:
- name: app-config
literals:
- ENV=production
- LOG_LEVEL=info
---
# apps/overlays/staging/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ../../base
namespace: staging
replicas:
- name: app
count: 2
images:
- name: registry.example.com/myapp
newTag: v1.2.3-rc.1
configMapGenerator:
- name: app-config
literals:
- ENV=staging
- LOG_LEVEL=debug
6.4 클러스터별 Kustomization
yaml
# clusters/production/apps/app-kustomization.yaml
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
name: app
namespace: flux-system
spec:
interval: 10m
path: ./apps/overlays/production
prune: true
sourceRef:
kind: GitRepository
name: app-repo
---
# clusters/staging/apps/app-kustomization.yaml
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
name: app
namespace: flux-system
spec:
interval: 5m
path: ./apps/overlays/staging
prune: true
sourceRef:
kind: GitRepository
name: app-repo
6.5 멀티 테넌시 (팀별 격리)
yaml
# tenants/team-a/namespace.yaml
apiVersion: v1
kind: Namespace
metadata:
name: team-a
---
# tenants/team-a/git-repo.yaml
apiVersion: source.toolkit.fluxcd.io/v1
kind: GitRepository
metadata:
name: team-a-repo
namespace: team-a
spec:
interval: 1m
url: https://github.com/org/team-a-repo
ref:
branch: main
secretRef:
name: team-a-github-token
---
# tenants/team-a/kustomization.yaml
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
name: team-a-apps
namespace: team-a
spec:
interval: 5m
path: ./apps
prune: true
sourceRef:
kind: GitRepository
name: team-a-repo
serviceAccountName: team-a-reconciler
---
# tenants/team-a/rbac.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
name: team-a-reconciler
namespace: team-a
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: team-a-reconciler
namespace: team-a
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: cluster-admin # 또는 제한된 Role
subjects:
- kind: ServiceAccount
name: team-a-reconciler
namespace: team-a
7. 프로그레시브 배포 (Flagger)
7.1 Flagger 설치
bash
# HelmRepository 추가
flux create source helm flagger \
--url=https://flagger.app \
--namespace=flux-system
# Flagger 설치
flux create helmrelease flagger \
--source=HelmRepository/flagger \
--chart=flagger \
--namespace=flux-system \
--values=- <<EOF
metricsServer: http://prometheus:9090
meshProvider: istio
EOF
# 또는 YAML
cat <<EOF | kubectl apply -f -
apiVersion: source.toolkit.fluxcd.io/v1beta2
kind: HelmRepository
metadata:
name: flagger
namespace: flux-system
spec:
interval: 30m
url: https://flagger.app
---
apiVersion: helm.toolkit.fluxcd.io/v2beta1
kind: HelmRelease
metadata:
name: flagger
namespace: flux-system
spec:
interval: 30m
chart:
spec:
chart: flagger
sourceRef:
kind: HelmRepository
name: flagger
values:
metricsServer: http://prometheus:9090
meshProvider: istio
EOF
7.2 Canary 배포
yaml
# apps/canary.yaml
apiVersion: flagger.app/v1beta1
kind: Canary
metadata:
name: myapp
namespace: default
spec:
# 대상 Deployment
targetRef:
apiVersion: apps/v1
kind: Deployment
name: myapp
# 서비스
service:
port: 80
targetPort: 8080
# 분석 (메트릭 기반)
analysis:
# 체크 간격
interval: 1m
# 최대 웨이트 (점진적 증가)
maxWeight: 50
# 증가 단계
stepWeight: 5
# 성공 임계값
threshold: 5
# 메트릭
metrics:
- name: request-success-rate
thresholdRange:
min: 99
interval: 1m
- name: request-duration
thresholdRange:
max: 500
interval: 1m
# 웹훅 (추가 검증)
webhooks:
- name: load-test
url: http://flagger-loadtester/
timeout: 5s
metadata:
cmd: "hey -z 1m -q 10 -c 2 http://myapp-canary/"
# 롤백 시 재시도 안 함
skipAnalysis: false
# 배포 프로세스:
# 1. myapp-primary (100% 트래픽)
# 2. 새 버전 배포 → myapp-canary 생성
# 3. Canary: 5% 트래픽
# 4. 메트릭 체크 (1분)
# 5. 성공 → 10% 트래픽
# 6. 반복 → 50% 도달
# 7. 검증 완료 → primary 업데이트
# 8. Canary 제거
7.3 Blue-Green 배포
yaml
apiVersion: flagger.app/v1beta1
kind: Canary
metadata:
name: myapp
namespace: default
spec:
targetRef:
apiVersion: apps/v1
kind: Deployment
name: myapp
service:
port: 80
analysis:
interval: 1m
threshold: 10
iterations: 10
# Blue-Green: 한 번에 전환
maxWeight: 0
stepWeight: 100
metrics:
- name: request-success-rate
thresholdRange:
min: 99
interval: 1m
# 배포 프로세스:
# 1. myapp-primary (Blue, 100% 트래픽)
# 2. 새 버전 배포 → myapp-canary (Green)
# 3. Green 검증 (메트릭)
# 4. 검증 성공 → 즉시 100% 전환
# 5. Blue 제거
7.4 A/B Testing
yaml
apiVersion: flagger.app/v1beta1
kind: Canary
metadata:
name: myapp
namespace: default
spec:
targetRef:
apiVersion: apps/v1
kind: Deployment
name: myapp
service:
port: 80
analysis:
interval: 1m
threshold: 10
maxWeight: 50
stepWeight: 10
# HTTP 헤더 기반 라우팅
match:
- headers:
user-agent:
regex: ".*Chrome.*"
- headers:
cookie:
regex: "^(.*?;)?(test=true)(;.*)?$"
metrics:
- name: request-success-rate
thresholdRange:
min: 99
interval: 1m
# Chrome 사용자 + test=true 쿠키 → Canary
# 나머지 → Primary
8. 알림과 모니터링
8.1 Slack 알림
yaml
# clusters/production/notifications/slack-provider.yaml
apiVersion: notification.toolkit.fluxcd.io/v1beta3
kind: Provider
metadata:
name: slack
namespace: flux-system
spec:
type: slack
channel: deployments
secretRef:
name: slack-webhook
---
apiVersion: v1
kind: Secret
metadata:
name: slack-webhook
namespace: flux-system
type: Opaque
stringData:
address: https://hooks.slack.com/services/xxx/yyy/zzz
---
# clusters/production/notifications/slack-alert.yaml
apiVersion: notification.toolkit.fluxcd.io/v1beta3
kind: Alert
metadata:
name: on-call
namespace: flux-system
spec:
providerRef:
name: slack
eventSeverity: info
eventSources:
- kind: GitRepository
name: '*'
- kind: Kustomization
name: '*'
- kind: HelmRelease
name: '*'
summary: "Cluster: production"
8.2 Discord 알림
yaml
apiVersion: notification.toolkit.fluxcd.io/v1beta3
kind: Provider
metadata:
name: discord
namespace: flux-system
spec:
type: discord
channel: "1234567890"
username: FluxBot
secretRef:
name: discord-webhook
---
apiVersion: v1
kind: Secret
metadata:
name: discord-webhook
namespace: flux-system
type: Opaque
stringData:
address: https://discord.com/api/webhooks/xxx/yyy
8.3 Webhook 알림
yaml
apiVersion: notification.toolkit.fluxcd.io/v1beta3
kind: Provider
metadata:
name: webhook
namespace: flux-system
spec:
type: generic
address: https://example.com/webhook
secretRef:
name: webhook-token
---
apiVersion: v1
kind: Secret
metadata:
name: webhook-token
namespace: flux-system
type: Opaque
stringData:
token: my-secret-token
---
apiVersion: notification.toolkit.fluxcd.io/v1beta3
kind: Alert
metadata:
name: webhook-alert
namespace: flux-system
spec:
providerRef:
name: webhook
eventSources:
- kind: Kustomization
name: '*'
8.4 Prometheus 메트릭
bash
# Flux 컨트롤러는 Prometheus 메트릭 노출
# :8080/metrics
# 주요 메트릭:
# - gotk_reconcile_condition: Reconcile 상태
# - gotk_reconcile_duration_seconds: Reconcile 시간
# - controller_runtime_reconcile_total: Reconcile 횟수
# Prometheus 스크랩 설정
kubectl apply -f - <<EOF
apiVersion: v1
kind: ServiceMonitor
metadata:
name: flux-system
namespace: flux-system
spec:
selector:
matchLabels:
app.kubernetes.io/part-of: flux
endpoints:
- port: http-prom
interval: 30s
EOF
# Grafana 대시보드
# https://grafana.com/grafana/dashboards/16714
# Flux Cluster Stats
# Flux Control Plane
9. 보안
9.1 Sealed Secrets
bash
# Sealed Secrets 설치
flux create source helm sealed-secrets \
--url=https://bitnami-labs.github.io/sealed-secrets \
--namespace=flux-system
flux create helmrelease sealed-secrets \
--source=HelmRepository/sealed-secrets \
--chart=sealed-secrets \
--namespace=kube-system
# kubeseal CLI 설치
brew install kubeseal
# Secret 생성
kubectl create secret generic mysecret \
--from-literal=password=mypassword \
--dry-run=client \
-o yaml > mysecret.yaml
# Seal (암호화)
kubeseal --format yaml < mysecret.yaml > mysealedsecret.yaml
# Git에 커밋 (안전)
git add mysealedsecret.yaml
git commit -m "Add sealed secret"
git push
# Flux가 자동으로 복호화하여 적용
9.2 SOPS (Mozilla)
bash
# SOPS 설치
brew install sops
# Age 키 생성
age-keygen -o age.txt
# Public 키 확인
cat age.txt | grep public
# .sops.yaml 생성
cat <<EOF > .sops.yaml
creation_rules:
- path_regex: .*.yaml
encrypted_regex: ^(data|stringData)$
age: age1xxx...
EOF
# Secret 암호화
sops --encrypt --in-place secret.yaml
# Git에 커밋
git add secret.yaml .sops.yaml
git commit -m "Add encrypted secret"
git push
# Flux에서 SOPS 활성화
flux create kustomization apps \
--source=GitRepository/app-repo \
--path=./apps \
--prune=true \
--interval=5m \
--decryption-provider=sops \
--decryption-secret=sops-age
# Age 키를 Secret으로
cat age.txt | kubectl create secret generic sops-age \
--namespace=flux-system \
--from-file=age.agekey=/dev/stdin
9.3 Policy (OPA Gatekeeper)
yaml
# Gatekeeper 설치
flux create source helm gatekeeper \
--url=https://open-policy-agent.github.io/gatekeeper/charts \
--namespace=flux-system
flux create helmrelease gatekeeper \
--source=HelmRepository/gatekeeper \
--chart=gatekeeper \
--namespace=gatekeeper-system
---
# Policy: 모든 컨테이너에 리소스 제한 필수
apiVersion: templates.gatekeeper.sh/v1
kind: ConstraintTemplate
metadata:
name: k8srequiredresources
spec:
crd:
spec:
names:
kind: K8sRequiredResources
targets:
- target: admission.k8s.gatekeeper.sh
rego: |
package k8srequiredresources
violation[{"msg": msg}] {
container := input.review.object.spec.containers[_]
not container.resources.limits.cpu
msg := sprintf("Container %v has no CPU limit", [container.name])
}
---
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sRequiredResources
metadata:
name: must-have-resources
spec:
match:
kinds:
- apiGroups: ["apps"]
kinds: ["Deployment"]
10. 트러블슈팅
10.1 일반적인 문제
bash
# 문제 1: Reconcile 실패
flux get all --all-namespaces
# 로그 확인
flux logs --kind=Kustomization --name=apps
# 강제 Reconcile
flux reconcile kustomization apps --with-source
# 문제 2: Git 인증 실패
# Secret 확인
kubectl get secret -n flux-system
# SSH 키 재생성
flux create secret git app-repo \
--url=ssh://git@github.com/user/repo \
--ssh-key-algorithm=rsa \
--ssh-rsa-bits=4096
# 문제 3: Image pull 실패
# Docker registry credentials 생성
kubectl create secret docker-registry regcred \
--docker-server=registry.example.com \
--docker-username=myuser \
--docker-password=mypassword \
--namespace=flux-system
# ImageRepository에 추가
# spec.secretRef.name: regcred
# 문제 4: Helm release 실패
flux get helmreleases --all-namespaces
# 상세 로그
kubectl describe helmrelease myapp -n default
# 재시도
flux reconcile helmrelease myapp
# 문제 5: 느린 Reconcile
# Interval 확인
flux get sources git
# Interval 단축
flux create source git app-repo \
--url=https://github.com/user/repo \
--branch=main \
--interval=30s
10.2 디버깅
bash
# Flux 시스템 체크
flux check
# 모든 리소스 상태
flux get all --all-namespaces
# 이벤트 확인
kubectl get events -n flux-system --sort-by='.lastTimestamp'
# Reconcile 추적
flux logs --follow --all-namespaces
# Suspend/Resume
flux suspend kustomization apps
flux resume kustomization apps
# 수동 Reconcile
flux reconcile source git app-repo
flux reconcile kustomization apps
# Reconcile 조건 확인
kubectl get kustomization apps -n flux-system -o yaml
# status.conditions 확인:
# - type: Ready
# status: "True"
# reason: ReconciliationSucceeded
10.3 성능 최적화
yaml
# Reconcile interval 조정
spec:
interval: 5m # 기본값: 1m
# Prune 비활성화 (대규모 클러스터)
spec:
prune: false
# Health check 타임아웃
spec:
timeout: 5m
healthChecks:
- apiVersion: apps/v1
kind: Deployment
name: app
namespace: default
# 재시도 간격
spec:
retryInterval: 2m
# Force 옵션
spec:
force: true # 리소스 재생성
11. 실무 체크리스트
Flux 사용 시:
초기 설정
- Flux CLI 설치
- GitHub Token 생성
- Flux 부트스트랩
- GitRepository 생성
애플리케이션 배포
- 매니페스트 Git에 커밋
- Kustomization 생성
- Reconcile 확인
- 알림 설정
Helm 통합
- HelmRepository 추가
- HelmRelease 생성
- Values 관리
- 업그레이드 전략
이미지 자동화
- ImageRepository 생성
- ImagePolicy 정의
- ImageUpdateAutomation 설정
- 마커 추가
멀티 클러스터
- Base/Overlay 구조
- 클러스터별 Kustomization
- 환경별 구성
- RBAC 설정
보안
- Sealed Secrets 또는 SOPS
- Private 저장소 인증
- RBAC 최소 권한
- Policy 적용
모니터링
- Slack/Discord 알림
- Prometheus 메트릭
- Grafana 대시보드
- 로그 수집
12. 결론
Flux는 GitOps의 표준입니다.
핵심 교훈:
- GitOps 네이티브 - Git이 진실의 원천
- Kubernetes 네이티브 - CRD 기반
- Pull 모델 - 클러스터가 Git에서 Pull
- 자동 조정 - Drift 자동 수정
- 멀티 테넌시 - 팀별 격리
- 프로그레시브 배포 - Canary, Blue-Green
- 이미지 자동화 - CI → Flux 자동 배포
- CNCF 프로젝트 - 커뮤니티 지원
Flux는 Kubernetes에 최적화된 GitOps 도구입니다. "Git에 푸시하면 자동 배포"라는 GitOps의 약속을 완벽하게 구현합니다. ArgoCD보다 단순하고, CI/CD보다 Kubernetes 네이티브합니다. GitOps로 클러스터를 선언적으로 관리하세요!
"Git Push = Auto Deploy. Flux!"
반응형
댓글