Kustomize Base/Overlay 패턴
TL;DR
- Kustomize Base/Overlay 패턴의 핵심 개념과 용어를 한눈에 정리한다.
- Kustomize Base/Overlay 패턴이(가) 등장한 배경과 필요성을 요약한다.
- Kustomize Base/Overlay 패턴의 특징과 적용 포인트를 빠르게 확인한다.
1. 개념
Kustomize Base/Overlay 패턴은(는) 핵심 용어와 정의를 정리한 주제로, 개발/운영 맥락에서 무엇을 의미하는지 설명한다.
2. 배경
기존 방식의 한계나 현업의 요구사항을 해결하기 위해 이 개념이 등장했다는 흐름을 이해하는 데 목적이 있다.
3. 이유
도입 이유는 보통 유지보수성, 성능, 안정성, 보안, 협업 효율 같은 실무 문제를 해결하기 위함이다.
4. 특징
- 핵심 정의와 범위를 명확히 한다.
- 실무 적용 시 선택 기준과 비교 포인트를 제공한다.
- 예시 중심으로 빠른 이해를 돕는다.
5. 상세 내용
작성일: 2026-02-24 카테고리: Infra / Kubernetes / Kustomize 포함 내용: Kustomize, Base/Overlay, kubectl apply -k, Strategic Merge Patch, JSON 6902, Helm 비교, GitOps, Component, SIG-CLI, kustomization.yaml, 환경별 설정
1. 핵심 개념
Kustomize란?
Kustomize = Kubernetes 공식 설정 커스터마이징 도구
┌─────────────────────────────────────────────────────────┐
│ │
│ 탄생 배경: │
│ ├── Google 내부 경험에서 비롯 (2018년) │
│ ├── 저자: Jeff Regan & Phillip Wittrock │
│ ├── Kubernetes SIG-CLI가 공식 관리 │
│ └── kubectl v1.14 (2019)부터 네이티브 내장 │
│ │
│ 핵심 철학: │
│ ├── 템플릿 없이 순수 YAML 기반으로 동작 │
│ ├── 원본 파일을 절대 수정하지 않음 │
│ └── 빌드 타임에 패치를 합성(overlay)하여 출력 │
│ │
│ 비유: │
│ "make처럼 선언적이고, │
│ sed처럼 텍스트를 편집한다" │
│ │
└─────────────────────────────────────────────────────────┘
Base/Overlay 패턴이란?
Base/Overlay = 공통 + 차이점 분리 전략
┌─────────────────────────────────────────────────────────┐
│ │
│ Base │
│ ├── 환경에 무관한 공통 매니페스트 │
│ └── 단일 진실의 원천 (Single Source of Truth) │
│ │
│ Overlay │
│ ├── Base를 참조하면서 환경별 차이점만 패치로 선언 │
│ └── Base를 절대 복사하지 않음 │
│ │
│ base/ │
│ │ │
│ ┌───────┼───────┐ │
│ ▼ ▼ ▼ │
│ overlays/ overlays/ overlays/ │
│ dev/ staging/ prod/ │
│ │
└─────────────────────────────────────────────────────────┘
2. 이 패턴이 등장한 배경
기존 방식의 문제점
기존에는 두 가지 나쁜 선택지밖에 없었다
┌─────────────────────────────────────────────────────────┐
│ Option A: 복사 후 수정 (Copy & Edit) │
│ │
│ deployment.yaml │
│ │ │
│ ├── deployment-dev.yaml (복사) │
│ ├── deployment-staging.yaml (복사) │
│ └── deployment-prod.yaml (복사) │
│ │
│ 문제점: │
│ ├── 공통 변경 시 모든 복사본을 수동으로 반영 필요 │
│ ├── 규모 커지면 Configuration Drift 불가피 │
│ └── "어느 게 진짜야?" 혼란 │
│ │
└─────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────┐
│ Option B: 템플릿 파라미터화 (Helm 방식) │
│ │
│ deployment.yaml (Go 템플릿) │
│ ┌─────────────────────────────────────────────────┐ │
│ │ replicas: │ │
│ │ image: : │ │
│ │ │ │
│ │ │ │
│ │ ... 수십 줄의 중첩 조건문 ... │ │
│ │ │ │
│ └─────────────────────────────────────────────────┘ │
│ │
│ 문제점: │
│ ├── 새로운 언어/도구 학습 필요 (Go 템플릿) │
│ ├── 파라미터 세트가 점점 복잡해짐 │
│ └── 설정 데이터와 프로그래밍 로직 경계 모호 │
│ │
└─────────────────────────────────────────────────────────┘
Kustomize의 해결책 - 패치 기반 커스터마이징
┌─────────────────────────────────────────────────────────┐
│ │
│ 핵심 관찰: │
│ "환경별 차이는 보통 전체 매니페스트의 일부분일 뿐" │
│ │
│ 예) prod vs dev 실제 차이: │
│ ├── replicas: 1 → 3 │
│ ├── image tag: latest → v2.3.1 │
│ └── resources.limits.memory: 256Mi → 1Gi │
│ (나머지 95%는 동일) │
│ │
│ Kustomize 접근법: │
│ ├── Base: 공통 95%를 원본 YAML로 그대로 유지 │
│ ├── Patch: 차이점 5%만 별도 파일로 선언 │
│ └── Build: 빌드 타임에 Base + Patch 합성 │
│ │
│ 원본 파일 = 절대 수정하지 않음 │
│ │
└─────────────────────────────────────────────────────────┘
3. 디렉토리 구조와 동작 방식
표준 디렉토리 구조
my-app/
├── base/
│ ├── kustomization.yaml ← 리소스 목록 선언
│ ├── deployment.yaml
│ ├── service.yaml
│ └── configmap.yaml
└── overlays/
├── dev/
│ ├── kustomization.yaml
│ └── replica-patch.yaml
├── staging/
│ └── kustomization.yaml
└── prod/
├── kustomization.yaml
└── hpa.yaml
Base kustomization.yaml 예시
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- deployment.yaml
- service.yaml
- configmap.yaml
commonLabels:
app: my-app
Overlay kustomization.yaml 예시 (prod)
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ../../base # Base를 참조
namePrefix: prod- # 모든 리소스 이름에 접두사 추가
images:
- name: my-app
newTag: v2.3.1 # 이미지 태그 고정
patches:
- path: replica-patch.yaml
패치 방식 두 가지
┌─────────────────────────────────────────────────────────┐
│ 방식 1: Strategic Merge Patch (가장 일반적) │
│ │
│ Kubernetes 객체 구조를 그대로 활용 │
│ ─── 덮어쓸 필드만 명시하면 나머지는 Base 유지 │
│ │
└─────────────────────────────────────────────────────────┘
# replica-patch.yaml (Strategic Merge Patch)
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
spec:
replicas: 3 # 이 필드만 덮어씀
template:
spec:
containers:
- name: app
resources:
limits:
memory: "1Gi"
┌─────────────────────────────────────────────────────────┐
│ 방식 2: JSON 6902 Patch (정밀한 RFC6902 연산) │
│ │
│ add / remove / replace / move / copy / test 연산 │
│ ─── 배열 인덱스 지정, 특정 경로 제거 등 정밀 제어 │
│ │
└─────────────────────────────────────────────────────────┘
# kustomization.yaml 내 JSON 6902 패치 예시
patches:
- target:
kind: Deployment
name: my-app
patch: |-
- op: replace
path: /spec/replicas
value: 3
- op: add
path: /spec/template/spec/containers/0/env/-
value:
name: LOG_LEVEL
value: "warn"
빌드 및 적용 명령어
# 렌더링 결과만 확인 (실제 적용 안 함)
kustomize build overlays/prod
# kubectl 내장 명령으로 바로 적용
kubectl apply -k overlays/prod
# 렌더링 후 파이프로 넘기기
kustomize build overlays/prod | kubectl apply -f -
4. Helm과의 비교
| 항목 | Kustomize | Helm |
|---|---|---|
| 핵심 추상화 | Overlay / Patch | 패키지 매니저 + 템플릿 |
| 설정 언어 | 순수 YAML + 패치 | Go 템플릿 + values.yaml |
| kubectl 통합 | 네이티브 내장 | 별도 바이너리 |
| 버전 관리/패키징 | 없음 (Git 위임) | SemVer Chart |
| 롤백 | 없음 (Git 위임) | 네이티브 지원 |
| 에코시스템 | 없음 | Artifact Hub 10,000+ Charts |
| GitOps 적합성 | 최적 | 렌더링 별도 필요 |
| 학습 곡선 | 낮음 | 높음 |
┌─────────────────────────────────────────────────────────┐
│ 핵심 차이점 │
│ │
│ Helm = 패키지 매니저 (apt / npm for K8s) │
│ ├── 서드파티 앱 설치 및 배포판 관리 │
│ ├── "nginx-ingress 설치해줘" 같은 패키징 │
│ └── Chart 버전 관리, 의존성 해결 │
│ │
│ Kustomize = 설정 오버레이 도구 │
│ ├── 이미 있는 YAML을 환경별로 커스터마이징 │
│ ├── "dev에선 1개, prod에선 3개" 같은 차이점 관리 │
│ └── 원본 파일 불변성 유지 │
│ │
│ 2025-2026 업계 합의: 함께 사용하는 것이 표준 │
│ ├── Helm으로 서드파티 앱 설치 │
│ └── Kustomize로 환경별 패치 적용 │
│ │
└─────────────────────────────────────────────────────────┘
실제 조합 예시:
# overlays/prod/kustomization.yaml
# Helm Chart를 Base로 두고 Kustomize로 패치하는 패턴
resources:
- ../../base
helmCharts:
- name: ingress-nginx
repo: https://kubernetes.github.io/ingress-nginx
version: "4.7.0"
releaseName: ingress-nginx
patches:
- path: custom-patch.yaml
5. SIG-CLI란 무엇인가
SIG (Special Interest Group) 구조
┌─────────────────────────────────────────────────────────┐
│ │
│ SIG = Special Interest Group (특별 관심 그룹) │
│ │
│ Kubernetes 프로젝트를 영역별로 나눠 관리하는 │
│ 공식 조직 단위 │
│ │
│ 배경: │
│ ├── 2014~2015년 K8s 급성장 │
│ ├── 기여자 수천 명, PR 수만 개 │
│ ├── 한 팀이 모든 것을 결정/리뷰하는 것이 불가능 │
│ └── 코드베이스 수백만 줄, 한 사람이 전체 이해 불가 │
│ │
│ 해결책: │
│ 관심 영역별로 전담 팀(SIG)을 둔다 │
│ │
│ 현재 20+ 개의 SIG 운영 중: │
│ ├── SIG-API Machinery (API 서버, 리소스 정의) │
│ ├── SIG-Apps (Deployment, StatefulSet) │
│ ├── SIG-Auth (인증, 인가, RBAC) │
│ ├── SIG-CLI (kubectl, Kustomize) │
│ ├── SIG-Network (Service, Ingress, CNI) │
│ ├── SIG-Node (kubelet, 컨테이너 런타임) │
│ ├── SIG-Scheduling (kube-scheduler) │
│ ├── SIG-Storage (PV, PVC, CSI) │
│ └── ... 등 │
│ │
│ 비유: │
│ ├── SIG = 국회의 상임위원회 │
│ │ └── 국방위, 기재위 각각 전문 영역 담당 │
│ └── K8s Steering Committee = 국회 운영위원회 │
│ └── SIG 간 조율, 전체 방향 설정 │
│ │
└─────────────────────────────────────────────────────────┘
왜 이런 구조가 나왔는가
┌─────────────────────────────────────────────────────────┐
│ │
│ 일반적인 오픈소스 거버넌스: │
│ └── BDFL (자비로운 독재자) 모델 │
│ 예: Linux의 Linus Torvalds │
│ │
│ Kubernetes의 특수성: │
│ ├── Google이 만들었지만 CNCF에 기증 (2015) │
│ ├── 특정 회사가 독점하면 안 됨 │
│ │ → 중립적 거버넌스 필요 │
│ ├── 코드베이스가 거대 (수백만 줄) │
│ └── 한 사람이 모든 영역을 이해하기 불가능 │
│ │
│ SIG 모델의 장점: │
│ ├── 분산 의사결정: 자기 영역에서 자율적 결정 │
│ ├── 전문성: CLI 전문가가 CLI를, 네트워크 전문가가 │
│ │ 네트워크를 결정 │
│ ├── 기업 중립: 여러 회사 멤버가 함께 운영 │
│ └── 확장성: 새 영역 필요 시 새 SIG 생성 │
│ │
└─────────────────────────────────────────────────────────┘
SIG-CLI의 역할
┌─────────────────────────────────────────────────────────┐
│ │
│ SIG-CLI = kubectl 및 CLI 도구 전담 그룹 │
│ │
│ 관리 대상: │
│ ├── kubectl (K8s 공식 CLI) │
│ ├── Kustomize (설정 커스터마이징) │
│ ├── kubectl plugins (플러그인 시스템, Krew) │
│ └── CLI 관련 UX/DX (출력 형식, 자동완성) │
│ │
│ 책임 범위: │
│ ├── 기능 설계 및 KEP(Enhancement Proposal) 검토 │
│ ├── PR 리뷰 및 머지 권한 │
│ ├── 릴리즈 관리 │
│ └── 커뮤니티 미팅 (격주) │
│ │
└─────────────────────────────────────────────────────────┘
Kustomize가 SIG-CLI에 소속된 이유
┌─────────────────────────────────────────────────────────┐
│ │
│ 1. kubectl에 내장됨 │
│ └── kubectl apply -k = Kustomize 기능 │
│ └── CLI 도구의 일부이므로 SIG-CLI 관할 │
│ │
│ 2. 원저자가 SIG-CLI 멤버 │
│ └── Phillip Wittrock이 Google에서 개발 후 │
│ SIG-CLI에 기여 │
│ │
│ 3. CLI 사용자 경험과 직결 │
│ └── "kubectl로 K8s를 어떻게 다룰 것인가?"의 일부 │
│ │
│ 의미: │
│ ├── Kustomize ≠ 커뮤니티 써드파티 도구 │
│ ├── Kubernetes 공식 프로젝트의 일부 │
│ ├── K8s 릴리즈 주기에 맞춰 함께 릴리즈 │
│ └── K8s Steering Committee 거버넌스 하에 운영 │
│ │
│ → Kustomize가 "산업 표준"이라 불리는 핵심 근거 │
│ │
└─────────────────────────────────────────────────────────┘
6. 산업 표준인가?
채택 현황 (CNCF 2024 Survey)
┌─────────────────────────────────────────────────────────┐
│ │
│ Helm ████████████████████████████████████ 75% │
│ Kustomize ███████ 14% │
│ │
│ * Kustomize 14% = 단독 사용 기준 │
│ * 실제 침투율은 훨씬 높음: │
│ ArgoCD / Flux 기반 GitOps 사용 기업은 │
│ 내부적으로 Kustomize를 네이티브 사용 │
│ │
└─────────────────────────────────────────────────────────┘
공식 지위
┌─────────────────────────────────────────────────────────┐
│ │
│ 공식성: │
│ ├── Kubernetes SIG-CLI 관리 프로젝트 │
│ ├── kubectl v1.14 (2019)부터 네이티브 내장 │
│ └── GitHub 11,900+ stars │
│ │
│ GitOps 도구 1등급 지원: │
│ ├── ArgoCD: Kustomize 네이티브 빌드 지원 │
│ └── Flux CD: Kustomize Controller 내장 │
│ │
│ 주요 기업 사용: │
│ ├── Google (원저작자) │
│ └── ArgoCD / Flux 기반 GitOps 사용 기업 대부분 │
│ │
└─────────────────────────────────────────────────────────┘
정확한 위치 규정
┌─────────────────────────────────────────────────────────┐
│ │
│ 배포/패키징의 표준 │
│ ┌─────────────────────────────────────────────────┐ │
│ │ Helm │ │
│ │ 서드파티 앱 설치, Chart 공유, 버전 관리 │ │
│ └─────────────────────────────────────────────────┘ │
│ + │
│ GitOps 환경 커스터마이징의 표준 │
│ ┌─────────────────────────────────────────────────┐ │
│ │ Kustomize │ │
│ │ 환경별 패치, 순수 YAML, GitOps 최적 │ │
│ └─────────────────────────────────────────────────┘ │
│ │
│ 둘은 경쟁이 아닌 보완 관계 │
│ │
└─────────────────────────────────────────────────────────┘
7. Component 패턴 (고급)
Component란?
┌─────────────────────────────────────────────────────────┐
│ Component = 선택적/조합 가능한 기능 단위 │
│ │
│ 추가된 버전: Kustomize v3.7.0+ │
│ kind: Component (Kustomization이 아님!) │
│ │
│ Base와 Overlay 사이 어딘가에 위치: │
│ │
│ components/ ← 선택적 기능 단위들 │
│ ├── monitoring/ ← Prometheus 설정 │
│ │ ├── kustomization.yaml (kind: Component) │
│ │ └── servicemonitor.yaml │
│ ├── hpa/ ← HorizontalPodAutoscaler │
│ │ ├── kustomization.yaml (kind: Component) │
│ │ └── hpa.yaml │
│ └── debug-logging/ ← 디버그 로그 설정 │
│ ├── kustomization.yaml (kind: Component) │
│ └── configmap-patch.yaml │
│ │
└─────────────────────────────────────────────────────────┘
# components/monitoring/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1alpha1
kind: Component # Kustomization이 아님!
resources:
- servicemonitor.yaml
patches:
- path: annotation-patch.yaml
# overlays/prod/kustomization.yaml
# prod: monitoring + hpa 포함
resources:
- ../../base
components:
- ../../components/monitoring
- ../../components/hpa
# overlays/dev/kustomization.yaml
# dev: debug-logging만 포함
resources:
- ../../base
components:
- ../../components/debug-logging
┌─────────────────────────────────────────────────────────┐
│ Component의 핵심 가치 │
│ │
│ 중복 패치 없이 기능을 조합: │
│ ├── prod: base + monitoring + hpa │
│ ├── staging: base + monitoring │
│ └── dev: base + debug-logging │
│ │
│ 같은 패치를 여러 overlay에 복붙하는 문제 해결 │
│ │
└─────────────────────────────────────────────────────────┘
8. 실전 Best Practices
┌─────────────────────────────────────────────────────────┐
│ 1. Base 파일을 직접 수정하지 않기 │
│ │
│ ❌ base/deployment.yaml 직접 편집 │
│ ✅ overlays/prod/patch.yaml 로 패치 │
│ │
│ Base = 읽기 전용 원본, 패치로만 커스터마이징 │
│ │
└─────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────┐
│ 2. 이미지 태그 고정 (latest 사용 금지) │
│ │
│ ❌ newTag: latest │
│ ✅ newTag: v2.3.1 │
│ │
│ GitOps에서 tag = 배포 버전의 유일한 진실 │
│ │
└─────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────┐
│ 3. Overlay를 작게 유지 │
│ │
│ Overlay가 너무 크다 = Base 설계를 재검토할 시점 │
│ 이상적인 Overlay = 5-10개 필드 변경 │
│ │
└─────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────┐
│ 4. namePrefix로 환경 구분 │
│ │
│ namePrefix: prod- → prod-my-app │
│ namePrefix: staging- → staging-my-app │
│ │
│ 같은 클러스터에 여러 환경 공존 시 충돌 방지 │
│ │
└─────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────┐
│ 5. 대규모 조직: Base/Overlay 별도 리포지토리 │
│ │
│ app-configs (Base 전용) │
│ └── base/my-app/ │
│ │
│ app-overlays (Overlay 전용, 팀별) │
│ ├── team-a/overlays/prod/ │
│ └── team-b/overlays/prod/ │
│ │
│ Base 변경 = PR 리뷰 필수, Overlay = 팀 자율 │
│ │
└─────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────┐
│ 6. CI에서 kustomize build로 유효성 검증 │
│ │
│ # .github/workflows/validate.yaml │
│ - run: kustomize build overlays/prod | \ │
│ kubectl apply --dry-run=client -f - │
│ │
│ 배포 전 렌더링 실패 조기 발견 │
│ │
└─────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────┐
│ 7. 중복 패치 → Component로 추출 │
│ │
│ 여러 overlay에 같은 패치가 등장하면: │
│ → components/ 디렉토리로 추출 │
│ → 각 overlay에서 components: 로 선언적 포함 │
│ │
└─────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────┐
│ 8. commonLabels 대신 labels + includeSelectors 주의 │
│ │
│ commonLabels: 는 selector도 함께 수정 │
│ → 기존 Deployment 업데이트 시 오류 유발 가능 │
│ │
│ 안전한 방법: │
│ labels: │
│ pairs: │
│ env: prod │
│ includeSelectors: false ← selector 제외 │
│ │
└─────────────────────────────────────────────────────────┘
관련 키워드
Kustomize, Base/Overlay, kubectl apply -k, Strategic Merge Patch, JSON 6902, Helm, GitOps, ArgoCD, Flux CD, Component, SIG-CLI, kustomization.yaml, Kubernetes, 환경별 설정, 패치 기반 커스터마이징