코드, 매니페스트, Helm — 배포 구조 정리
자꾸 헷갈려서 정리한다. 코드, 매니페스트, Helm 차트가 각각 뭐고 배포가 어떻게 돌아가는지.
세 가지 개념
1
2
3
코드 = 앱 로직 (Python, TypeScript)
매니페스트 = 운영 설정 (몇 개 띄울지, 메모리, 환경변수, 이미지 태그)
Helm 차트 = 매니페스트를 템플릿으로 관리하는 도구
코드가 “뭘 하는지”라면, 매니페스트는 “어떻게 돌릴지”다.
예를 들어:
- “postgres 이미지를 pgvector로 바꿔라” → 매니페스트 변경
- “환경변수 추가해라” → 매니페스트 변경
- “replicas를 2개로 늘려라” → 매니페스트 변경
- “API 로직 수정” → 코드 변경
Helm은 매니페스트를 values.yaml 하나로 관리하게 해주는 템플릿 엔진이다. values-prod.yaml에서 값만 바꾸면 매니페스트가 자동 생성된다.
배포 구조
1
2
3
4
5
git push (apps/ 변경)
→ GitHub Actions가 변경 감지 (detect-changes)
→ SSH → rsync → docker buildx build → docker save | k3s ctr images import
→ helm/values-prod.yaml의 이미지 태그를 커밋 SHA로 업데이트 → git push
→ ArgoCD에 sync 트리거 → Helm 렌더링 → Pod 교체 (배포 완성)
GitHub Actions = 빌드 + values 업데이트. ArgoCD = 실제 Pod 교체. ArgoCD가 없으면 이미지만 서버에 있고 Pod는 안 바뀐다.
GitHub Actions — 커밋마다 자동 빌드+배포. 380회 실행.
ArgoCD sync: 트리거 + polling
배포를 빠르게 반영하는 표준 방법은 트리거 + polling fallback을 같이 쓰는 것이다:
- 트리거: GitHub Actions 마지막에 SSH로
kubectl patch application을 실행해서 ArgoCD sync를 즉시 실행. 배포 지연 0초. - polling: 1분 주기로 git 변경 감지. 트리거가 실패하거나 수동 git push 시 보험 역할.
트리거만 쓰면 SSH 장애 시 배포가 아예 안 되고, polling만 쓰면 배포가 느리다. 둘 다 쓰는 게 표준이다.
ArgoCD 대시보드 — Service → Pod 매핑, Sync 상태, Health 한눈에
ArgoCD는 Helm 차트를 직접 렌더링한다
ArgoCD source를 helm/ 디렉토리로 등록해서, values 변경 시 Helm template을 렌더링하고 k8s에 apply한다. 매니페스트를 kubectl get -o yaml로 export해서 관리하는 방식은 이중 관리가 되어 쓰지 않는다.
이미지 태그: 커밋 SHA
이미지 태그를 고정 버전 대신 커밋 SHA(git rev-parse --short HEAD)로 자동 생성한다. 매번 다른 태그이니 덮어쓰기가 없고, 롤백도 이전 SHA로 되돌리면 끝. 같은 태그 덮어쓰기로 인한 docker 문제도 이걸로 해결했다.
삽질 기록
kubectl get -o yaml로 export한 매니페스트를 그대로 Git에 넣으면 안 된다:
uid,resourceVersion,creationTimestamp→ UID 충돌deployment.kubernetes.io/revision→ 영구 OutOfSynckubectl.kubernetes.io/last-applied-configuration→ diff 노이즈
이런 클러스터 생성 메타데이터를 전부 제거하고, ArgoCD에 ignoreDifferences를 설정해야 정상 작동한다. 지금은 Helm 차트 직접 렌더링으로 전환해서 이 문제가 발생하지 않는다.