Notes
GitOps Source of Truth
GitOps를 Git 기반 desired state 운영 모델로 정리하고, DevOps와의 관계, 4가지 원칙, pull-based reconciliation, drift detection, rollback, Kubernetes 적용 방식을 설명한다.
- Published
- Updated
- Area
- Cloud Infrastructure
- Type
- concept
- Series
- DevOps Explained
- Category
- Notes
개요
GitOps는 Git을 단순한 source code 저장소가 아니라, 운영 환경의 desired state를 저장하는 source of truth로 사용하는 운영 방식이다.
일반적인 CI/CD에서는 pipeline이 build와 test를 수행한 뒤, 직접 cluster에 배포 명령을 실행하는 경우가 많다.
일반적인 CI/CD push 방식:
code 변경
-> CI pipeline 실행
-> image build
-> registry push
-> kubectl apply 또는 helm upgrade
-> production cluster 변경
GitOps에서는 관점이 달라진다.
GitOps 방식:
Git repository에 원하는 상태를 선언
-> GitOps controller가 Git을 감시
-> cluster의 실제 상태와 Git의 desired state 비교
-> 차이가 있으면 자동 reconcile
즉, GitOps는 단순히 Git을 사용하는 배포 방식이 아니다. Git에 저장된 선언적 configuration을 기준으로 실제 시스템 상태를 계속 맞추는 운영 모델이다.
핵심을 짧게 정리하면 다음과 같다.
GitOps = Git에 선언된 desired state를 기준으로
cluster와 infrastructure의 실제 상태를 자동으로 맞추는 운영 방식
GitOps가 필요한 이유
Kubernetes 환경에서는 application 하나를 배포할 때도 여러 리소스가 함께 움직인다.
Deployment
Service
Ingress
ConfigMap
Secret
PersistentVolumeClaim
HorizontalPodAutoscaler
NetworkPolicy
ServiceAccount
Role / RoleBinding
작은 서비스 하나라면 사람이 직접 kubectl apply를 실행해도 관리할 수 있다. 하지만 서비스가 많아지고, cluster가 dev/staging/production으로 나뉘고, 여러 팀이 동시에 배포하기 시작하면 다음 질문이 중요해진다.
누가 production에 어떤 manifest를 적용했는가?
현재 cluster 상태가 Git에 있는 파일과 같은가?
긴급 수정으로 cluster에 직접 바꾼 값이 남아 있지 않은가?
rollback하려면 어떤 상태로 되돌려야 하는가?
dev/staging/prod 환경 차이가 의도된 것인가?
전통적인 push-based CD에서는 CI server가 cluster에 직접 명령을 내린다.
CI server:
kubectl apply -f k8s/
helm upgrade my-app ./chart
이 방식은 단순하고 직관적이다. 하지만 운영 관점에서는 다음 문제가 생길 수 있다.
| 문제 | 설명 |
|---|---|
| Cluster credential 노출 | CI server가 production cluster 접근 권한을 가져야 한다. |
| 변경 추적 어려움 | 실제 cluster에 적용된 상태와 Git 상태가 달라질 수 있다. |
| Drift 발생 | 누군가 cluster에서 직접 수정하면 Git과 live state가 달라진다. |
| Rollback 기준 불명확 | 이전에 어떤 manifest가 적용되었는지 추적이 어려울 수 있다. |
| Multi-cluster 확장 어려움 | 여러 cluster에 같은 방식으로 push하려면 credential과 pipeline이 복잡해진다. |
| Audit 약함 | 누가 어떤 desired state를 승인했는지 Git history와 분리될 수 있다. |
GitOps는 이 문제를 다음 구조로 바꾼다.
Git repository:
운영 환경의 desired state 저장
GitOps controller:
Git을 감시하고 cluster 상태와 비교
Cluster:
controller가 내부에서 desired state로 reconcile
이 구조에서는 CI server가 production cluster에 직접 접근하지 않아도 된다. CI는 image를 만들고 Git의 deployment repository를 갱신하는 데 집중하고, 실제 cluster 반영은 cluster 안의 GitOps controller가 수행한다.
GitOps와 DevOps의 관계
GitOps와 DevOps는 경쟁 개념이 아니다.
DevOps는 개발과 운영의 협업, CI/CD 자동화, feedback loop 단축, infrastructure automation, monitoring과 운영 개선을 포함하는 더 넓은 문화와 실천 방식이다.
DevOps:
Development와 Operations의 협업
CI/CD 자동화
feedback loop 단축
infrastructure automation
monitoring과 운영 개선
빠르고 안정적인 software delivery
GitOps는 그중에서도 특히 deployment와 operations를 Git 기반으로 선언적·자동화·감사 가능하게 만드는 방식이다.
GitOps:
Git을 source of truth로 사용
desired state를 선언적으로 저장
controller가 actual state와 desired state를 비교
drift가 있으면 reconcile
변경 이력과 rollback을 Git history로 관리
관계를 표로 정리하면 다음과 같다.
| 구분 | DevOps | GitOps |
|---|---|---|
| 범위 | 개발·운영 협업 전체 | 배포와 운영 상태 관리 방식 |
| 중심 도구 | CI/CD, IaC, monitoring, collaboration | Git, declarative config, controller |
| 핵심 목표 | 빠르고 안정적인 delivery | auditable하고 reproducible한 deployment |
| 상태 관리 | pipeline과 운영 도구마다 다를 수 있음 | Git desired state 중심 |
| 배포 방식 | push-based 또는 pull-based 모두 가능 | 주로 pull-based reconciliation |
| Kubernetes와 관계 | Kubernetes 외 환경도 포함 | Kubernetes와 특히 잘 맞음 |
즉, DevOps가 목표와 문화라면, GitOps는 그 목표를 Kubernetes/cloud-native 환경에서 구현하는 delivery pattern에 가깝다.
DevOps가 목표와 문화라면,
GitOps는 그 목표를 Kubernetes/cloud-native 환경에서 구현하는 delivery pattern이다.
GitOps의 4가지 핵심 원칙
GitOps를 이해할 때는 다음 네 가지 원칙을 중심으로 보는 것이 좋다.
Declarative
Versioned and Immutable
Pulled Automatically
Continuously Reconciled
1. Declarative
GitOps에서 관리되는 시스템의 desired state는 declarative해야 한다.
Declarative하다는 것은 “어떤 명령을 어떤 순서로 실행하라”가 아니라, “최종적으로 어떤 상태가 되어야 한다”를 정의한다는 뜻이다.
Imperative 방식은 다음처럼 명령의 순서를 직접 나열한다.
kubectl create deployment web --image=nginx:1.27
kubectl scale deployment web --replicas=3
kubectl expose deployment web --port=80
반면 declarative 방식은 원하는 최종 상태를 YAML로 표현한다.
apiVersion: apps/v1
kind: Deployment
metadata:
name: web
spec:
replicas: 3
selector:
matchLabels:
app: web
template:
metadata:
labels:
app: web
spec:
containers:
- name: web
image: nginx:1.27
ports:
- containerPort: 80
GitOps에서는 Git에 이런 desired state를 저장한다.
Git에 저장되는 것:
Kubernetes manifest
Helm values
Kustomize overlay
policy
environment-specific configuration
중요한 점은 GitOps가 단순히 Kubernetes YAML만 저장하는 방식은 아니라는 것이다. 선언적으로 표현 가능한 application configuration, infrastructure configuration, policy도 GitOps 대상이 될 수 있다.
2. Versioned and Immutable
GitOps에서 desired state는 versioned and immutable해야 한다. 즉, 현재 상태뿐 아니라 과거 상태도 추적 가능해야 한다.
Git commit A:
image: app:v1
Git commit B:
image: app:v2
Git commit C:
replicas: 5
이 구조에서는 다음 질문에 답할 수 있다.
누가 변경했는가?
언제 변경했는가?
무엇이 변경되었는가?
왜 변경했는가?
어떤 commit으로 되돌리면 되는가?
GitOps에서 latest tag를 사용하는 것은 주의해야 한다.
image: my-app:latest
겉으로는 Git에 desired state가 저장된 것처럼 보이지만, latest가 가리키는 실제 image는 시간이 지나며 바뀔 수 있다. 그러면 Git commit만으로 정확히 어떤 artifact가 배포되었는지 알기 어렵다.
더 안전한 방식은 commit SHA나 immutable tag, 가능하면 image digest를 사용하는 것이다.
image: registry.example.com/my-app:a1b2c3d
또는 다음처럼 digest를 사용할 수 있다.
image: registry.example.com/my-app@sha256:...
GitOps에서 versioned and immutable은 단순히 Git을 쓴다는 뜻이 아니라, Git history만으로 desired state의 변경 이력을 신뢰할 수 있어야 한다는 뜻이다.
3. Pulled Automatically
GitOps에서는 software agent가 desired state를 자동으로 pull해야 한다.
전통적인 push 방식에서는 CI server가 cluster에 명령을 보낸다.
CI server
-> kubectl apply
-> cluster 변경
GitOps의 pull 방식에서는 cluster 안의 controller가 Git을 감시한다.
Git repository
<- GitOps controller가 pull
-> cluster state reconcile
이 차이는 보안과 운영에 큰 영향을 준다.
| 구분 | Push-based CD | Pull-based GitOps |
|---|---|---|
| 실행 주체 | 외부 CI server | cluster 내부 controller |
| Cluster credential 위치 | CI server에 필요 | cluster 내부에 제한적으로 존재 |
| 변경 감지 | pipeline 실행 시점 중심 | controller가 지속적으로 Git 감시 |
| Drift 대응 | 별도 drift detection 필요 | controller가 지속적으로 비교 가능 |
| Multi-cluster | CI가 여러 cluster credential 관리 | 각 cluster가 자기 Git 상태를 pull |
Pull 방식의 장점은 production cluster credential을 외부 CI server에 넓게 배포하지 않아도 된다는 점이다. 각 cluster가 자기에게 필요한 Git repository를 읽고, 자기 cluster 상태를 맞춘다.
물론 pull 방식도 보안 설계가 필요하다. GitOps controller가 Git repository에 접근할 credential과 cluster 안에서 resource를 수정할 RBAC 권한을 갖기 때문이다.
4. Continuously Reconciled
GitOps에서 controller는 desired state와 actual state를 지속적으로 비교하고 reconcile한다.
desired state:
Git에 선언된 상태
actual state:
cluster에 실제 존재하는 상태
reconciliation:
둘의 차이를 감지하고 desired state로 맞추는 과정
예를 들어 Git에는 replicas: 3이 선언되어 있는데, 누군가 cluster에서 직접 replicas: 5로 바꾸었다고 하자.
Git:
replicas: 3
Cluster:
replicas: 5
GitOps controller:
drift 감지
replicas를 다시 3으로 조정
이것이 GitOps의 핵심이다. 단순히 Git에 YAML을 저장하는 것이 아니라, 실제 환경이 Git에 선언된 상태와 계속 일치하도록 만드는 것이다.
이 개념은 Kubernetes controller의 reconciliation model과 잘 맞는다.
Kubernetes controller:
Deployment desired state와 Pod actual state를 맞춤
GitOps controller:
Git desired state와 cluster actual state를 맞춤
GitOps의 기본 Workflow
GitOps workflow를 단순화하면 다음과 같다.
1. 개발자가 code 변경
2. CI pipeline이 test/build 수행
3. container image 생성
4. image를 registry에 push
5. GitOps repository의 image tag 또는 manifest 변경
6. pull request 생성
7. review 후 merge
8. GitOps controller가 변경 감지
9. cluster에 desired state 반영
10. 상태와 health 확인
Kubernetes 관점에서는 다음처럼 표현할 수 있다.
Application repository:
source code
CI:
test
build
image push
Registry:
container image 저장
GitOps repository:
deployment manifest / Helm values / Kustomize overlay 저장
GitOps controller:
Git repository 감시
cluster actual state와 desired state 비교
sync/reconcile 수행
Kubernetes cluster:
실제 workload 실행
이 구조에서는 application source code repository와 deployment configuration repository를 분리할 수도 있고, 하나의 repository 안에서 디렉터리를 나눌 수도 있다.
GitOps Repository 구조
GitOps를 도입할 때 중요한 결정 중 하나가 repository 구조다.
Application repo와 GitOps repo 분리
app-repo:
src/
Dockerfile
tests/
package.json
gitops-repo:
apps/my-app/base/
apps/my-app/overlays/dev/
apps/my-app/overlays/staging/
apps/my-app/overlays/prod/
이 구조의 장점은 application code와 deployment state가 분리된다는 것이다.
| 장점 | 설명 |
|---|---|
| 권한 분리 | 개발자는 app repo, 운영자는 prod GitOps repo 관리 가능 |
| 배포 이력 명확 | deployment 변경만 별도 추적 가능 |
| 환경별 관리 쉬움 | dev/staging/prod overlay 분리 가능 |
| GitOps controller 대상 명확 | controller가 deployment repo만 감시 |
단점도 있다.
단점:
repository가 늘어남
image tag update 자동화가 필요함
code 변경과 deployment 변경의 연결을 추적해야 함
Monorepo 방식
repo:
services/my-app/src/
services/my-app/Dockerfile
deploy/my-app/base/
deploy/my-app/overlays/dev/
deploy/my-app/overlays/prod/
이 구조는 한 repository 안에 application code와 deployment config를 함께 둔다.
장점은 다음과 같다.
장점:
code와 manifest 변경을 한 PR에서 관리 가능
작은 팀이나 단일 서비스에 단순함
commit 단위 추적이 쉬움
단점은 다음과 같다.
단점:
repository 권한 분리가 어려울 수 있음
여러 팀이 함께 쓰면 복잡해짐
GitOps controller가 감시할 path를 신중히 제한해야 함
조직 규모와 권한 모델에 따라 repository 구조 선택이 달라진다.
GitOps와 Kubernetes가 잘 맞는 이유
GitOps는 Kubernetes와 특히 잘 맞는다. 이유는 Kubernetes 자체가 declarative desired state model을 사용하기 때문이다.
Kubernetes에서는 사용자가 원하는 상태를 YAML로 선언한다.
apiVersion: apps/v1
kind: Deployment
metadata:
name: api
spec:
replicas: 3
template:
spec:
containers:
- name: api
image: registry.example.com/api:a1b2c3d
Kubernetes controller는 이 desired state에 맞춰 실제 Pod를 생성하고 유지한다. GitOps controller는 한 단계 위에서 작동한다.
GitOps controller:
Git에 있는 Kubernetes manifest를 cluster에 반영
Kubernetes controller:
cluster에 반영된 manifest를 기준으로 Pod/Service 상태를 유지
즉, GitOps는 Kubernetes reconciliation model을 Git repository까지 확장한 것처럼 볼 수 있다.
Git desired state
-> GitOps controller
-> Kubernetes API object
-> Kubernetes controller
-> Pod/Service actual state
Argo CD와 Flux의 역할
GitOps를 구현하는 대표적인 도구는 Argo CD와 Flux다.
두 도구 모두 Git repository를 감시하고 Kubernetes cluster 상태를 desired state와 맞추는 역할을 한다.
| 도구 | 특징 |
|---|---|
| Argo CD | UI가 강하고 Application 중심으로 상태를 확인하기 좋다. |
| Flux | Kubernetes controller 방식에 가깝고 Git/OCI source, Kustomize/Helm 연계가 강하다. |
도구를 선택할 때는 다음을 봐야 한다.
| 기준 | 확인할 점 |
|---|---|
| UI 필요성 | 운영자가 UI에서 sync 상태를 봐야 하는가? |
| Multi-cluster | 여러 cluster를 어떻게 관리할 것인가? |
| Helm/Kustomize | 어떤 manifest packaging 방식을 쓰는가? |
| 권한 모델 | 팀별 application 권한을 어떻게 나눌 것인가? |
| Drift 처리 | out-of-sync 상태를 어떻게 감지하고 복구할 것인가? |
| Rollback | Git revert와 도구의 rollback model을 어떻게 사용할 것인가? |
| Secret 관리 | sealed secret, external secret, vault 연계를 어떻게 할 것인가? |
GitOps의 핵심은 특정 도구가 아니라 Git desired state와 continuous reconciliation이다. 도구는 이 원칙을 구현하는 수단이다.
Push-based CD와 Pull-based GitOps 비교
GitOps를 이해할 때 가장 중요한 비교가 push와 pull이다.
Push-based CD
CI/CD pipeline:
cluster credential 보유
kubectl apply 실행
cluster에 직접 변경 push
장점은 다음과 같다.
- 구조가 단순함
- 기존 CI/CD 도구와 익숙함
- 즉시 명령 실행 가능
- 초기 도입이 쉬움
단점은 다음과 같다.
- CI server에 cluster credential이 필요함
- cluster drift를 계속 감지하기 어려움
- 여러 cluster로 확장 시 credential 관리가 복잡함
- 실제 cluster 상태가 Git과 달라질 수 있음
Pull-based GitOps
GitOps controller:
cluster 내부에서 Git repository 감시
desired state를 pull
actual state와 비교
reconcile 수행
장점은 다음과 같다.
- Git이 source of truth가 됨
- cluster credential을 외부 CI에 넓게 배포하지 않아도 됨
- drift detection과 reconciliation이 자연스러움
- rollback이 Git revert 중심으로 단순해짐
- multi-cluster 운영에 적합함
단점도 있다.
- GitOps controller 운영이 필요함
- Git repository 구조 설계가 필요함
- Secret 관리 방식이 중요해짐
- 자동 reconcile이 원하지 않는 변경을 되돌릴 수 있음
- stateful workload와 migration은 별도 전략이 필요함
비교하면 다음과 같다.
| 구분 | Push-based CD | Pull-based GitOps |
|---|---|---|
| 배포 실행 위치 | CI/CD server | Cluster 내부 controller |
| Source of truth | Pipeline 실행 결과 또는 Git | Git repository |
| Credential | CI server가 cluster credential 보유 | Controller가 제한된 권한으로 cluster 내부에서 동작 |
| Drift 감지 | 별도 구현 필요 | 기본 모델에 포함 |
| Rollback | pipeline 재실행 또는 수동 rollback | Git revert 중심 |
| Multi-cluster | pipeline이 여러 cluster에 push | 각 cluster가 Git에서 pull |
| 운영 복잡도 | 초기 단순 | controller/repo 설계 필요 |
GitOps와 CI/CD의 역할 분리
GitOps를 도입하면 CI와 CD의 역할이 더 명확해진다.
CI:
source code 검증
unit/integration test
container image build
image scan
registry push
SBOM/provenance 생성
GitOps CD:
deployment config 변경 감시
cluster sync
drift detection
health check
rollback 지원
예를 들어 Tekton과 Argo CD를 함께 쓴다면 다음 구조가 자연스럽다.
Tekton:
Git clone
test
image build
image push
GitOps repo image tag update
Argo CD:
GitOps repo 감시
cluster와 desired state 비교
sync
health 확인
이렇게 역할을 나누면 CI pipeline이 production cluster에 직접 접근하지 않아도 된다.
CI의 책임:
artifact를 안전하게 만들기
GitOps controller의 책임:
선언된 desired state를 cluster에 반영하기
이 분리는 보안과 운영 측면에서 중요하다.
Image Tag 업데이트 방식
GitOps workflow에서 자주 고민되는 지점이 image tag 업데이트다.
CI가 image를 만들면 GitOps repository의 manifest나 Helm values를 갱신해야 한다.
예를 들어 CI가 다음 image를 만들었다고 하자.
registry.example.com/my-app:a1b2c3d
그러면 GitOps repo의 manifest가 바뀐다.
image:
repository: registry.example.com/my-app
tag: a1b2c3d
또는 Deployment manifest가 직접 바뀔 수 있다.
containers:
- name: my-app
image: registry.example.com/my-app:a1b2c3d
이 변경을 자동 commit할 수도 있고, PR로 만들 수도 있다.
자동 commit 방식:
CI가 GitOps repo에 바로 commit
GitOps controller가 sync
PR 방식:
CI가 image tag update PR 생성
reviewer 승인
merge 후 sync
각 방식의 차이는 다음과 같다.
| 방식 | 장점 | 주의점 |
|---|---|---|
| 자동 commit | 빠름, 완전 자동화에 적합 | production까지 자동 반영될 수 있음 |
| PR 방식 | review와 승인 가능 | lead time이 늘 수 있음 |
| 환경별 promotion | dev→staging→prod 단계 관리 쉬움 | promotion workflow 설계 필요 |
Production에는 PR 기반 promotion을 두고, dev에는 자동 commit을 두는 식으로 환경별 정책을 나눌 수 있다.
Environment 분리와 Promotion
GitOps에서는 dev, staging, production 환경을 어떻게 나눌지가 중요하다.
대표적인 구조는 다음과 같다.
apps/
my-app/
base/
deployment.yaml
service.yaml
overlays/
dev/
kustomization.yaml
values.yaml
staging/
kustomization.yaml
values.yaml
prod/
kustomization.yaml
values.yaml
base에는 공통 설정을 두고, 환경별 차이는 overlays에서 관리한다.
| 환경 | 차이 예시 |
|---|---|
| dev | replica 1, 작은 resource request, debug logging |
| staging | production-like config, test database |
| prod | replica 3+, stricter resource, production secret, HPA |
주의할 점은 환경 차이가 너무 커지면 staging이 production 검증 역할을 하지 못한다는 것이다.
나쁜 구조:
dev/staging/prod가 거의 다른 시스템처럼 동작
좋은 구조:
공통 base를 유지하고, 필요한 차이만 overlay로 분리
GitOps에서는 환경 차이도 Git diff로 확인할 수 있어야 한다.
Drift Detection
GitOps의 큰 장점 중 하나가 drift detection이다.
Drift는 Git에 선언된 desired state와 실제 cluster 상태가 달라진 상태다.
예를 들어 Git에는 다음이 있다.
replicas: 3
그런데 누군가 cluster에서 직접 수정한다.
kubectl scale deployment api --replicas=5
그러면 상태는 다음과 같다.
Git desired state:
replicas = 3
Cluster actual state:
replicas = 5
결과:
drift 발생
GitOps controller는 이를 감지하고 다시 Git 상태로 맞출 수 있다.
drift 감지
-> out-of-sync 표시
-> 자동 sync 또는 수동 sync
-> replicas = 3으로 복구
이 기능은 운영 안정성에 중요하다.
장점:
cluster 수동 변경을 감지
Git을 source of truth로 유지
audit되지 않은 변경을 줄임
환경 재현성을 높임
다만 모든 drift를 즉시 자동으로 되돌리는 것이 항상 좋은 것은 아니다. 긴급 장애 대응 중 수동 scaling을 했는데 GitOps controller가 바로 되돌리면 운영자가 의도한 임시 대응이 실패할 수 있다.
따라서 auto-sync 정책은 환경별로 다르게 설계해야 한다.
| 환경 | 권장 정책 예시 |
|---|---|
| dev | auto-sync 적극 사용 |
| staging | auto-sync + pruning 가능 |
| production | auto-sync 여부 신중히 결정, manual approval 또는 sync window 고려 |
| incident 중 | auto-sync 일시 중단 절차 필요 |
Rollback
GitOps에서 rollback은 보통 Git revert로 표현된다.
문제 발생:
commit C에서 production 장애
대응:
Git revert commit C
GitOps controller가 이전 desired state로 sync
이 방식의 장점은 rollback도 Git history에 남는다는 것이다.
누가 rollback했는가?
어떤 commit을 revert했는가?
언제 rollback했는가?
rollback 이후 cluster 상태는 어떤가?
하지만 주의할 점이 있다. 모든 장애가 Git revert만으로 해결되지는 않는다.
다음 변경은 rollback이 어렵다.
database schema migration
data format 변경
message queue event schema 변경
cache key format 변경
external API contract 변경
stateful workload 변경
예를 들어 application image만 이전으로 되돌려도 database schema가 이미 바뀌었다면 이전 version이 동작하지 않을 수 있다.
따라서 GitOps에서도 backward compatibility가 중요하다.
안전한 migration 예:
1. 새 column 추가
2. app이 old/new schema 모두 읽도록 배포
3. data backfill
4. app이 new schema 사용
5. old column 제거
GitOps rollback은 강력하지만, application과 data compatibility가 함께 설계되어야 한다.
GitOps와 보안
GitOps는 보안 측면에서 장점이 많지만, 잘못 설계하면 새로운 위험도 생긴다.
장점
| 장점 | 설명 |
|---|---|
| 변경 이력 | 모든 desired state 변경이 Git history에 남는다. |
| Review | production 변경을 PR review로 검토할 수 있다. |
| 권한 분리 | CI가 production cluster credential을 직접 갖지 않아도 된다. |
| Drift 감지 | 수동 변경과 비인가 변경을 탐지할 수 있다. |
| Audit | 누가 어떤 상태를 승인했는지 추적 가능하다. |
| Rollback | Git revert로 desired state 복구 가능하다. |
주의할 점
GitOps repo에는 민감 정보를 그대로 넣으면 안 된다.
절대 직접 넣지 말아야 할 것:
password
token
private key
kubeconfig
database credential
cloud access key
Kubernetes Secret manifest도 base64 encoding일 뿐 암호화가 아니다.
apiVersion: v1
kind: Secret
data:
password: cGFzc3dvcmQ=
이 값은 쉽게 decode할 수 있다.
따라서 GitOps에서는 secret 관리 전략이 필요하다.
| 방식 | 설명 |
|---|---|
| External Secrets | external secret manager에서 cluster로 secret 동기화 |
| Sealed Secrets | encrypted Secret을 Git에 저장하고 cluster에서 복호화 |
| SOPS | YAML secret을 암호화하여 Git에 저장 |
| Vault 연동 | runtime에 secret manager에서 주입 |
| CI/CD secret store | pipeline 단계에서 필요한 credential만 사용 |
또한 GitOps controller의 권한도 최소화해야 한다.
나쁜 예:
Argo CD/Flux controller가 cluster-admin
모든 namespace와 secret에 접근 가능
좋은 방향:
application별 namespace 권한 제한
project별 repository scope 제한
production sync 권한 제한
Git repository write 권한 최소화
Policy as Code와 GitOps
GitOps는 Policy as Code와 잘 맞는다.
GitOps repo에 들어오는 변경을 PR 단계에서 검사할 수 있고, cluster admission 단계에서도 검사할 수 있다.
예를 들어 다음 정책을 둘 수 있다.
- privileged container 금지
- hostPath volume 제한
- container는 root로 실행 금지
- production namespace에는 resource requests/limits 필수
- LoadBalancer service는 승인된 namespace에서만 허용
- image는 승인된 registry에서만 허용
- latest tag 사용 금지
- Secret plaintext commit 금지
GitOps workflow에서 policy check는 다음 지점에 들어갈 수 있다.
Pull Request:
manifest lint
schema validation
policy-as-code check
Merge:
GitOps controller sync
Admission:
Kubernetes admission controller가 최종 정책 검증
Runtime:
drift와 policy violation 관찰
이렇게 하면 잘못된 desired state가 Git에 들어가기 전에 막고, 혹시 들어가더라도 cluster에서 다시 막을 수 있다.
Progressive Delivery와 GitOps
GitOps는 progressive delivery와도 결합할 수 있다.
Progressive delivery는 새 version을 한 번에 전체 사용자에게 배포하지 않고, canary, blue-green, feature flag 등을 통해 점진적으로 노출하는 방식이다.
GitOps + Canary:
Git에 새 version 선언
canary controller가 5% traffic에 먼저 배포
metrics 확인
정상이라면 25%, 50%, 100%로 확대
비정상이라면 rollback
GitOps는 desired state 변경을 관리하고, progressive delivery controller는 rollout 전략과 metric 검증을 담당한다.
확인할 metric은 다음과 같다.
| Metric | 목적 |
|---|---|
| HTTP 5xx rate | server error 증가 여부 |
| p95/p99 latency | 지연 악화 여부 |
| request success rate | 요청 성공률 |
| pod restart count | crash 여부 |
| business transaction success | 실제 user journey 성공 여부 |
| SLO burn rate | reliability 목표 영향 |
GitOps가 있다고 해서 배포가 자동으로 안전해지는 것은 아니다. GitOps는 원하는 상태를 안정적으로 반영하는 방식이고, 새 version이 application-level로 안전한지는 test, canary, observability가 함께 판단해야 한다.
GitOps와 Observability
GitOps를 운영하려면 observability가 필요하다.
GitOps controller가 sync에 성공했다고 해서 application이 정상이라는 뜻은 아니다.
Sync 성공:
manifest가 cluster에 적용됨
Health 정상:
Kubernetes resource가 기대한 상태임
Application 정상:
실제 사용자 요청이 성공하고 latency가 정상임
이 세 가지는 다르다.
GitOps에서 확인해야 할 상태는 다음과 같다.
| 상태 | 의미 |
|---|---|
| Sync status | Git desired state와 cluster actual state가 일치하는가 |
| Health status | Kubernetes resource가 정상 상태인가 |
| Drift status | Git과 다른 수동 변경이 있는가 |
| Rollout status | 새 version 배포가 완료되었는가 |
| Application metric | error rate, latency, throughput이 정상인가 |
| Business metric | 핵심 사용자 journey가 정상인가 |
GitOps controller의 UI나 CLI는 sync와 health를 보여줄 수 있지만, SLO나 user impact는 Prometheus, Grafana, Alertmanager, tracing, logging 같은 observability stack과 함께 봐야 한다.
Multi-cluster GitOps
GitOps는 multi-cluster 운영에 특히 유용하다.
여러 cluster가 있을 때 push-based CD는 CI server가 각 cluster credential을 관리해야 한다.
CI server:
dev kubeconfig
staging kubeconfig
prod kubeconfig
region-a kubeconfig
region-b kubeconfig
GitOps에서는 각 cluster가 자기 Git repository 또는 path를 pull하도록 구성할 수 있다.
cluster-dev:
Git path: clusters/dev
cluster-staging:
Git path: clusters/staging
cluster-prod:
Git path: clusters/prod
이 구조의 장점은 다음과 같다.
- cluster별 desired state 분리
- cluster credential 외부 노출 감소
- cluster가 자기 상태를 스스로 reconcile
- 신규 cluster bootstrap 자동화 가능
- Git diff로 cluster 간 차이 확인 가능
Multi-cluster GitOps에서는 repo structure와 controller 배치 방식이 중요하다.
| 방식 | 설명 |
|---|---|
| cluster별 controller | 각 cluster 안에 GitOps controller 설치 |
| hub-and-spoke | 중앙 cluster의 controller가 여러 cluster 관리 |
| environment path 분리 | Git path로 dev/staging/prod 분리 |
| app-of-apps pattern | 상위 application이 여러 하위 app 관리 |
| bootstrap repo | cluster 초기 설치 상태를 Git으로 관리 |
어떤 구조가 맞는지는 cluster 수, 보안 정책, 네트워크 접근성, 운영팀 구조에 따라 달라진다.
GitOps와 Infrastructure as Code의 차이
GitOps와 IaC는 겹치지만 같은 말은 아니다.
IaC는 infrastructure를 code로 정의하는 방식이다.
IaC:
Terraform
CloudFormation
Pulumi
Ansible
Kubernetes YAML
GitOps는 Git에 저장된 desired state를 controller가 자동으로 pull하고 reconcile하는 운영 방식이다.
| 구분 | IaC | GitOps |
|---|---|---|
| 핵심 | infrastructure를 code로 정의 | Git desired state와 actual state를 reconcile |
| 범위 | provisioning, configuration | deployment, operations, cluster state management |
| 실행 방식 | plan/apply, script, pipeline 등 다양 | controller 기반 pull/reconcile 중심 |
| Source of truth | 보통 Git | Git 또는 versioned desired state store |
| Drift 대응 | 별도 plan/drift detection 필요 | continuous reconciliation에 포함 |
| 예시 | Terraform으로 VPC 생성 | Argo CD/Flux로 Kubernetes app sync |
즉, IaC는 GitOps의 재료가 될 수 있다. 하지만 Git에 Terraform code를 저장했다고 자동으로 GitOps가 되는 것은 아니다.
Git에 IaC 저장:
version control은 됨
GitOps:
agent가 desired state를 pull하고
actual state를 계속 reconcile해야 함
Kubernetes Homelab에서 GitOps 적용하기
개인 k3s나 homelab 환경에서도 GitOps는 유용하다.
k3s, Traefik, Longhorn, Nexus, MetalLB, registry 같은 구성 요소를 운영한다면, GitOps는 “서버가 날아가도 다시 만들 수 있는 상태”를 만드는 데 도움이 된다.
예를 들어 다음을 GitOps로 관리할 수 있다.
| 영역 | GitOps 관리 대상 |
|---|---|
| Namespace | 서비스별 namespace |
| Ingress | Traefik IngressRoute, TLS 설정 |
| Storage | Longhorn StorageClass, backup 설정 |
| Registry | Nexus/Harbor deployment, PVC, ingress |
| Observability | Prometheus, Grafana, Loki values |
| App | Deployment, Service, ConfigMap, HPA |
| Network | MetalLB IPAddressPool, L2Advertisement |
| Security | RBAC, NetworkPolicy, ServiceAccount |
작은 homelab에서는 다음부터 시작하는 것이 현실적이다.
1. Kubernetes manifest와 Helm values를 Git에 저장
2. Argo CD 또는 Flux 설치
3. dev/internal service부터 GitOps로 관리
4. Secret은 Git에 평문으로 넣지 않음
5. 수동 변경이 생기면 Git에 반영
6. cluster 재구축 절차를 README로 정리
예시 구조는 다음과 같다.
homelab-gitops/
clusters/
k3s-main/
apps/
traefik/
longhorn/
nexus/
prometheus/
grafana/
infrastructure/
metallb/
storageclass/
namespaces/
Homelab에서 GitOps의 장점은 다음이다.
- 어떤 서비스가 어떤 values로 설치되었는지 Git에 남음
- 장애 후 복구가 쉬워짐
- 수동 변경과 drift를 줄일 수 있음
- ingress, storage, registry 구성을 문서화할 수 있음
- 새 node나 새 cluster로 이관할 때 재현성이 좋아짐
주의할 점도 있다.
- secret을 Git에 그대로 넣지 말 것
- auto-sync가 storage나 database workload에 미치는 영향 검토
- Longhorn, database, registry처럼 stateful workload는 backup/restore 전략 필요
- GitOps controller 자체 복구 절차도 필요
- bootstrap dependency를 고려해야 함
특히 GitOps controller도 cluster 안에서 동작하므로, cluster 자체가 완전히 망가졌을 때 controller를 어떻게 다시 설치할지 bootstrap 절차가 필요하다.
Bootstrap 문제
GitOps를 쓰다 보면 중요한 질문이 생긴다.
GitOps controller도 cluster 안에 있는데,
cluster가 새로 만들어졌을 때 GitOps controller는 누가 설치하는가?
이를 bootstrap 문제라고 볼 수 있다.
일반적인 흐름은 다음과 같다.
1. Kubernetes cluster 생성
2. 최소한의 bootstrap command 실행
3. GitOps controller 설치
4. GitOps controller가 Git repo를 바라보도록 설정
5. 나머지 platform component를 GitOps로 설치
즉, GitOps가 모든 것을 처음부터 자동으로 해결하는 것은 아니다. 최소 bootstrap 단계는 필요하다.
Homelab에서도 다음처럼 나눌 수 있다.
Manual/bootstrap:
k3s 설치
kubeconfig 확보
GitOps controller 설치
Git repository 연결
GitOps-managed:
namespace
ingress
storage
monitoring
registry
application
이 경계를 명확히 해야 복구 절차가 단순해진다.
자칫 실수하기 쉬운 부분
Git에 YAML을 저장하면 GitOps라고 생각하는 경우
Git에 Kubernetes manifest를 저장하는 것은 GitOps의 일부일 수 있다. 하지만 controller가 actual state를 continuously reconcile하지 않는다면 완전한 GitOps라고 보기 어렵다.
Git에 YAML 저장:
version control
GitOps:
version control
+ pull-based automation
+ continuous reconciliation
+ drift detection
CI가 계속 kubectl apply하면서 GitOps라고 부르는 경우
CI가 Git에서 manifest를 읽고 kubectl apply를 실행하는 구조는 Git-based deployment일 수는 있지만, GitOps의 pull/reconcile model과는 다르다.
CI:
Git read
kubectl apply
이 구조:
Git을 사용하지만 push-based CD에 가까움
GitOps에서는 cluster 내부 agent가 Git을 pull하고 상태를 맞춘다.
Secret을 Git에 그대로 넣는 경우
GitOps는 Git을 source of truth로 삼지만, secret을 평문으로 저장하라는 뜻이 아니다.
주의:
Kubernetes Secret의 base64는 암호화가 아님
Git history에 secret이 남으면 제거가 어려움
secret은 별도 암호화 또는 external secret manager로 관리해야 함
Auto-sync를 무조건 켜는 경우
Auto-sync는 편리하지만 production에서는 신중해야 한다.
위험:
잘못된 commit이 merge되면 즉시 production 반영
incident 중 수동 조치를 GitOps가 되돌릴 수 있음
대규모 변경이 자동으로 적용될 수 있음
Production에서는 approval, sync window, policy check, progressive delivery를 함께 고려해야 한다.
GitOps가 모든 배포 문제를 해결한다고 생각하는 경우
GitOps는 desired state 관리와 reconciliation에 강하다. 하지만 다음 문제는 별도로 설계해야 한다.
- database migration
- schema compatibility
- feature flag
- canary analysis
- SLO monitoring
- rollback safety
- secret rotation
- multi-cluster ownership
GitOps는 배포의 기반을 안정화하지만, application release engineering 전체를 자동으로 해결하지는 않는다.
실무 검증 포인트
GitOps를 운영할 때는 다음 질문을 확인해야 한다.
| 검증 포인트 | 확인 질문 |
|---|---|
| Source of truth | 운영 환경의 desired state가 Git에 있는가? |
| Declarative config | 배포 상태가 명령이 아니라 선언형으로 표현되는가? |
| Versioning | image tag, Helm chart, config가 versioned/immutable한가? |
| Pull model | cluster 내부 controller가 Git을 pull하는가? |
| Reconciliation | actual state와 desired state 차이를 감지하고 복구하는가? |
| Secret 관리 | secret이 Git에 평문으로 저장되지 않는가? |
| RBAC | GitOps controller 권한이 최소화되어 있는가? |
| Drift policy | manual change를 어떻게 감지하고 처리하는가? |
| Rollback | Git revert로 안전하게 되돌릴 수 있는가? |
| Migration | database/schema 변경이 rollback과 호환되는가? |
| Observability | sync status와 application health를 모두 확인하는가? |
| Promotion | dev→staging→prod 승격 workflow가 명확한가? |
| Bootstrap | cluster 재구축 시 GitOps controller를 다시 설치할 절차가 있는가? |
| Multi-cluster | cluster별 repo/path/권한 구조가 명확한가? |
Mental Model
GitOps는 다음 mental model로 이해하면 좋다.
Git:
운영 환경의 desired state를 저장하는 source of truth
CI:
source code를 test/build하고 image를 registry에 push
Registry:
versioned artifact 저장소
GitOps repository:
image tag, manifest, Helm values, Kustomize overlay 저장
GitOps controller:
Git desired state와 cluster actual state를 비교
Kubernetes:
실제 workload 실행
Observability:
sync 성공 이후 application health와 user impact 확인
더 짧게 정리하면 다음과 같다.
GitOps = Git에 선언하고, controller가 맞춘다.
정리
GitOps는 Git을 운영 환경의 desired state를 저장하는 source of truth로 삼고, cluster 내부의 controller가 Git 상태를 자동으로 pull하여 실제 시스템 상태와 지속적으로 reconcile하는 DevOps 운영 방식이다.
핵심은 다음과 같다.
- GitOps는 Git에 선언된 desired state와 실제 cluster 상태를 맞추는 운영 모델이다.
- DevOps와 GitOps는 경쟁 개념이 아니다. GitOps는 DevOps를 구현하는 구체적인 deployment/operation pattern이다.
- GitOps의 핵심 원칙은 declarative, versioned and immutable, pulled automatically, continuously reconciled이다.
- Push-based CD는 CI server가 cluster에 직접 변경을 push하고, pull-based GitOps는 cluster 내부 controller가 Git을 pull한다.
- GitOps는 drift detection과 rollback을 Git history 중심으로 단순화한다.
- GitOps repository 구조는 application repo 분리 방식과 monorepo 방식 중 조직의 권한 모델과 규모에 맞게 선택해야 한다.
- Kubernetes는 declarative desired state와 controller reconciliation model을 사용하므로 GitOps와 잘 맞는다.
- Argo CD와 Flux는 GitOps를 구현하는 대표적인 controller다.
- Secret은 Git에 평문으로 저장하면 안 되며, External Secrets, Sealed Secrets, SOPS, Vault 같은 전략이 필요하다.
- Auto-sync는 편리하지만 production에서는 approval, sync window, policy check, progressive delivery와 함께 설계해야 한다.
- GitOps controller 자체를 설치하는 bootstrap 절차도 필요하다.
GitOps의 본질은 다음 네 가지로 압축된다.
Declarative:
원하는 상태를 선언한다.
Versioned and Immutable:
원하는 상태의 변경 이력을 Git에 남긴다.
Pulled Automatically:
cluster의 controller가 Git 상태를 자동으로 가져온다.
Continuously Reconciled:
실제 상태와 원하는 상태가 달라지면 계속 맞춘다.
결국 GitOps는 단순한 배포 자동화 도구가 아니라, 운영 환경의 상태를 Git에 선언하고 실제 시스템이 그 선언과 계속 일치하도록 만드는 운영 모델이다.