Kustomize - Kustomize vs Helm

2026. 1. 8. 11:53·CKA

앞에서 Kustomize가 base + overlay 구조로 “공통 매니페스트 재사용 + 환경별 차이만 덮어쓰기”를 해결했다면, Helm은 같은 문제를 템플릿(Go template) + values 방식으로 풉니다. 둘 다 “환경별(dev/stage/prod)로 replicas, 이미지 태그, 리소스 제한 등을 다르게 배포”하는 데 쓰이지만, 접근 방식과 트레이드오프가 꽤 다릅니다.


Helm이 해결하는 문제(=Kustomize와 동일한 출발점)

  • Kubernetes 매니페스트를 환경별로 조금씩 다르게 배포해야 한다
  • 그런데 환경별로 디렉터리 복붙해서 YAML을 관리하면 리소스가 늘수록 유지보수가 깨진다
  • 그래서 “공통은 재사용하고, 환경별로 바뀌는 값만” 관리하고 싶다

Helm의 핵심 방식: 템플릿(Go template) + values.yaml

Helm 차트(chart)는 크게 두 덩어리로 생각하면 됩니다.

  1. templates/
    • 쿠버네티스 리소스 YAML처럼 보이지만, 중간중간 변수/로직이 들어간 Go 템플릿
  2. values.yaml (및 env별 values 파일)
    • 템플릿에 들어갈 변수 값들의 모음 (환경별로 파일을 나눠서 관리)

예시: Deployment 템플릿에서 replicas를 변수로

templates/deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{ .Release.Name }}
spec:
  replicas: {{ .Values.replicaCount }}
  selector:
    matchLabels:
      app: {{ .Release.Name }}
  template:
    metadata:
      labels:
        app: {{ .Release.Name }}
    spec:
      containers:
        - name: nginx
          image: "nginx:{{ .Values.image.tag }}"
          ports:
            - containerPort: 80

여기서 중요한 포인트는:

  • {{ ... }} 가 Helm(Go template) 문법이고
  • .Values.replicaCount, .Values.image.tag 같은 값이 values 파일에서 주입된다는 것

values.yaml로 변수 값 제공

values.yaml

replicaCount: 1

image:
  tag: "1.27.3"

환경마다 replicaCount나 image.tag를 다르게 하고 싶다면, 환경별 values 파일을 별도로 둡니다.


전형적인 Helm 프로젝트 구조(환경별 values)

예를 들어 아래처럼 구성합니다.

mychart/
  Chart.yaml
  templates/
    deployment.yaml
    service.yaml
  values.yaml                # 기본값(디폴트)
  environments/
    values.dev.yaml
    values.staging.yaml
    values.prod.yaml
  • values.yaml: 공통/기본값
  • values.<env>.yaml: 환경별로 덮어쓸 값들

예시: env별 values 파일

environments/values.dev.yaml

replicaCount: 1
image:
  tag: "1.27.3-dev"

environments/values.staging.yaml

replicaCount: 2
image:
  tag: "1.27.3-rc"

environments/values.prod.yaml

replicaCount: 5
image:
  tag: "1.27.3"

배포 워크플로우(명령어 예시)

1) 렌더링 결과를 먼저 보고 싶을 때(매우 권장)

Helm 템플릿은 “렌더링 전에는 완전한 YAML이 아님”이 핵심 리스크라서, 배포 전에 렌더링 결과를 확인하는 습관이 좋습니다.

helm template myapp ./mychart -f environments/values.staging.yaml

또는 네임스페이스/릴리즈명까지 포함해서:

helm template myapp ./mychart \
  --namespace staging \
  -f environments/values.staging.yaml

2) 설치(install)

helm install myapp ./mychart \
  --namespace staging --create-namespace \
  -f environments/values.staging.yaml

3) 업그레이드(upgrade)

helm upgrade myapp ./mychart \
  --namespace staging \
  -f environments/values.staging.yaml

보통은 설치/업그레이드를 한 번에:

helm upgrade --install myapp ./mychart \
  --namespace staging --create-namespace \
  -f environments/values.staging.yaml

4) 릴리즈 이력/롤백(Helm이 “패키지 매니저”인 이유)

Helm은 단순히 템플릿 렌더링 도구가 아니라 릴리즈 단위로 설치/업그레이드/히스토리/롤백을 제공합니다.

helm list -n staging
helm history myapp -n staging
helm rollback myapp 2 -n staging

이 “릴리즈 관리” 성격은 Kustomize에는 없는 Helm의 강점입니다.


Helm의 장점(=Kustomize 대비 “기능이 더 많음”)

Helm은 템플릿 엔진을 갖고 있어서 다음이 가능합니다.

  • 조건부 리소스 생성 (if, else)
  • 반복문 (range)
  • 함수/필터(문자열 가공 등)
  • 훅(Hooks)로 특정 타이밍에 Job 실행(예: 마이그레이션)

예: 프로덕션에서만 HPA를 만들고 싶다면

{{- if .Values.hpa.enabled }}
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
...
{{- end }}

이런 “로직”은 Kustomize보다 Helm이 훨씬 강합니다.


Helm의 단점(=기능이 많은 만큼 복잡해짐)

1) 템플릿은 렌더링 전엔 “순수 YAML”이 아니다

{{ }}가 들어간 파일은 kubectl이 바로 이해하는 YAML이 아니고, 사람이 읽기에도 “실제 결과가 무엇인지” 머릿속에서 렌더링해야 합니다.

그래서 운영에서는 다음 습관이 중요합니다.

  • helm template로 결과를 먼저 확인
  • helm lint로 기본 검증
helm lint ./mychart

2) 차트가 커질수록 가독성이 급격히 떨어질 수 있다

변수/조건/반복이 많아지면:

  • “어떤 값이 필수인지”
  • “어떤 조합에서 어떤 리소스가 생성되는지”
  • “특정 환경에서 실제로 뭘 배포하는지”
    파악이 어려워집니다.

실무에서는 보통 다음으로 완화합니다.

  • 템플릿 로직 최소화(가능하면 values로 해결)
  • _helpers.tpl에 공통 로직/이름 규칙 모으기
  • values.yaml에 주석/문서화 철저히
  • values.schema.json로 값 스키마 검증(규모가 커지면 특히 유효)

Kustomize vs Helm: 선택 기준을 딱 잘라보면

Kustomize가 더 유리한 경우

  • “기본 YAML이 그대로” 남아 있길 원한다 (가독성/리뷰 우선)
  • 환경별 차이가 patch로 충분하다 (replicas, image tag, labels, namespace 등)
  • 템플릿 언어/로직 없이 단순한 구조를 선호한다
  • kubectl 기반 워크플로우를 유지하고 싶다

Helm이 더 유리한 경우

  • 리소스 생성이 환경/옵션에 따라 크게 달라지고 조건부/반복이 필요하다
  • 릴리즈 단위의 설치/업그레이드/히스토리/롤백 같은 패키지 매니저 기능이 중요하다
  • 외부에 배포 가능한 “차트 패키지” 형태로 재사용/공유하고 싶다
  • 복잡한 앱 스택(여러 컴포넌트)을 하나의 배포 단위로 관리하고 싶다

실무 팁: “둘 중 하나만”이 정답은 아니다

많은 팀이 실제로는 다음처럼 섞어서 씁니다.

  • Helm으로 벤더 차트 설치 (ingress-nginx, cert-manager, metrics-server 같은 것들)
  • 애플리케이션은 Kustomize로 overlay 관리
    또는
  • 애플리케이션도 Helm로 관리하되, 환경별 values를 엄격히 분리하고 렌더링 결과를 CI에서 검증

중요한 건 도구가 아니라, “환경별 드리프트(불일치)를 어떻게 막고, 변경을 어떻게 안전하게 리뷰/배포하느냐”입니다.

'CKA' 카테고리의 다른 글

kustomize - kustomization.yaml  (0) 2026.01.08
Kustomize - Install/Setup Kustomize  (0) 2026.01.08
Kustomize  (0) 2026.01.08
Helm - 정리  (1) 2026.01.07
Helm - Lifecycle Management(Upgrade/Rollback)  (0) 2026.01.07
'CKA' 카테고리의 다른 글
  • kustomize - kustomization.yaml
  • Kustomize - Install/Setup Kustomize
  • Kustomize
  • Helm - 정리
5jyan5
5jyan5
  • 5jyan5
    jyan
    5jyan5
  • 전체
    오늘
    어제
    • 분류 전체보기 (242)
      • 김영한의 스프링 핵심 원리(기본편) (8)
      • 김영한의 스프링 핵심 원리 - 고급편 (11)
      • 김영한의 스프링 MVC 1편 (1)
      • 김영한의 스프링 DB 1편 (3)
      • 김영한의 스프링 MVC 2편 (3)
      • 김영한의 ORM 표준 JPA 프로그래밍(기본편) (9)
      • 김영한의 스프링 부트와 JPA 활용2 (2)
      • 김영한의 실전 자바 - 중급 1편 (1)
      • 김영한의 실전 자바 - 고급 1편 (9)
      • 김영한의 실전 자바 - 고급 2편 (9)
      • Readable Code: 읽기 좋은 코드를 작성.. (2)
      • 김영한의 실전 자바 - 고급 3편 (9)
      • CKA (118)
      • 개발 (37)
      • 경제 (4)
      • 리뷰 (1)
      • 정보 (2)
  • 블로그 메뉴

    • 링크

    • 공지사항

    • 인기 글

    • 태그

      빈 후처리기
      Thread
      @args
      단방향 맵핑
      양방향 맵핑
      버퍼
      조회 성능 최적화
      자바
      jpq
      @within
      gesingleresult
      스레드
      락
      hibernate5module
      @discriminatorvalue
      cglib
      프록시
      Target
      @discriminatorcolumn
      WAS
      김영한
      jdk 동적 프록시
      reentarantlock
      페치 조인
      typequery
      프록시 팩토리
      requset scope
      log trace
      JPQL
      고급
    • 최근 댓글

    • 최근 글

    • hELLO· Designed By정상우.v4.10.2
    5jyan5
    Kustomize - Kustomize vs Helm
    상단으로

    티스토리툴바