K8s Kustomize 오버레이 운영

Kustomize란?

Kustomize는 Kubernetes 매니페스트를 템플릿 없이 오버레이 방식으로 커스터마이징하는 도구다. Helm이 Go 템플릿으로 값을 주입하는 반면, Kustomize는 원본 YAML을 그대로 유지하고 패치(patch)로 환경별 차이만 선언한다. kubectl에 내장되어 있어 별도 설치 없이 kubectl apply -k로 바로 사용할 수 있다.

디렉토리 구조

k8s/
├── base/                        # 공통 리소스 (환경 무관)
│   ├── kustomization.yaml
│   ├── deployment.yaml
│   ├── service.yaml
│   └── configmap.yaml
├── overlays/
│   ├── dev/                     # 개발 환경 오버레이
│   │   ├── kustomization.yaml
│   │   ├── replica-patch.yaml
│   │   └── env-configmap.yaml
│   ├── staging/
│   │   ├── kustomization.yaml
│   │   └── replica-patch.yaml
│   └── prod/                    # 프로덕션 오버레이
│       ├── kustomization.yaml
│       ├── replica-patch.yaml
│       ├── hpa.yaml
│       └── resource-patch.yaml

base/에 모든 환경에 공통인 리소스를 두고, overlays/에서 환경별 차이만 패치로 선언한다. 원본 YAML을 수정하지 않으므로 변경 추적이 명확하다.

base: 공통 리소스 정의

# base/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

resources:
  - deployment.yaml
  - service.yaml
  - configmap.yaml

commonLabels:
  app: api-server

---
# base/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: api-server
spec:
  replicas: 1
  selector:
    matchLabels:
      app: api-server
  template:
    metadata:
      labels:
        app: api-server
    spec:
      containers:
        - name: api
          image: api-server:latest
          ports:
            - containerPort: 3000
          resources:
            requests:
              cpu: 100m
              memory: 128Mi
            limits:
              cpu: 500m
              memory: 512Mi
          envFrom:
            - configMapRef:
                name: api-config

overlays: 환경별 패치

# overlays/prod/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

resources:
  - ../../base              # base 참조
  - hpa.yaml                # 프로덕션 전용 리소스 추가

namespace: production       # 네임스페이스 오버라이드

namePrefix: prod-           # 리소스 이름에 접두사 추가
commonLabels:
  env: production

images:                     # 이미지 태그 오버라이드
  - name: api-server
    newName: registry.example.com/api-server
    newTag: v2.3.1

patches:                    # 패치 적용
  - path: replica-patch.yaml
  - path: resource-patch.yaml

패치 방식: Strategic Merge vs JSON Patch

Kustomize는 두 가지 패치 방식을 지원한다:

# 1. Strategic Merge Patch (기본, 직관적)
# replica-patch.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: api-server
spec:
  replicas: 5              # replicas만 오버라이드

---
# resource-patch.yaml — 리소스 제한 변경
apiVersion: apps/v1
kind: Deployment
metadata:
  name: api-server
spec:
  template:
    spec:
      containers:
        - name: api        # 컨테이너 이름으로 매칭
          resources:
            requests:
              cpu: 500m
              memory: 512Mi
            limits:
              cpu: "2"
              memory: 2Gi
# 2. JSON 6902 Patch (정밀한 제어)
# kustomization.yaml에서:
patches:
  - target:
      kind: Deployment
      name: api-server
    patch: |-
      - op: replace
        path: /spec/replicas
        value: 5
      - op: add
        path: /spec/template/spec/containers/0/env/-
        value:
          name: LOG_LEVEL
          value: warn
방식 장점 적합한 상황
Strategic Merge 직관적, YAML 그대로 필드 추가/변경
JSON 6902 배열 인덱스 접근, 삭제 가능 정밀 수정, 필드 삭제

ConfigMap·Secret 생성기

Kustomize는 파일이나 리터럴에서 ConfigMap과 Secret을 자동 생성하고, 해시 접미사를 붙여 변경 시 롤링 업데이트를 트리거한다:

# kustomization.yaml
configMapGenerator:
  - name: api-config
    literals:
      - DATABASE_HOST=db.production.internal
      - LOG_LEVEL=warn
      - NODE_ENV=production
    files:
      - configs/nginx.conf     # 파일을 ConfigMap으로

secretGenerator:
  - name: api-secrets
    literals:
      - DB_PASSWORD=s3cur3p@ss
    files:
      - secrets/tls.crt
      - secrets/tls.key
    type: kubernetes.io/tls

generatorOptions:
  disableNameSuffixHash: false   # true면 해시 접미사 비활성화

생성된 ConfigMap 이름은 api-config-8k2m5h처럼 내용 해시가 붙는다. ConfigMap 내용이 변경되면 새 해시로 이름이 바뀌고, Deployment가 이를 참조하므로 자동으로 롤링 업데이트가 발생한다. K8s ConfigMap·Secret 운영에서 다룬 Reloader 없이도 변경 감지가 가능한 것이다.

components: 재사용 가능한 기능 단위

여러 오버레이에서 공유할 수 있는 기능 단위를 components로 분리한다:

# components/monitoring/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1alpha1
kind: Component

patches:
  - target:
      kind: Deployment
    patch: |-
      - op: add
        path: /spec/template/metadata/annotations/prometheus.io~1scrape
        value: "true"
      - op: add
        path: /spec/template/metadata/annotations/prometheus.io~1port
        value: "9090"

resources:
  - service-monitor.yaml

---
# overlays/prod/kustomization.yaml에서 사용
components:
  - ../../components/monitoring
  - ../../components/istio-sidecar

monitoring, istio-sidecar, resource-limits 등을 component로 만들면 dev에선 monitoring만, prod에선 monitoring + istio를 조합해 사용할 수 있다.

빌드와 검증

# 최종 매니페스트 미리보기 (적용 전 확인)
kubectl kustomize overlays/prod

# 또는 kustomize CLI
kustomize build overlays/prod

# diff로 현재 클러스터와 비교
kubectl diff -k overlays/prod

# 적용
kubectl apply -k overlays/prod

# 파이프라인에서 kustomize edit으로 이미지 태그 업데이트
cd overlays/prod
kustomize edit set image api-server=registry.example.com/api-server:${GIT_SHA}
# → kustomization.yaml의 images 섹션이 업데이트됨

Helm과의 비교·조합

비교 Kustomize Helm
접근 방식 오버레이 + 패치 Go 템플릿 + values
학습 곡선 낮음 (순수 YAML) 높음 (템플릿 문법)
패키지 배포 ✅ Chart 레지스트리
릴리스 관리 ✅ helm history/rollback
kubectl 내장 ❌ (별도 설치)
# Helm Chart를 Kustomize로 커스터마이징 (조합 사용)
# kustomization.yaml
helmCharts:
  - name: ingress-nginx
    repo: https://kubernetes.github.io/ingress-nginx
    version: 4.8.3
    releaseName: ingress
    namespace: ingress-nginx
    valuesFile: nginx-values.yaml

# Helm으로 기본 설치 + Kustomize로 추가 패치
patches:
  - target:
      kind: Deployment
      name: ingress-nginx-controller
    patch: |-
      - op: add
        path: /spec/template/spec/tolerations
        value:
          - key: node-role
            value: edge
            effect: NoSchedule

Helm Chart를 Kustomize의 helmCharts로 렌더링한 뒤 패치를 적용하면, 서드파티 Chart를 포크하지 않고도 커스터마이징할 수 있다.

GitOps 파이프라인 통합

# CI에서 이미지 태그 업데이트 → Git push → ArgoCD 감지
# .github/workflows/deploy.yml
- name: Update image tag
  run: |
    cd k8s/overlays/prod
    kustomize edit set image api-server=registry.example.com/api-server:${{ github.sha }}

- name: Commit and push
  run: |
    git config user.name "ci-bot"
    git add k8s/overlays/prod/kustomization.yaml
    git commit -m "deploy: api-server ${{ github.sha }}"
    git push

K8s RBAC에서 다룬 ServiceAccount 권한 관리와 결합하면, CI 봇이 최소 권한으로 배포 매니페스트만 업데이트하고, ArgoCD가 클러스터에 적용하는 안전한 파이프라인을 구성할 수 있다.

정리

기능 용도
base + overlays 환경별 매니페스트 분리
Strategic Merge Patch 필드 추가/변경
JSON 6902 Patch 정밀 수정, 배열 조작
configMapGenerator 해시 기반 자동 롤링 업데이트
components 재사용 가능한 기능 조합
helmCharts Helm + Kustomize 조합

Kustomize는 “YAML을 YAML로 커스터마이징”하는 철학이다. 템플릿 문법 없이 base + overlay + patch만으로 환경별 배포를 관리할 수 있어, GitOps 워크플로에서 변경 추적과 코드 리뷰가 투명해진다.

위로 스크롤
WordPress Appliance - Powered by TurnKey Linux