yaml 복붙 관리의 드리프트 문제를 Kustomize overlay로 구조화하기
로컬·개발·에어갭 3환경 매니페스트를 복사해서 관리하다 겪은 드리프트 문제부터, Kustomize base/overlay 구조로 옮기는 절차, ArgoCD Application 연동, 드리프트 재발 방지 검증까지.
목표
이 로드맵은 환경을 로컬·개발·에어갭 3개로 나눠 운영하는데, 지금까지는 환경별로 매니페스트 디렉토리를 통째로 복사해서 관리하고 있었다 - k8s/local/, k8s/dev/, k8s/airgap/ 세 폴더에 거의 동일한 yaml이 중복돼 있는 구조다. 이 시리즈는 그 복붙 관리가 실제로 어떤 문제(드리프트)를 만드는지 겪어보고, Kustomize의 base/overlay 구조로 옮겨 그 문제를 구조적으로 없애는 절차를 다룬다.
개념: 설정 드리프트(Config Drift)란 무엇인가
드리프트는 "같아야 할 설정이 시간이 지나며 조금씩 달라지는 것"을 말한다. 환경별로 yaml을 복사해서 관리하면, 공통으로 고쳐야 할 부분(예: 리소스 요청량, 헬스체크 경로)을 수정할 때마다 3개 파일을 전부 손으로 고쳐야 한다. 사람이 하는 일이라 언젠가 한 곳을 빠뜨리게 되고, 그 순간부터 "왜 개발 환경에서는 되는데 에어갭에서는 안 되지?"라는 질문이 생긴다 - 코드가 문제가 아니라 환경 설정이 몰래 갈라져 있어서 생기는 장애다.
Kustomize는 이 문제를 "공통 부분(base)과 환경별 차이(overlay)를 분리"하는 방식으로 푼다. base에는 모든 환경이 공유하는 원본 매니페스트만 두고, 각 환경은 base를 그대로 참조하면서 자신에게 필요한 차이만 patch로 얹는다. 복붙이 아니라 참조이므로, base를 고치면 모든 환경에 자동으로 반영된다 - 드리프트가 애초에 발생할 수 없는 구조가 된다.
| 방식 | 공통 설정 변경 시 | 환경별 차이 |
|---|---|---|
| yaml 복붙 (기존) | N개 파일을 전부 손으로 수정 - 누락 위험 | 파일 전체가 환경마다 별도로 존재 |
| Kustomize overlay | base 1곳만 수정 - 모든 환경에 자동 반영 | patch로 차이만 명시적으로 선언 |
실제 구축 절차
1. 기존 복붙 구조 확인 - 어디가 실제로 갈라져 있는지 먼저 찾는다
Kustomize로 옮기기 전에, 지금 세 환경의 yaml이 실제로 어디서 다른지부터 diff로 확인한다. 이 작업 자체가 "우리가 인지하지 못한 드리프트가 이미 있었는지"를 드러낸다.
diff -r k8s/local/ k8s/dev/
diff -r k8s/dev/ k8s/airgap/
여기서 나오는 차이는 크게 두 종류로 갈린다 - 의도한 차이(에어갭 환경만 이미지 레지스트리가 harbor.local인 것 등)와 의도하지 않은 차이(누군가 dev에서만 리소스 limit을 고치고 다른 환경엔 반영 안 한 것). 후자를 발견하는 순간이 바로 "복붙 관리의 대가"를 실감하는 지점이다.
2. base 추출 - 공통 매니페스트만 남긴다
세 환경에서 공통인 부분만 뽑아 base/로 옮긴다. 여기엔 환경별로 달라지는 값(이미지 레지스트리, replica 수, context-path 등)을 넣지 않는다 - 넣는 순간 base가 다시 특정 환경에 종속된다.
k8s/
├── base/
│ ├── kustomization.yaml
│ ├── deployment.yaml
│ ├── service.yaml
│ └── configmap.yaml
└── overlays/
├── local/
├── dev/
└── airgap/
# k8s/base/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- deployment.yaml
- service.yaml
- configmap.yaml
3. overlay 작성 - 환경별 차이만 patch로 선언
각 overlay는 base를 참조(resources: [../../base])하면서, 자신에게 필요한 차이만 patch로 얹는다.
# k8s/overlays/airgap/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ../../base
images:
- name: api-server
newName: harbor.local/proxy-cache/api-server # 에어갭만 내부 미러 레지스트리 사용
patches:
- target:
kind: Deployment
name: api-server
patch: |-
- op: replace
path: /spec/replicas
value: 5
- path: configmap-patch.yaml
# k8s/overlays/airgap/configmap-patch.yaml - context-path 등 에어갭 전용 값만 override
apiVersion: v1
kind: ConfigMap
metadata:
name: api-server-config
data:
EXTERNAL_API_HOST: "localhost:8081" # 에어갭 환경은 내부 API를 path prefix로 우회
# 렌더링 결과 미리보기 - 실제 적용 전에 최종 yaml이 의도대로 나오는지 확인
kustomize build k8s/overlays/local/
kustomize build k8s/overlays/dev/
kustomize build k8s/overlays/airgap/
kustomize build는 base와 patch를 합쳐 최종 yaml을 출력만 할 뿐 클러스터에 아무것도 적용하지 않는다 - 세 환경의 렌더링 결과를 나란히 비교해서 의도한 차이만 남아있는지, 실수로 base 내용이 깨지지 않았는지 눈으로 검증할 수 있다.
4. ArgoCD Application에 Kustomize 연동
시리즈 2에서 만든 ArgoCD GitOps 배포에 Kustomize를 편입한다. Application의 source.path가 overlay 디렉토리를 가리키게만 바꾸면, ArgoCD가 자동으로 kustomize build를 실행해서 그 결과를 배포한다 - 별도 빌드 스크립트가 필요 없다.
# argocd-application-airgap.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: api-server-airgap
spec:
source:
repoURL: https://git.internal/infra-manifests.git
path: k8s/overlays/airgap
targetRevision: main
destination:
server: https://kubernetes.default.svc
namespace: default
syncPolicy:
automated:
prune: true
selfHeal: true # 클러스터에서 누가 kubectl로 직접 고쳐도 Git 상태로 되돌림
selfHeal: true가 이 구조의 마지막 조각이다 - Kustomize로 드리프트를 구조적으로 없앴어도, 누군가 클러스터에 kubectl edit으로 직접 손을 대면 Git과 실제 상태가 다시 갈라질 수 있다. ArgoCD의 self-heal은 그 수동 변경을 감지해 Git에 선언된 상태로 자동으로 되돌린다 - "설정 소스는 Git 하나뿐"이라는 원칙을 배포 이후에도 강제하는 셈이다.
5. 드리프트 재발 방지 검증
# 의도적으로 클러스터에 직접 변경을 가한 뒤
kubectl scale deployment api-server -n airgap --replicas=99
# ArgoCD가 감지해 Git 선언 값으로 되돌리는지 확인
kubectl argo rollouts get rollout api-server -n airgap --watch # 또는
argocd app get api-server-airgap --refresh
검증 방법
- 3환경의
kustomize build렌더링 결과를 diff로 비교해, 의도한 차이만 남아있는지 확인 - base를 수정했을 때 3환경 모두에 자동으로 반영되는지 확인 (환경별로 따로 고치지 않아도 됨)
- 클러스터에 수동으로 가한 변경이 ArgoCD self-heal로 Git 선언 상태로 자동 복구되는지 확인
- 1번 절차에서 발견한 "의도하지 않은 차이"가 overlay 구조로 옮긴 뒤 문서화된 patch로 명시됐는지 확인
체크리스트
- 기존 3환경 yaml을 diff로 비교해 의도한 차이/의도하지 않은 차이 구분
- 공통 매니페스트를 base로 추출
- 환경별 차이를 overlay patch로 분리 (이미지 레지스트리, replica 수, 설정값 등)
-
kustomize build로 3환경 렌더링 결과 사전 검증 - ArgoCD Application의 source.path를 overlay로 전환
- selfHeal 활성화 후 수동 변경이 자동 복구되는지 검증