12.2 Kustomize
Helm의 템플릿 방식에는 대가가 있다. {{ .Values.replicaCount }}가 들어간 파일은 렌더링 전에는 유효한 YAML이 아니어서, 편집기의 스키마 검사도 kubectl apply도 그 파일을 직접 다루지 못한다. Kustomize는 같은 문제를 반대 방향에서 푼다. 완성된 매니페스트를 그대로 두고, 환경별 차이를 별도의 YAML로 선언해 겹쳐 적용하는 방식이다. 모든 파일이 처음부터 끝까지 유효한 YAML로 남는다는 것이 이 도구의 출발점이자 정체성이다.
kustomization.yaml과 base/overlays
Kustomize의 단위는 kustomization.yaml이 있는 디렉토리다. 이 파일이 어떤 리소스를 포함하고 어떤 변형을 적용할지 선언한다. 관례적인 구조는 공통 매니페스트를 담은 base와 환경별 차이를 담은 overlays의 분리다.
app/
├── base/
│ ├── kustomization.yaml
│ ├── deployment.yaml
│ └── service.yaml
└── overlays/
├── dev/
│ └── kustomization.yaml
└── prod/
├── kustomization.yaml
└── replica-patch.yamlbase는 리소스 목록만 선언한다.
# base/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- deployment.yaml
- service.yamloverlay는 base를 리소스로 참조하고 그 위에 변형을 선언한다.
# overlays/prod/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ../../base
namePrefix: prod-
patches:
- path: replica-patch.yamlKustomize는 kubectl 1.14부터 내장이라 별도 설치가 필요 없다. kubectl kustomize overlays/prod는 병합 결과를 출력만 하고, kubectl apply -k overlays/prod는 그 결과를 클러스터에 적용한다. 적용 전에 출력을 확인하는 습관은 Helm의 helm template과 같은 자리에 있다.
패치 두 방식
부분 수정은 patches로 선언하고, 형식이 둘이다. strategic merge patch는 대상 리소스와 같은 kind, 같은 name을 가진 부분 YAML을 작성해 겹치는 방식이다. 원본과 같은 모양이라 읽기 쉽다.
# overlays/prod/replica-patch.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: web
spec:
replicas: 5JSON6902 패치는 경로를 지정해 add, replace, remove 연산을 적용한다. 컨테이너 배열의 특정 요소처럼 merge로 표현하기 애매한 지점을 정확히 지목할 때 쓴다.
# overlays/prod/kustomization.yaml (patches 항목)
patches:
- target:
kind: Deployment
name: web
patch: |-
- op: replace
path: /spec/template/spec/containers/0/resources/limits/memory
value: 1Gi일상적인 수정은 strategic merge로 충분하고, 배열 인덱스나 필드 삭제가 필요할 때 JSON6902를 쓰는 흐름이 자연스럽다.
공통 변형
패치 없이 kustomization.yaml의 필드만으로 처리되는 변형이 있다. 리소스 이름 앞뒤에 문자열을 붙이는 namePrefix와 nameSuffix, 모든 리소스에 label을 추가하는 commonLabels, 이미지 이름과 태그를 교체하는 images, replica 수를 지정하는 replicas가 대표적이다.
namePrefix: prod-
commonLabels:
app.kubernetes.io/part-of: shop
images:
- name: nginx
newTag: 1.27.1images 변형은 CI에서 빌드한 태그를 매니페스트 수정 없이 반영하는 데 자주 쓰인다. namePrefix는 이름만 바꾸는 것이 아니라 그 이름을 참조하는 다른 리소스(Service를 가리키는 Ingress 등)까지 함께 갱신한다.
configMapGenerator와 secretGenerator는 파일이나 리터럴에서 ConfigMap과 Secret을 생성하는 변형이다. 생성된 이름 뒤에 내용의 해시가 붙고 이를 참조하는 워크로드의 참조도 함께 갱신되므로, 설정 내용이 바뀌면 이름이 바뀌어 Deployment의 롤링 재기동이 자연스럽게 유발된다. ConfigMap을 제자리에서 수정했을 때 Pod가 알아채지 못하는 문제(Part VII. 구성과 시크릿)에 대한 Kustomize식 답이다.
.spec.selector와 Service의 selector에도 같은 항목을 추가한다. Deployment의 selector는 생성 후 변경 불가라서, 이미 운영 중인 리소스에 commonLabels를 나중에 추가하면 apply가 거부된다. 최신 Kustomize의 labels 필드는 selector 포함 여부를 선택할 수 있으므로, label만 추가하려면 labels 필드에 includeSelectors: false를 지정한다.Helm과의 선택 기준
두 도구는 겹치는 자리보다 다른 자리가 크다. Helm의 강점은 패키징과 배포판이다. 남이 만든 소프트웨어를 버전 붙은 아티팩트로 받아 설치하고, 릴리스 이력과 rollback을 도구가 관리한다. 서드파티 소프트웨어 설치는 사실상 Helm 차트가 표준 유통 형식이다. Kustomize의 강점은 자기 매니페스트의 환경 변형이다. 템플릿 문법 없이 dev와 prod의 차이를 YAML 그대로 관리하고, kubectl만으로 동작한다.
그래서 실무에서는 양자택일보다 조합이 흔하다. 서드파티는 Helm 차트로 설치하고 자체 애플리케이션은 Kustomize로 변형하는 분담이 하나, helm template의 출력을 base로 삼아 Kustomize 패치를 적용하는 연결이 또 하나다. Kustomize의 helmCharts 필드는 이 연결을 kustomization.yaml 안에서 선언하게 해 주고, 12.5에서 다루는 Argo CD와 Flux는 두 형식 모두를 렌더러로 지원한다.
정리
Kustomize는 템플릿 없이 base 위에 overlay를 겹쳐 환경별 매니페스트를 만들고, kubectl에 내장되어 -k 플래그로 바로 적용된다. 패키징과 유통이 필요하면 Helm, 자기 매니페스트의 환경 분기가 필요하면 Kustomize라는 분담이 일반적이고, 두 도구를 한 파이프라인에서 조합하는 구성도 흔하다.