블로그 이미지
Cloud Engineer

클라우드 & 쿠버네티스 엔지니어의 기술 기록

쿠버네티스 기반 프라이빗 클라우드 구축·운영과 레거시 → 클라우드 전환 경험을 정리합니다. 직접 부딪힌 문제와 트러블슈팅 과정을 위주로 기록해요.

Kubernetes Private Cloud Legacy to Cloud
전체 방문자
오늘
어제

GitHub Activity

GitHub Stats Top Languages
GitHub Streak

Tech Stack

Container & Orchestration

OpenShift OpenShift Virtualization RKE2 Rancher Kubernetes Docker Helm

Middleware / WAS

JBoss Apache HTTPD Tomcat

Cloud

AWS Google Cloud

Auth / Identity

Keycloak Google OIDC OAuth2 Proxy

Automation / IaC

Ansible

카테고리 둘러보기

DevOps/Kubernetes 2026. 9. 30. 16:59

Kustomize 정리 - base와 overlay로 환경별 매니페스트 관리하기

728x90

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

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로 바뀌었다는 점만 알아두면 바로 실무에 적용할 수 있습니다.

참고사항

728x90