GitOps
매니페스트의 source of truth를 git에 두고 클러스터 안의 컨트롤러가 git을 watch 해 자동으로 동기화하는 운영 모델을 다룹니다. push 모델과 pull 모델의 차이, GitOps의 네 원칙, ArgoCD의 Application CRD · App of Apps · Sync Wave, Flux의 GitRepository · Kustomization · HelmRelease, 디렉터리 구조 패턴, 그리고 비밀을 git에 두는 세 가지 표준 도구까지 한 사이클로 정리하며 3부를 마무리합니다.
3부의 마지막 챕터입니다. 15장 CNI 깊이부터 19장 옵저버빌리티까지 클러스터의 데이터 플레인 · 권한 · 정책 · 확장 · 관측을 한 층씩 쌓아 왔습니다. 이번 챕터는 그 모든 매니페스트가 클러스터에 들어가는 방식 자체를 다룹니다 — GitOps입니다. kubectl apply를 사람이 손으로 돌리는 대신, 매니페스트의 source of truth를 git에 두고 클러스터 안의 컨트롤러가 git을 watch 해 자동으로 동기화하는 운영 모델입니다. ArgoCD와 Flux가 이 모델의 두 표준 구현체이고, 3부의 마지막 챕터로 두 도구의 모델 · 운영 패턴 · 3부 회고 · 4부 안내까지 한 사이클로 정리합니다.
이번 챕터의 끝에서는 운영 클러스터의 변경이 사람의 손이 아니라 git PR을 거쳐 자동으로 흘러가는 모양이 손에 들어옵니다. 4장 Deployment와 ReplicaSet §“replicas 조정"에서 짚었던 “선언형 매니페스트가 항상 진실의 출처"가 본격적인 운영 모델로 굳어지는 단계입니다.
Push 모델과 Pull 모델 #
먼저 GitOps가 등장하기 전의 표준이었던 모델과 비교해 봅니다. CI / CD 파이프라인이 클러스터에 매니페스트를 적용하는 방식은 크게 두 갈래입니다.
| 모델 | 흐름 |
|---|---|
| Push | CI 파이프라인이 클러스터의 API 서버에 직접 kubectl apply. CI 시스템이 클러스터 자격 증명을 보유 |
| Pull (GitOps) | 클러스터 안의 컨트롤러가 git을 watch. 매니페스트가 변경되면 컨트롤러가 자동으로 동기화 |
전통적인 CD 파이프라인은 push 모델이었습니다. GitHub Actions나 Jenkins가 빌드 후 kubectl apply -f manifests/를 돌리고 끝이었습니다. 이 모델의 문제는 셋입니다.
- CI 시스템이 클러스터의 강한 자격 증명을 들고 있다 — CI 시스템이 침해당하면 클러스터도 침해됩니다.
- Drift가 보이지 않는다 — 누가 클러스터에 직접
kubectl edit을 돌리면 git의 매니페스트와 실제 클러스터가 어긋나는데, 그 어긋남을 감지할 표준 메커니즘이 없습니다. - 여러 클러스터로 확장이 어렵다 — 클러스터 N 개에 같은 매니페스트를 적용하려면 N 번
kubectl apply를 돌려야 합니다.
GitOps 모델은 이 셋을 한 번에 푼 방식입니다. 클러스터 안의 컨트롤러가 git을 watch 하므로 외부에서 클러스터 자격 증명을 들고 있을 필요가 없고, 그 컨트롤러가 동기화 상태를 계속 보고 있으므로 drift를 자동으로 감지하며, 각 클러스터가 자기 git을 watch 하는 모델이라 N 개 확장이 자연스럽습니다.
GitOps의 네 원칙 #
OpenGitOps 프로젝트가 정리한 GitOps의 네 원칙은 다음과 같습니다.
| 원칙 | 의미 |
|---|---|
| Declarative | 시스템의 desired state가 선언적으로 표현된다 |
| Versioned and Immutable | desired state가 git 같은 변경 불가능한 저장소에 보관된다 |
| Pulled Automatically | 승인된 변경사항이 자동으로 시스템에 적용된다 |
| Continuously Reconciled | 컨트롤러가 desired state와 실제 state의 차이를 계속 좁힌다 |
K8s의 매니페스트는 declarative이고, git은 versioned + immutable입니다. ArgoCD와 Flux가 그 위에 pull + reconciliation을 더해 GitOps를 완성합니다. 1장 쿠버네티스란에서 본 reconcile loop 모델이 클러스터 안의 컨트롤러 단을 넘어 클러스터 · git 사이의 동기화에까지 확장된 모양입니다.
ArgoCD — Application CRD 중심의 모델 #
ArgoCD는 Intuit가 만들어 CNCF에 기증한 GitOps 도구입니다. 가장 큰 특징은 풍부한 웹 UI입니다. 클러스터의 모든 Application의 동기화 상태, drift, 매니페스트 변경 내역을 한 화면에서 볼 수 있어서 운영 팀의 진입 장벽이 낮습니다.
Application CRD — ArgoCD의 단위 #
ArgoCD가 git에서 매니페스트를 가져와 클러스터에 동기화하는 단위가 Application CRD입니다. 18장 CRD와 Operator 패턴의 모델이 GitOps 도구에도 그대로 적용된 예입니다.
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: my-app
namespace: argocd
spec:
project: default
source:
repoURL: https://github.com/myorg/manifests.git
targetRevision: main
path: apps/my-app/overlays/prod
destination:
server: https://kubernetes.default.svc
namespace: my-app
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true이 매니페스트가 ArgoCD에 적용되면 다음 일이 자동으로 일어납니다.
- ArgoCD 컨트롤러가
repoURL의path디렉터리를 git에서 가져옴 - Kustomize / Helm / 일반 YAML을 자동 인식해서 매니페스트를 렌더링
- 클러스터의
destination에 동기화 (automated.selfHeal: true이므로 drift를 자동 복구) - git의 매니페스트가 변경되면 자동으로 다시 동기화 (
automated) - git에서 사라진 객체는 클러스터에서도 삭제 (
prune: true)
App of Apps — Application의 묶음 관리 #
여러 Application을 한곳에서 관리하는 패턴이 App of Apps입니다. 한 Application의 source가 다른 Application 매니페스트들이 들어 있는 디렉터리를 가리키는 구조입니다.
manifests/
apps/
root.yaml ← 루트 Application (ArgoCD에 manual 적용)
children/
app-a.yaml ← Application: app-a
app-b.yaml ← Application: app-b
app-c.yaml ← Application: app-c
...루트 Application 한 개만 ArgoCD에 처음 등록하면, 그 안에서 자식 Application 들이 차례로 만들어지고, 각 자식 Application이 다시 자기 매니페스트를 동기화합니다. 클러스터에 새 앱을 추가하려면 git에 새 자식 Application 한 장만 추가하면 끝입니다.
Sync Wave — 순서 있는 적용 #
매니페스트 적용에 순서가 필요한 경우가 있습니다 — Namespace를 먼저 만들고, 그 안에 ConfigMap을 만들고, 그다음에 Deployment를 띄우는 순서. ArgoCD는 annotation으로 이 순서를 표현합니다.
metadata:
annotations:
argocd.argoproj.io/sync-wave: "0" # Namespace
---
metadata:
annotations:
argocd.argoproj.io/sync-wave: "1" # ConfigMap, Secret
---
metadata:
annotations:
argocd.argoproj.io/sync-wave: "2" # Deployment, StatefulSet낮은 wave가 먼저 적용되고, 그 wave의 객체가 모두 healthy 상태가 된 뒤 다음 wave가 진행됩니다. CRD를 먼저 만들고 그 CRD의 인스턴스를 적용하는 패턴이 가장 자주 만나는 사용처입니다.
Flux — 작은 컴포넌트의 묶음 #
Flux는 Weaveworks가 만든 GitOps 도구로 ArgoCD와 같은 카테고리의 도구이지만 접근이 다릅니다. Flux v2는 한 큰 컴포넌트가 아니라 여러 작은 컨트롤러의 묶음으로 설계되어 있습니다.
| Flux 컨트롤러 | 역할 |
|---|---|
| source-controller | git / Helm 저장소 / OCI 이미지에서 매니페스트 fetching |
| kustomize-controller | Kustomize 매니페스트 적용 |
| helm-controller | HelmRelease 객체로 Helm 차트 적용 |
| notification-controller | Slack / Teams / GitHub 등에 이벤트 통지 |
| image-automation-controller | 컨테이너 이미지 새 버전을 git에 자동 commit |
각 컨트롤러가 자기 CRD를 갖고, 그 CRD의 매니페스트로 모든 동작이 표현됩니다.
GitRepository + Kustomization — Flux의 기본 묶음 #
apiVersion: source.toolkit.fluxcd.io/v1
kind: GitRepository
metadata:
name: manifests
namespace: flux-system
spec:
interval: 1m
url: https://github.com/myorg/manifests.git
ref:
branch: main
---
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
name: my-app
namespace: flux-system
spec:
interval: 5m
path: ./apps/my-app/overlays/prod
prune: true
sourceRef:
kind: GitRepository
name: manifests
targetNamespace: my-appGitRepository가 git을 watch 하고, Kustomization이 그 git의 한 디렉터리를 클러스터에 적용합니다. 두 객체의 분리 덕에 같은 git을 여러 Kustomization이 다른 path로 가리킬 수 있습니다.
HelmRelease — Helm 차트의 GitOps 화 #
apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
name: prometheus
namespace: monitoring
spec:
interval: 10m
chart:
spec:
chart: kube-prometheus-stack
version: "55.x"
sourceRef:
kind: HelmRepository
name: prometheus-community
values:
prometheus:
prometheusSpec:
retention: 30dhelm install을 손으로 돌리는 대신 HelmRelease 매니페스트로 표현하면 Helm 차트의 설치 · 업그레이드도 GitOps의 흐름 안으로 들어옵니다. 19장의 kube-prometheus-stack도 같은 모양으로 GitOps 안에 묶을 수 있습니다.
ArgoCD vs Flux — 선택의 결 #
| 차원 | ArgoCD | Flux |
|---|---|---|
| 모델 | 한 큰 컴포넌트 + 풍부한 UI | 작은 컨트롤러의 묶음 + CLI 중심 |
| 진입 장벽 | 낮음 (UI로 시작) | 중간 (CRD 매니페스트로 시작) |
| 멀티테넌시 | AppProject로 표현 | namespace 단위 분리 |
| 멀티클러스터 | 한 ArgoCD가 여러 클러스터 관리 가능 | 각 클러스터에 Flux 한 개 (hub-spoke 가능) |
| Helm 지원 | 1급 | HelmRelease CRD로 1급 |
| 이미지 자동 업데이트 | argocd-image-updater (별도) | image-automation-controller (내장) |
선택의 결은 보통 다음을 따라갑니다.
- 운영 팀이 GUI를 선호하고, 한 화면에서 모든 클러스터를 보고 싶다면 ArgoCD가 자연스럽습니다.
- 모든 운영을 매니페스트로 표현하고 싶고, 작은 컴포넌트의 묶음을 선호한다면 Flux가 잘 맞습니다.
두 도구 모두 CNCF 졸업 프로젝트이고 운영 규모로 굳어 있습니다. 한쪽을 잘못 골라 큰 사고가 나는 종류의 결정은 아닙니다. 24장 CI / CD 파이프라인에서는 GitHub Actions와 ArgoCD의 결합 — 빌드 결과 이미지 태그가 git PR로 들어오고 ArgoCD가 자동 동기화하는 흐름 — 을 본격적으로 다룹니다.
디렉터리 구조 패턴 #
GitOps repo의 디렉터리 구조는 운영 팀의 스타일에 따라 갈리지만, 자주 보는 패턴 두 가지가 있습니다.
1. env-per-folder — 환경별 분기 #
manifests/
base/
my-app/
deployment.yaml
service.yaml
envs/
dev/
kustomization.yaml ← base + dev patch
staging/
kustomization.yaml
prod/
kustomization.yamlKustomize의 base + overlay 패턴을 그대로 활용한 구조입니다. 환경별 차이 (replicas, image tag, resources)가 overlay에 패치로 들어갑니다. 7장 Namespace와 라벨에서 짚었던 환경별 매니페스트 한 벌 패턴이 이 디렉터리 구조 위에서 본격적으로 굴러갑니다.
2. app-per-folder + branch-per-env #
manifests/ (main branch = prod)
apps/
my-app/
deployment.yaml
service.yaml
other-app/
...
manifests-dev/ (dev branch)
manifests-staging/ (staging branch)브랜치를 환경 분기로 쓰는 모델입니다. 환경 차이가 commit으로 표현되어 audit이 자연스럽지만, 브랜치 사이의 sync 부담이 큽니다.
운영에서는 env-per-folder가 더 자주 쓰입니다. 변경의 흐름이 한 브랜치 (main) 안에서 일어나므로 PR 리뷰가 단순합니다.
Secret을 git에 어떻게 올릴까 #
GitOps의 큰 숙제 중 하나가 비밀을 git에 두는 길입니다. K8s Secret을 평문으로 git에 올릴 수는 없습니다. 표준 도구가 셋 있습니다.
| 도구 | 모델 |
|---|---|
| Sealed Secrets | Bitnami가 만든 도구. 비밀을 SealedSecret으로 암호화해 git에 올림. 클러스터 안의 컨트롤러가 자기 키로만 복호화 가능 |
| External Secrets Operator | git에는 외부 비밀 저장소 (AWS Secrets Manager, Vault 등)의 참조만 두고, 컨트롤러가 K8s Secret으로 동기화 |
| SOPS + age / PGP | git에 암호화된 YAML을 직접 올림. ArgoCD / Flux 모두 SOPS 통합 지원 |
External Secrets Operator가 가장 자주 쓰이는 길입니다. 비밀의 source of truth가 외부 저장소에 있고, K8s에는 그 참조만 들어오므로 비밀 회전이 외부 저장소에서 한 번에 끝납니다. 16장 RBAC / ServiceAccount 깊이의 IRSA와 결합하면 비밀 저장소 접근 자격 증명조차 클러스터 안에 정적으로 두지 않을 수 있습니다. 세 도구의 본격적인 운영 비교는 29장 시크릿 운영에서 다룹니다.
운영 시 잡아 둘 원칙 #
1. auto-sync vs manual sync — 환경별 분기 #
syncPolicy.automated를 켜 두면 git의 변경이 즉시 클러스터에 반영됩니다. dev / staging은 자동, prod는 수동 (또는 PR 머지 후 자동)으로 갈래를 두는 게 일반적입니다. prod에 자동 sync를 걸 때는 syncOptions: PruneLast=true로 삭제를 마지막에 처리하는 등의 안전장치를 같이 잡습니다.
2. drift detection의 의미 #
GitOps 컨트롤러는 git과 실제 클러스터의 차이를 계속 비교합니다. 누가 kubectl edit으로 직접 수정하면 그 변경은 즉시 drift로 감지되고, selfHeal: true 이면 git의 매니페스트로 다시 덮어씁니다. 이게 GitOps의 강점이지만, 동시에 함정이기도 합니다 — 컨트롤러가 자동 생성하는 필드 (status, 자동 라벨)는 drift처럼 보이면 안 됩니다. ArgoCD / Flux 모두 ignoreDifferences 설정으로 무시할 필드를 적을 수 있습니다. 18장 §“status subresource"가 이 drift 문제를 CRD 차원에서 미리 분리해 두는 패턴입니다.
3. Helm value 변경의 영향 #
HelmRelease의 values를 바꾸면 그 차트가 만든 모든 객체가 재배포됩니다. 의도치 않은 재배포가 일어나지 않도록 values 변경의 영향 범위를 PR 단계에서 dry-run으로 미리 확인하는 게 좋습니다. 17장 Admission Controller의 dry-run 점진 도입 패턴이 GitOps 동기화와 그대로 묶입니다 — 정책의 dry-run도 GitOps의 dry-run도 같은 방향의 안전장치입니다.
4. 멀티클러스터의 hub-spoke 모델 #
클러스터 N 개를 GitOps로 관리할 때 표준 모델 둘이 있습니다.
- 각 클러스터가 자기 GitOps 컨트롤러를 가짐 — 클러스터 자기완결적, 외부 의존성 적음
- 한 hub 클러스터의 GitOps 컨트롤러가 spoke 클러스터들을 관리 — 운영 단순화, hub의 가용성이 critical
ArgoCD는 두 모델 모두 잘 맞고, Flux는 첫 번째 모델이 자연스럽습니다.
3부 회고 — 깊이 6장으로 손에 들어온 것 #
3부의 마지막 챕터이므로 한 번 짚어 둡니다. 1부가 매니페스트 한 장의 모델을, 2부가 그 매니페스트가 운영 클러스터에서 굴러가는 깊이를, 3부가 그 위에 정책 엔진 · 확장 · 관측 · 동기화의 깊이를 한 층씩 더했습니다.
- 15장 — CNI 깊이. K8s 네트워크 모델의 네 조건, CNI 인터페이스, iptables / IPVS / eBPF의 데이터 플레인, Calico와 Cilium의 비교.
- 16장 — RBAC / ServiceAccount 깊이. Aggregated ClusterRole, Impersonation, projected token, IRSA / Workload Identity로 K8s ServiceAccount를 클라우드 IAM과 연결.
- 17장 — Admission Controller. API 서버의 5단계 흐름, mutating / validating webhook, OPA Gatekeeper와 Kyverno의 정책 엔진 비교.
- 18장 — CRD와 Operator 패턴. K8s API 자체를 확장하는 길, controller-runtime 기반 Operator의 골격, ownerReference / finalizer / status subresource.
- 19장 — 옵저버빌리티. 메트릭 / 로그 / 트레이스의 세 축, Prometheus + kube-state-metrics, Loki, OpenTelemetry, Grafana, Alertmanager.
- 20장 (본 챕터) — GitOps. 매니페스트의 source of truth를 git에 두는 운영 모델, ArgoCD와 Flux, 디렉터리 구조와 비밀 관리.
이 여섯 장을 다 따라온 시점이라면 K8s를 도입하고 운영하는 사람의 시야 — “어떤 CNI를 도입할지, 어떤 정책 엔진을 도입할지, 어떤 옵저버빌리티 스택을 고를지, GitOps 파이프라인을 어떻게 짤지"를 결정하는 단계의 시야가 손에 들어옵니다.
연습문제 #
- ArgoCD를 로컬 클러스터에 설치하고, 본인의 매니페스트 저장소를 가리키는 Application 한 장을 만들어 봅니다.
automated.selfHeal: true로 두고, 그 후kubectl edit으로 클러스터의 객체를 직접 수정해 봅니다. ArgoCD가 drift를 감지하고 git의 매니페스트로 자동 복구하는 흐름을 시간 순서대로 기록하고, §“drift detection의 의미"의 모델로 한 단락으로 정리합니다. - 본인의 매니페스트 저장소를 env-per-folder 구조로 재구성해 봅니다.
base/,envs/dev/,envs/staging/,envs/prod/로 갈라 두고, dev와 prod의replicas· image tag가 어떻게 overlay로 표현되는지를 정리합니다. 7장의 네임스페이스 분리와 이 디렉터리 구조가 어떻게 짝을 이루는지 한 단락으로 메모합니다. - Sealed Secrets, External Secrets Operator, SOPS 세 도구의 모델을 §“Secret을 git에 어떻게 올릴까"의 표로 비교한 뒤, 본인 클러스터 환경 (EKS / GKE / 온프레미스, 외부 비밀 저장소 사용 여부)에 비춰 어느 도구를 고를지 한 단락으로 결정합니다. 16장의 IRSA / Workload Identity와 결합했을 때 어느 도구가 “비밀번호 0” 운영에 가장 매끄럽게 들어맞는지도 함께 추론합니다.
한 줄 요약: GitOps는 매니페스트의 source of truth를 git에 두고 클러스터 안의 컨트롤러가 git을 watch 해 pull · reconcile 하는 운영 모델이다. ArgoCD는 풍부한 UI와 Application CRD · App of Apps · Sync Wave가 강점, Flux는 작은 컨트롤러 묶음 (source · kustomize · helm · notification · image-automation)과 CLI 중심이 강점이다. 비밀은 Sealed Secrets · External Secrets · SOPS 세 도구 중 환경에 맞춰 고르고, IRSA와 결합하면 비밀 저장소 접근까지 정적 자격 증명 없이 운영할 수 있다. 운영의 네 가드레일은 환경별 auto-sync 분기 · drift detection의
ignoreDifferences· Helm value 변경의 영향 점검 · 멀티클러스터의 hub-spoke 결정이다.
다음 챕터 #
3부가 끝났습니다. 1~3부가 K8s의 매니페스트와 그 운영 모델을 매니페스트 차원에서 이해하는 길이었다면, 4부는 그 위에 진짜 서비스를 한 개 올리고 운영하는 한 사이클입니다. EKS 위에 클러스터를 처음부터 셋업하고, 앱 배포 골격을 잡고, DB를 연결하고, CI / CD 파이프라인을 짜고, 모니터링 · 알람을 거는 흐름을 처음부터 끝까지 따라갑니다.
4부 전체의 줄거리는 다음과 같습니다.
| 챕터 | 주제 |
|---|---|
| 21장 | EKS 클러스터 셋업 — Terraform · eksctl · IRSA · 애드온 |
| 22장 | 앱 배포 골격 — Deployment · Service · Ingress · Helm |
| 23장 | DB 연동 — RDS · Secrets Manager · External Secrets · 커넥션 풀 |
| 24장 | CI / CD 파이프라인 — GitHub Actions · ECR · ArgoCD |
| 25장 | 모니터링·알람 — Prometheus · CloudWatch · Alertmanager |
| 26장 | 운영 체크리스트 — 업그레이드 · 백업·복구 · 비용 · 보안 |
21장 EKS 클러스터 셋업부터는 추상이 아니라 진짜 도입 사례입니다. Terraform으로 VPC · IAM · EKS 클러스터를 처음부터 만들고, 노드 그룹과 애드온을 잡고, IRSA와 ALB Controller를 같이 설치하는 한 사이클을 따라갑니다.