"git push만 하면 자동으로 배포된다"는 말을 그대로 믿고 진행했다면 어디서 막혔을지, 그리고 실제로 어디서 막혔는지 정리.

1. GitOps의 핵심 아이디어

전통적인 배포는 "명령형(imperative)"이다 — 사람이나 CI가 kubectl apply, ssh + 스크립트 실행 같은 동작을 실행시킨다. 클러스터의 실제 상태와, "이게 맞는 상태다"라고 기록해둔 문서가 따로 놀기 쉽다.

GitOps는 반대다: **Git 저장소 안의 YAML이 "유일한 진실"**이고, 클러스터는 그 상태를 계속 "따라가려고" 하는 대상이다. 사람은 클러스터에 직접 명령하지 않고 git에 커밋만 한다. 클러스터 쪽의 별도 컨트롤러(여기선 ArgoCD)가 git을 주기적으로 보고, git과 클러스터 실제 상태가 다르면 알아서 맞춘다.

이번 작업에서 이 원칙을 지키려고 한 부분: DB 비밀번호/GEMINI_API_KEY 같은 시크릿은 git에 넣지 않고 kubectl로 클러스터에 직접 주입했다. 순수 GitOps 원칙에서 보면 예외지만, public 레포에 평문 시크릿을 커밋하는 것보다는 훨씬 안전한 실용적 타협.

2. ArgoCD Application이라는 오브젝트 — GitOps의 실제 연결고리

git 저장소에 YAML을 올려놓는 것만으로는 아무 일도 안 일어난다. "이 git 레포의 이 경로를, 이 클러스터의 이 네임스페이스에 동기화해라"는 매핑을 ArgoCD에게 알려주는 리소스가 필요한데, 그게 Application이다.

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: target-tracking-service
  namespace: argocd
spec:
  source:
    repoURL: https://github.com/sm010422/k3s-msa-infrastructure.git
    targetRevision: HEAD
    path: apps/target-tracking-service
  destination:
    server: https://kubernetes.default.svc
    namespace: c4i
  syncPolicy:
    automated: { prune: true, selfHeal: true }
    syncOptions: [CreateNamespace=true]

이번에 가장 중요했던 발견: 이 YAML 파일이 리포 안에 있다는 사실 자체는 아무 의미가 없다. Application도 결국 하나의 쿠버네티스 리소스라서, argocd 네임스페이스에 kubectl apply로 실제로 생성해야 ArgoCD 컨트롤러가 그 존재를 인식한다.

kubectl get application -n argocd   # → No resources found

사용자가 공유한 4단계 계획("이미지 push → 매니페스트 반영 → git push → ArgoCD가 감지해서 자동 배포")은 이 Application이 이미 등록되어 있다는 전제 위에서만 성립한다.

kubectl apply -f argocd/applications/target-tracking-service.yaml

3. syncPolicy가 의미하는 것

4. Sync Status가 Unknown이라는 것의 의미