Kustomize 정리 - base와 overlay로 환경별 매니페스트 관리하기
kubectl 1.34 기준으로 정리합니다(내장 Kustomize v5.7.1). dev/prod처럼 환경마다 살짝씩 다른 매니페스트를 관리할 때 YAML을 통째로 복붙하는 대신 쓰는 Kustomize를, base+overlay 예제를 직접 빌드해본 결과와 함께 정리합니다.

왜 필요한가
같은 애플리케이션이라도 dev는 레플리카 1개면 충분하고, prod는 3개는 떠 있어야 합니다. 이미지 태그도 dev는 최신, prod는 고정된 버전을 씁니다. 이걸 deployment-dev.yaml, deployment-prod.yaml처럼 파일을 통째로 복사해서 관리하면, 나중에 공통 부분(포트, 볼륨 마운트 등)을 고칠 때 두 파일을 다 고쳐야 하고 언젠가 하나를 빼먹게 됩니다.
Kustomize는 이 문제를 "공통 부분(base) + 환경별 차이(overlay)"로 나눠서 풉니다. base는 한 번만 작성하고, overlay는 "레플리카 수를 3으로 바꿔라", "이미지 태그를 1.25.3으로 바꿔라" 같은 패치(patch, 원본을 부분적으로 수정하는 명세)만 적습니다. 별도 템플릿 언어가 없어서 순수 YAML만 알면 되고, kubectl에 내장돼 있어 추가 설치도 필요 없습니다.
핵심 개념
| 용어 | 의미 |
|---|---|
| base | 모든 환경이 공유하는 원본 매니페스트 모음 |
| overlay | base를 참조해 환경별 차이만 얹는 디렉터리 (dev, prod 등) |
| kustomization.yaml | "이 디렉터리에 어떤 리소스가 있고 어떻게 조합할지"를 정의하는 설정 파일. 디렉터리마다 하나씩 |
| patch | base의 특정 필드를 추가·수정·삭제하는 명세. JSON Patch 문법을 많이 씀 |
실습 - 디렉터리 구조
nginx 기반 webapp을 예로, base 하나에 dev·prod overlay 두 개를 만들었습니다.
base/deployment.yaml
base/kustomization.yaml
base/service.yaml
overlays/dev/kustomization.yaml
overlays/prod/kustomization.yaml
여기서 봐야 할 부분: overlay 디렉터리에는 deployment.yaml 같은 리소스 파일이 없습니다. overlay는 base를 참조만 하고, 차이만 kustomization.yaml 안에 패치로 적습니다.
base 작성
# base/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: webapp
spec:
replicas: 1
selector:
matchLabels:
app: webapp
template:
metadata:
labels:
app: webapp
spec:
containers:
- name: webapp
image: nginx:1.25
ports:
- containerPort: 80
resources:
requests:
cpu: 100m
memory: 128Mi
# base/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- deployment.yaml
- service.yaml
labels:
- pairs:
app: webapp
includeSelectors: true
여기서 봐야 할 부분: resources에 이 디렉터리에 포함할 파일 목록을 적습니다. labels는 나열된 리소스 전체에 app: webapp 라벨을 자동으로 붙여주는 기능인데, 예전 예제에는 같은 역할을 하는 commonLabels가 자주 등장합니다. 실제로 commonLabels로 빌드해보면 "deprecated. Please use 'labels' instead" 경고가 뜹니다 - 지금 새로 쓴다면 labels 필드를 쓰는 게 맞습니다.
overlay 작성 - dev / prod
# overlays/dev/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ../../base
namePrefix: dev-
configMapGenerator:
- name: webapp-config
literals:
- LOG_LEVEL=debug
patches:
- target:
kind: Deployment
name: webapp
patch: |-
- op: add
path: /spec/template/spec/containers/0/envFrom
value:
- configMapRef:
name: webapp-config
# overlays/prod/kustomization.yaml (dev와 다른 부분만)
namePrefix: prod-
replicas:
- name: webapp
count: 3
images:
- name: nginx
newTag: "1.25.3"
configMapGenerator:
- name: webapp-config
literals:
- LOG_LEVEL=info
# + resources.requests를 500m/512Mi로 올리는 patch
여기서 봐야 할 부분: configMapGenerator는 ConfigMap을 만들어주는데, patch에서는 그냥 webapp-config라는 원래 이름으로 참조하면 됩니다. Kustomize가 빌드 시점에 해시가 붙은 실제 이름으로 자동 치환해줍니다 (바로 다음 절 출력에서 확인됩니다).
빌드해서 확인하기
클러스터에 적용하기 전에 kubectl kustomize로 최종 결과물을 미리 볼 수 있습니다. 실제로 위 파일들로 빌드한 결과입니다.
$ kubectl kustomize overlays/dev
apiVersion: v1
data:
LOG_LEVEL: debug
kind: ConfigMap
metadata:
name: dev-webapp-config-47668c6k28
---
apiVersion: v1
kind: Service
metadata:
labels:
app: webapp
name: dev-webapp
spec:
ports:
- port: 80
targetPort: 80
selector:
app: webapp
---
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: webapp
name: dev-webapp
spec:
replicas: 1
template:
spec:
containers:
- envFrom:
- configMapRef:
name: dev-webapp-config-47668c6k28
image: nginx:1.25
name: webapp
# ...
여기서 봐야 할 부분: ConfigMap 이름이 dev-webapp-config-47668c6k28로, 우리가 적은 webapp-config에 dev- 접두사와 내용 기반 해시가 자동으로 붙었습니다. 그리고 Deployment의 envFrom.configMapRef.name도 똑같이 바뀐 이름을 정확히 가리키고 있습니다 - 이게 Kustomize가 자동으로 해주는 "이름 참조 고정" 기능입니다. 내용이 바뀌면 해시도 바뀌므로, ConfigMap을 갱신하면 Deployment가 자동으로 롤링 업데이트됩니다.
prod overlay는 replicas: 3, image: nginx:1.25.3, LOG_LEVEL: info로 값만 다르게 나옵니다 - base 파일은 그대로 두고 overlay만 바꿔서 두 가지 결과를 만든 것입니다.
실제로 적용하기
# 적용 전에 실제 클러스터와 차이를 미리 본다
kubectl diff -k overlays/prod
# 적용
kubectl apply -k overlays/prod
-k 옵션은 "이 경로의 kustomization.yaml을 빌드해서 적용하라"는 뜻입니다. kubectl diff -k로 먼저 실제 클러스터 상태와 차이를 확인하고 적용하는 습관을 들이면, 의도치 않은 변경을 배포 전에 잡을 수 있습니다. (이 글의 diff·apply 출력은 실제 클러스터가 없어 싣지 않았습니다 - 위 kubectl kustomize 결과와 동일한 리소스가 만들어집니다.)
요약
Kustomize는 base(공통) + overlay(차이)로 환경별 매니페스트를 관리하게 해주고, kubectl에 내장돼 있어 별도 설치가 필요 없습니다. configMapGenerator로 만든 리소스는 이름 참조가 자동으로 고정되고, 예전 예제의 commonLabels는 labels로 바뀌었다는 점만 알아두면 바로 실무에 적용할 수 있습니다.
참고사항
'DevOps > Kubernetes' 카테고리의 다른 글
| Helm 차트 기초 정리 - Kustomize와 무엇이 다른가 (0) | 2026.10.02 |
|---|---|
| kubectl 생산성 도구 모음 - krew로 설치하는 실전 플러그인 5가지 (0) | 2026.09.30 |
| Dynamic Resource Allocation(DRA) 정리 - device plugin을 대체하는 쿠버네티스 하드웨어 할당 표준 (0) | 2026.09.30 |
| Gateway API Inference Extension 정리 - LLM 추론 트래픽을 위한 쿠버네티스 네이티브 라우팅 (0) | 2026.09.28 |
| Cilium Service Mesh 정리 - eBPF 기반 사이드카 없는 쿠버네티스 네트워킹 (0) | 2026.09.22 |
