다중 쿠버네티스 클러스터 GitOps 점진적 배포 구현

이 예제에서는 스테이징(staging)과 프로덕션(production) 두 개의 클러스터 환경을 가정합니다. Flux와 Kustomize를 활용해 중복 선언을 최소화하면서 클러스터를 관리하는 것이 핵심 목표입니다.

Flux는 HelmRepository와 HelmRelease CRD(Custom Resource Definition)를 사용하여 데모 애플리케이션 설치, 테스트, 업그레이드를 수행합니다. Flux는 Helm 저장소를 모니터링하고 semver 범위에 따라 최신 차트 버전으로 자동 업그레이드합니다.

사전 준비

프로젝트 저장소:

쿠버네티스 클러스터(v1.16+)와 kubectl(v1.18+)이 필요합니다. 로컬 테스트에는 Kubernetes Kind를 사용할 수 있습니다.

GitHub 계정과 저장소 생성 권한이 있는 Personal Access Token이 필요합니다.

Flux CLI 설치 (macOS/Linux):

brew install fluxcd/tap/flux

또는:

curl -s https://fluxcd.io/install.sh | sudo bash

프로젝트 구조

저장소 디렉토리 구성:

├── 애플리케이션
│   ├── 베이스
│   ├── 프로덕션 
│   └── 스테이징
├── 인프라
│   ├── nginx
│   ├── redis
│   └── 소스
└── 클러스터
    ├── 프로덕션
    └── 스테이징

애플리케이션 구성:

./애플리케이션/
├── 베이스
│   └── 앱데모
│       ├── kustomization.yaml
│       ├── 네임스페이스.yaml
│       └── 릴리즈.yaml
├── 프로덕션
│   ├── kustomization.yaml
│   └── 앱데모-패치.yaml
└── 스테이징
    ├── kustomization.yaml
    └── 앱데모-패치.yaml

공통 HelmRelease (apps/base/app-demo/release.yaml):

apiVersion: helm.toolkit.fluxcd.io/v2beta1
kind: HelmRelease
metadata:
  name: app-demo
  namespace: app-demo
spec:
  chart:
    spec:
      chart: app-demo
      sourceRef:
        kind: HelmRepository
        name: app-demo
        namespace: flux-system
  interval: 5m
  values:
    cache: redis-master.redis:6379
    ingress:
      enabled: true
      annotations:
        kubernetes.io/ingress.class: nginx

스테이징 전용 패치 (apps/staging/app-demo-patch.yaml):

apiVersion: helm.toolkit.fluxcd.io/v2beta1
kind: HelmRelease
metadata:
  name: app-demo
spec:
  chart:
    spec:
      version: ">=1.0.0-alpha"
  test:
    enable: true
  values:
    ingress:
      hosts:
        - app-demo.staging

프로덕션 전용 패치 (apps/production/app-demo-patch.yaml):

apiVersion: helm.toolkit.fluxcd.io/v2beta1
kind: HelmRelease
metadata:
  name: app-demo
spec:
  chart:
    spec:
      version: ">=1.0.0"
  values:
    ingress:
      hosts:
        - app-demo.production

인프라 구성:

./인프라/
├── nginx
│   ├── kustomization.yaml
│   ├── 네임스페이스.yaml
│   └── 릴리즈.yaml
├── redis
│   ├── kustomization.yaml
│   ├── 네임스페이스.yaml
│   └── 릴리즈.yaml
└── 소스
    ├── bitnami.yaml
    ├── kustomization.yaml
    └── 앱데모.yaml

Helm 저장소 정의 (infrastructure/sources/app-demo.yaml):

apiVersion: source.toolkit.fluxcd.io/v1beta1
kind: HelmRepository
metadata:
  name: app-demo
spec:
  interval: 5m
  url: https://stefanprodan.github.io/podinfo

클러스터 부트스트랩

클러스터 디렉토리 구성:

./클러스터/
├── 프로덕션
│   ├── 앱.yaml
│   └── 인프라.yaml
└── 스테이징
    ├── 앱.yaml
    └── 인프라.yaml

스테이징 Kustomization (clusters/staging/apps.yaml):

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

환경 변수 설정:

export GITHUB_TOKEN=<토큰>
export GITHUB_USER=<사용자명>
export GITHUB_REPO=<저장소명>

사전 조건 확인:

flux check --pre

스테이징 클러스터 부트스트랩:

flux bootstrap github \
    --context=staging \
    --owner=${GITHUB_USER} \
    --repository=${GITHUB_REPO} \
    --branch=main \
    --path=clusters/staging

배포 상태 확인:

watch flux get helmreleases --all-namespaces

애플리케이션 접근 테스트:

kubectl -n nginx port-forward svc/nginx-ingress-controller 8080:80 &
curl -H "Host: app-demo.staging" http://localhost:8080

프로덕션 클러스터 부트스트랩:

flux bootstrap github \
    --context=production \
    --owner=${GITHUB_USER} \
    --repository=${GITHUB_REPO} \
    --branch=main \
    --path=clusters/production

시크릿 암호화

SOPS 설치:

brew install gnupg sops

GPG 키 생성:

gpg --full-generate-key
gpg --list-secret-keys fluxcdbot@users.noreply.github.com

시크릿 생성:

kubectl -n redis create secret generic redis-auth \
--from-literal=password=change-me \
--dry-run=client \
-o yaml > infrastructure/redis/redis-auth.yaml

sops --encrypt \
--pgp=<키ID> \
--encrypted-regex '^(data|stringData)$' \
--in-place infrastructure/redis/redis-auth.yaml

복호화 설정 (infrastructure.yaml):

spec:
  decryption:
    provider: sops
    secretRef:
      name: sops-gpg

클러스터 추가

신규 개발 클러스터 디렉토리 생성:

mkdir -p clusters/dev
cp clusters/staging/infrastructure.yaml clusters/dev
cp clusters/staging/apps.yaml clusters/dev

Flux 부트스트랩:

flux bootstrap github \
    --context=dev \
    --owner=${GITHUB_USER} \
    --repository=${GITHUB_REPO} \
    --branch=main \
    --path=clusters/dev

환경 복제

프로덕션 복제 클러스터 부트스트랩:

flux bootstrap github \
    --context=production-clone \
    --owner=${GITHUB_USER} \
    --repository=${GITHUB_REPO} \
    --branch=main \
    --path=clusters/production-clone

Kustomization 설정 (clusters/production-clone/kustomization.yaml):

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
  - flux-system
  - ../production/infrastructure.yaml
  - ../production/apps.yaml

배포 동기화:

flux reconcile kustomization flux-system \
    --context=production-clone \
    --with-source

태그: fluxcd kustomize helm gitops kubernetes

6월 5일 01:26에 게시됨