GitOps와 조정 루프의 운영 감각
GitOps는 Git을 원하는 상태의 기준으로 두고, 클러스터 안의 에이전트가 실제 상태를 지속적으로 맞추는 운영 방법론입니다. ArgoCD와 FluxCD의 선택 기준, 조정 루프, 시크릿과 Helm 주의점, 프로덕션 운영 실패 포인트까지 함께 정리합니다.
Script Companion
오디오와 함께 스크립트 보기
- 01
GitOps의 출발점은 Git을 인프라와 애플리케이션 상태의 단일 진실 공급원으로 삼는다는 생각입니다. 기존 CI/CD가 빌드하고, 이미지를 푸시하고, 배포 스크립트를 실행하는 흐름에 가깝다면, GitOps는 Git에 원하는 상태를 선언하고 컨트롤러가 클러스터를 그 상태로 맞추는 흐름입니다. 2026년 기준으로 Kubernetes 클러스터 관리에서 사실상 표준으로 자리 잡았다는 점도 이 문서의 중요한 전제입니다. 감사 추적은 Git 히스토리에 남고, 롤백은 이전 커밋으로 되돌리는 방식으로 단순해집니다.
- 02
GitOps의 네 가지 원칙은 선언적 상태, 버전 관리, 자동 적용, 자가 치유입니다. 인프라와 앱 상태는 YAML 같은 선언적 코드로 정의하고, 그 파일은 Git에 저장되어 변경 이력을 남깁니다. Git에 머지된 변경은 에이전트가 자동으로 클러스터에 적용하고, 실제 상태가 Git과 달라지면 다시 원하는 상태로 복원합니다. 여기서 핵심은 배포 버튼보다 상태 수렴입니다. 누가 무엇을 배포했는지, 현재 클러스터가 왜 이런 모양인지, 문제가 생겼을 때 어디로 되돌릴지의 기준이 Git에 모입니다.
- 03
Push 모델과 Pull 모델의 차이는 보안 경계에서 크게 드러납니다. 기존 Push 방식에서는 Jenkins나 GitHub Actions 같은 CI 서버가 kubectl apply를 직접 실행하므로, CI 서버가 클러스터 접근 토큰이나 kubeconfig를 가져야 합니다. 이 서버가 침해되면 클러스터 전체가 위험해질 수 있습니다. GitOps Pull 모델은 반대로 클러스터 안의 ArgoCD나 Flux 에이전트가 Git을 감시하고 필요한 변경을 스스로 적용합니다. 외부 시스템이 클러스터 안으로 밀고 들어오는 대신, 클러스터가 Git을 읽어 원하는 상태를 당겨오는 구조입니다.
- 04
ArgoCD의 중심에는 Reconciliation Loop, 즉 조정 루프가 있습니다. Application Controller는 Git의 설계도와 Kubernetes 클러스터의 실제 상태를 계속 비교하는 감리사처럼 동작합니다. 기본적으로 3분마다, 정확히는 120초에 최대 60초의 랜덤 지터를 더해 Git과 클러스터를 비교합니다. 지터를 넣는 이유는 Application이 많을 때 모든 앱이 동시에 Git을 조회해 부하가 몰리는 상황을 피하기 위해서입니다. 이 루프가 있기 때문에 GitOps는 한 번 배포하고 끝나는 스크립트가 아니라 계속 상태를 맞추는 제어 시스템에 가깝습니다.
- 05
조정 루프의 흐름은 Observe, Diff, Act로 나눌 수 있습니다. 먼저 Repo Server가 Git에서 최신 매니페스트를 가져오고, Helm이면 helm template을 실행하며, Kustomize면 빌드 결과를 만듭니다. 다음으로 Application Controller가 Kubernetes API에서 현재 상태를 가져와 Git의 선언과 비교합니다. 차이가 있으면 Application은 OutOfSync로 표시되고, Auto-Sync가 설정되어 있으면 kubectl apply가 자동 실행됩니다. 내부적으로는 상태 확인을 담당하는 Status Processors 기본 20개와 실제 Sync를 담당하는 Operation Processors 기본 10개가 큐를 나누어 처리합니다.
- 06
Observe, Diff, Act라는 사고 모델은 GitOps 밖에서도 그대로 유용합니다. Terraform은 원격 state와 실제 클라우드 리소스를 보고 .tf 선언과 비교한 뒤 apply로 수렴시킵니다. Kubernetes Controller는 etcd Watch API로 변화를 감지하고 spec과 status의 차이를 계산해 하위 리소스를 만들거나 수정합니다. DB Replication 감지에서는 replica lag 지표와 primary LSN, replica LSN 차이를 보며 재동기화나 읽기 라우팅 제외를 판단합니다. 문서가 강조하는 전이 가치는 여기 있습니다. 낯선 시스템도 현재 상태 관찰, 차이 계산, 상태 수렴이라는 축으로 분해할 수 있습니다.
- 07
코드 리뷰에서도 Reconciliation 패턴을 보는 기준이 있습니다. 첫째는 멱등성입니다. 같은 상태로 수렴하는 작업을 여러 번 실행해도 부작용이 없어야 하며, DB 마이그레이션이 매 ArgoCD Sync마다 실행된다면 이 기준을 어깁니다. 둘째는 단방향 소유권입니다. Terraform이 Kubernetes Deployment를 관리하면서 ArgoCD도 같은 Deployment를 관리하면 두 시스템이 같은 리소스를 동시에 소유하게 됩니다. 셋째는 수렴 보장입니다. OutOfSync 루프처럼 목표 상태에 도달하지 못하는 영구적 에러는 Reconciler 설계 결함의 신호로 봐야 합니다.
- 08
도구 선택에서는 ArgoCD와 FluxCD의 성격 차이를 봐야 합니다. ArgoCD는 중앙 집중형이고 내장 Web UI가 있으며, 중앙 플랫폼팀이 여러 팀에 서비스를 제공하는 멀티테넌트 환경에 잘 맞습니다. FluxCD는 분산형, CLI 중심, 모듈러 구조에 가깝고, 각 팀이 자율적으로 클러스터를 운영하는 환경에 어울립니다. 정량 기준으로는 관리 클러스터 수가 3개 이상이고 중앙 컨트롤 플레인이 필요하면 ArgoCD 쪽이 자연스럽습니다. 반대로 클러스터별 독립 운영을 선호하고 터미널 중심 운영이면 FluxCD가 맞을 수 있습니다. 신규 프로젝트라면 문서는 ArgoCD를 더 안전한 선택으로 봅니다.
- 09
매니페스트 관리는 Kustomize base와 overlay 패턴으로 설명할 수 있습니다. 공통 기반은 base에 두고, dev, staging, prod 같은 환경별 차이는 overlay 패치로 관리합니다. ArgoCD에서는 Application의 path를 overlays/prod로 지정하면 base를 병합해 렌더링하고, FluxCD에서는 Kustomization CR이 비슷한 역할을 합니다. FluxCD 내부 구조도 이 관점과 잘 맞습니다. 단일 컨트롤러가 아니라 Source, Kustomize, Helm 같은 역할별 컨트롤러가 Kubernetes CRD 기반으로 느슨하게 결합됩니다. 필요한 기능만 선택해 쓰는 Kubernetes 네이티브 설계가 FluxCD의 특징입니다.
- 10
운영 규모가 커지면 App of Apps와 ApplicationSet이 중요해집니다. App of Apps는 하나의 부모 Application이 여러 자식 Application을 관리하는 구조로, 단일 클러스터에서 수십 개 애플리케이션을 일관되게 묶을 때 쓰입니다. ApplicationSet은 여러 클러스터와 여러 앱의 조합을 자동으로 만드는 리소스입니다. 앱 20개와 클러스터 5개처럼 조합이 커질 때 파일 하나로 100개 Application을 생성할 수 있습니다. Cluster Generator는 등록된 클러스터 목록을, Git Generator는 저장소 구조나 JSON 파일을, Matrix Generator는 두 Generator의 조합을 기준으로 Application을 만듭니다.
- 11
배포 순서를 제어할 때는 Sync Waves와 Hooks를 사용합니다. DB 마이그레이션, 앱 배포, 스모크 테스트처럼 순서가 중요한 작업을 한 번에 섞어 적용하면 실패 원인을 추적하기 어렵습니다. Sync Wave는 argocd.argoproj.io/sync-wave 어노테이션의 숫자를 기준으로 작은 숫자부터 적용하며, 기본값은 0이고 음수도 가능합니다. Sync Hooks는 PreSync, Sync, PostSync, SyncFail, PreDelete 같은 시점에 실행되는 리소스입니다. 특히 PreDelete Hooks는 ArgoCD v3.3에서 Application 삭제 전 클린업 Job을 먼저 실행하고 완료 후 리소스를 삭제할 수 있게 합니다.
- 12
ArgoCD와 Helm을 함께 쓸 때는 helm install이나 helm upgrade가 아니라 helm template을 실행한다는 점을 놓치면 안 됩니다. ArgoCD는 Chart를 렌더링해 YAML을 만든 뒤 kubectl apply로 적용합니다. 그래서 Helm의 pre-install과 pre-upgrade 훅이 ArgoCD의 Sync 흐름에서는 함께 실행될 수 있고, 훅이 멱등하지 않으면 DB 마이그레이션이나 초기화 Job이 매번 중복 실행될 수 있습니다. 또 Helm Release 히스토리는 남지 않고 이력은 Git에만 남습니다. randAlphaNum처럼 렌더링마다 값이 바뀌는 함수는 지속적인 OutOfSync를 만들 수 있으므로 고정값이나 외부 Secret 관리로 분리해야 합니다.
- 13
시크릿은 GitOps의 예외로 다뤄야 합니다. GitOps가 모든 상태를 Git에 둔다고 해도 비밀번호나 API Key를 평문으로 저장하면 저장소 접근자 모두에게 노출됩니다. 문서는 두 가지 패턴을 제시합니다. Sealed Secrets는 암호화된 시크릿을 Git에 저장하고, 클러스터 안의 컨트롤러가 이를 일반 Kubernetes Secret으로 바꿉니다. External Secrets Operator는 AWS Secrets Manager나 HashiCorp Vault 같은 외부 저장소의 값을 Kubernetes Secret으로 동기화합니다. AWS 환경에서는 이 패턴이 많이 쓰인다고 정리합니다. Git에 보이는 것은 선언이어야 하지, 비밀 값 자체가 아니어야 합니다.
- 14
프로덕션에서는 ArgoCD 자체도 운영 대상입니다. EKS에 직접 설치할 때 기본 non-HA 설치는 각 컴포넌트가 Pod 1개로 동작하므로, 한 Pod 재시작만으로 배포 파이프라인이 멈출 수 있습니다. HA 구성에서는 Application Controller가 StatefulSet으로 샤딩을 지원하고, Repo Server는 여러 복제본으로 Git 클론과 Helm 렌더링을 병렬 처리하며, Redis HA는 Sentinel로 자동 페일오버를 담당합니다. Redis가 죽으면 캐시 손실로 모든 앱 상태를 Git에서 다시 읽어야 하므로 API Server 부하가 커질 수 있습니다. 단일 Pod 구성은 프로덕션 기준으로 부적합하다는 점이 문서의 분명한 경계입니다.
- 15
운영 중 자주 보이는 실패는 증상과 원인을 나눠 보면 정리됩니다. Application이 Unknown이고 failed to load live state가 보이면 ArgoCD가 Kubernetes API 상태를 읽지 못하는 상황이며, ServiceAccount RBAC 권한이나 클러스터 연결을 확인해야 합니다. Sync 후 몇 분 뒤 다시 OutOfSync가 반복되면 Kubernetes가 자동 추가한 필드나 다른 컨트롤러의 수정이 원인일 수 있고, 실제 diff와 Application 조건을 함께 봐야 합니다. repository not accessible나 authentication required는 Private Git 저장소의 SSH Key나 HTTPS 토큰 문제로 이어질 수 있습니다. Repo Server가 OOMKilled로 재시작되면 큰 Helm Chart 렌더링과 낮은 메모리 limit, 동시 Sync 요청을 함께 의심해야 합니다.
- 16
2025년 이후 변화도 선택 기준에 들어갑니다. AWS EKS Capability for ArgoCD는 ArgoCD 소프트웨어를 AWS 컨트롤 플레인에서 실행해 워커 노드를 소비하지 않고, 스케일링과 업그레이드를 AWS가 처리하는 관리형 방식입니다. Git 저장소 접근을 AWS 계정 레벨에서 처리하고, AWS Secrets Manager, ECR, CodeCommit, IAM 역할과 통합됩니다. ArgoCD v3.0은 2025년 4월 출시되었고, v2.14는 2025년 11월 4일 공식 EOL이 되었습니다. v3.x에서는 AppProject 단위 RBAC, Source Hydrator, OCI Registry 네이티브 지원, PreDelete Hooks 같은 변화가 운영 판단에 영향을 줍니다. 정리하면 GitOps는 Git 이력, Pull 모델, 조정 루프, 소유권 경계를 함께 운영하는 방식입니다.
같은 레이어