콘텐츠로 이동

16. Helm과 Kustomize

클러스터 컴포넌트를 설치하는 두 방법

커리큘럼 항목은 “Use Helm and Kustomize to install cluster components” 다.

  • 차트를 만드는 게 아니라 설치하고 값을 바꾸는 쪽이다
  • 실제로 CNI·Ingress 컨트롤러·모니터링은 전부 이 둘 중 하나로 설치한다
flowchart LR
    subgraph H["Helm — 템플릿 + 값 주입"]
      CH["Chart<br/>Go 템플릿"] --> VAL["Values 주입"] --> REL["Release<br/>상태를 추적한다"]
    end
    subgraph K["Kustomize — 베이스 + 오버레이"]
      BASE["base/<br/>평범한 YAML"] --> OVR["overlays/prod<br/>패치를 얹는다"] --> OUT["최종 YAML<br/>상태 추적 없음"]
    end
    REL -.->|"별도 바이너리"| BIN["helm"]
    OUT -.->|"kubectl 에 내장"| KUB["kubectl -k"]

    classDef helm fill:#dbeafe,stroke:#2563eb,color:#1e3a8a
    classDef kust fill:#dcfce7,stroke:#16a34a,color:#14532d
    classDef mute fill:#f1f5f9,stroke:#94a3b8,color:#334155
    class CH,VAL,REL helm
    class BASE,OVR,OUT kust
    class BIN,KUB mute
Helm Kustomize
방식 템플릿 + 값 주입 베이스 YAML + 오버레이 패치
배포 형태 패키지(차트) 저장소 그냥 디렉터리
상태 관리 릴리스를 추적한다 없음 (kubectl apply와 동일)
설치 별도 바이너리 kubectl에 내장 (-k)

Chart

패키지. 템플릿 + 기본값의 묶음.

Values

차트에 주입하는 설정값.

Release

클러스터에 설치된 차트의 인스턴스. 이름이 있고, 같은 차트를 여러 번 설치할 수 있다.

Repository

차트를 배포하는 곳.

  • 디렉터리mychart/
    • Chart.yaml 이름, 버전, 의존성
    • values.yaml 기본값
    • 디렉터리templates/ Go 템플릿이 섞인 매니페스트
      • deployment.yaml
      • service.yaml
      • _helpers.tpl
    • 디렉터리charts/ 서브차트

같은 차트를 다른 이름의 릴리스로 여러 번 설치할 수 있다. 릴리스 정보는 네임스페이스의 Secret에 저장된다 (Helm 3부터. Tiller는 없어졌다).

  1. 저장소 등록

    Terminal window
    helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
    helm repo update
    helm repo list
    helm search repo ingress
    helm search hub prometheus
  2. 차트 살펴보기 — ★ 무엇을 바꿀 수 있는지 여기서 찾는다

    Terminal window
    helm show values ingress-nginx/ingress-nginx # 설정 가능한 값 전부
    helm show chart ingress-nginx/ingress-nginx
    helm pull ingress-nginx/ingress-nginx --untar # 로컬로 받아서 뜯어보기
  3. 설치

    Terminal window
    helm install my-ingress ingress-nginx/ingress-nginx \
    --namespace ingress-nginx --create-namespace
  4. 확인

    Terminal window
    helm list -A
    helm status my-ingress -n ingress-nginx
    helm get values my-ingress -n ingress-nginx
    helm get manifest my-ingress -n ingress-nginx # 실제로 적용된 YAML
Terminal window
helm install my-ingress ingress-nginx/ingress-nginx \
--set controller.replicaCount=3 \
--set controller.service.type=NodePort \
--set-string controller.config.use-forwarded-headers="true"

값 한두 개만 바꿀 때. 시험에서 가장 자주 쓰는 형태.

Terminal window
# 적용 전에 결과 확인 — 시험·실무 모두 유용하다
helm template my-ingress ingress-nginx/ingress-nginx -f my-values.yaml
helm install my-ingress ingress-nginx/ingress-nginx --dry-run --debug
flowchart LR
    Q["이 차트의 어떤 값을 바꾸시오"] --> S1["helm show values 차트<br/>키 이름을 찾는다"]
    S1 --> S2["--set 키=값<br/>또는 -f values.yaml"]
    S2 --> S3["helm template 로 결과 확인"]
    S3 --> S4["helm install / upgrade"]

    classDef key fill:#dbeafe,stroke:#2563eb,color:#1e3a8a
    classDef mute fill:#f1f5f9,stroke:#94a3b8,color:#334155
    class S1 key
    class Q,S2,S3,S4 mute
Terminal window
helm upgrade my-ingress ingress-nginx/ingress-nginx --set controller.replicaCount=5
helm upgrade --install my-ingress ingress-nginx/ingress-nginx # 없으면 설치, 있으면 업그레이드
helm history my-ingress -n ingress-nginx
# REVISION UPDATED STATUS CHART DESCRIPTION
# 1 2026-08-01 superseded ingress-nginx-4.11.0 Install complete
# 2 2026-08-05 deployed ingress-nginx-4.11.0 Upgrade complete
helm rollback my-ingress 1 -n ingress-nginx
helm uninstall my-ingress -n ingress-nginx
flowchart LR
    U["helm upgrade"] --> Q{"-f 또는 --set 을<br/>줬는가"}
    Q -->|"줬다"| NEW["그 값이 적용된다"]
    Q -->|"안 줬다"| KEEP["이전 값이 유지된다 · Helm 3"]
    Q -->|"--reset-values"| RESET["차트 기본값으로 초기화 ⚠️"]
    UN["helm uninstall"] -->|"CRD 는 남긴다 ⚠️<br/>의도된 동작 · 데이터 보호"| CRD["CustomResourceDefinition"]

    classDef ok fill:#dcfce7,stroke:#16a34a,color:#14532d
    classDef warn fill:#fef3c7,stroke:#d97706,color:#78350f
    classDef mute fill:#f1f5f9,stroke:#94a3b8,color:#334155
    class NEW,KEEP ok
    class RESET,CRD warn
    class U,Q,UN mute

Kustomize — 템플릿 없는 커스터마이징

섹션 제목: “Kustomize — 템플릿 없는 커스터마이징”
  • 디렉터리base/
    • kustomization.yaml
    • deployment.yaml
    • service.yaml
  • 디렉터리overlays/
    • 디렉터리dev/
      • kustomization.yaml
      • replica-patch.yaml
    • 디렉터리prod/
      • kustomization.yaml
      • replica-patch.yaml
base/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- deployment.yaml
- service.yaml
commonLabels:
app: web
  • 템플릿 언어가 없다. 전부 유효한 YAML이다
  • 베이스는 그대로 두고 오버레이가 패치를 얹는다
  • kubectl에 내장되어 있다 — 별도 설치가 필요 없다
flowchart LR
    B["base/<br/>deployment.yaml · service.yaml"] --> D["overlays/dev<br/>replicas 1 · nginx:latest"]
    B --> P["overlays/prod<br/>replicas 5 · nginx:1.28 · namePrefix prod-"]
    D --> OD["kubectl apply -k overlays/dev"]
    P --> OP["kubectl apply -k overlays/prod"]

    classDef key fill:#dbeafe,stroke:#2563eb,color:#1e3a8a
    classDef ok fill:#dcfce7,stroke:#16a34a,color:#14532d
    classDef mute fill:#f1f5f9,stroke:#94a3b8,color:#334155
    class B key
    class OD,OP ok
    class D,P mute

오버레이 — 이름·네임스페이스·이미지 바꾸기

섹션 제목: “오버레이 — 이름·네임스페이스·이미지 바꾸기”
overlays/prod/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ../../base # 베이스를 가져온다
namespace: prod # 전부 이 네임스페이스로
namePrefix: prod- # 모든 이름 앞에 붙인다
commonAnnotations: { owner: platform-team }
images:
- { name: nginx, newTag: "1.28" } # 이미지 태그만 교체
replicas:
- { name: web, count: 5 } # 레플리카 수만 교체
  • images / replicas패치 파일 없이 가장 자주 바꾸는 값을 직접 지정하는 단축이다
  • namePrefix를 쓰면 참조하는 Service·볼륨 이름도 함께 갱신된다
configMapGenerator:
- name: app-config
literals: ["LOG_LEVEL=warn"]
secretGenerator:
- name: db-secret
literals: ["password=prodsecret"]
patches:
- path: resource-patch.yaml # 파일로 패치
target: { kind: Deployment, name: web }
  • generator는 ConfigMap/Secret을 오버레이에서 새로 만든다 (베이스에 둘 필요가 없다)
  • patches 는 베이스의 임의 필드를 고친다. target으로 대상을 고른다
Terminal window
kubectl kustomize overlays/prod # 결과를 출력만 (미리보기)
kubectl apply -k overlays/prod # 적용 (delete -k 로 제거)
kustomize build overlays/prod | kubectl apply -f - # 독립 바이너리를 쓸 때

패치 두 가지 방식

바꿀 부분만 같은 구조로 쓴다. 읽기 쉽다.

resource-patch.yaml
apiVersion: apps/v1
kind: Deployment
metadata: { name: web }
spec:
template:
spec:
containers:
- name: nginx
resources: { limits: { memory: 512Mi } }
Terminal window
kubectl kustomize overlays/prod | grep -A2 'kind: ConfigMap'
# name: prod-app-config-7g5bd8f2mk

이것이 6장의 “ConfigMap을 바꿔도 Pod이 안 바뀐다” 문제를 구조적으로 푼다.

flowchart LR
    CM["configMapGenerator<br/>LOG_LEVEL=warn"] --> H1["이름에 내용 해시가 붙는다<br/>app-config-7g5bd8f2mk"]
    H1 --> D1["Deployment 의 참조도<br/>자동으로 갱신된다"]
    CHG["값을 debug 로 바꾼다"] --> H2["새 해시<br/>app-config-2k9xf4m1qp"]
    H2 --> D2["Deployment 템플릿이 바뀐다<br/>→ 자동 롤아웃 ✅"]

    classDef key fill:#dbeafe,stroke:#2563eb,color:#1e3a8a
    classDef ok fill:#dcfce7,stroke:#16a34a,color:#14532d
    classDef mute fill:#f1f5f9,stroke:#94a3b8,color:#334155
    class H1,H2 key
    class D2 ok
    class CM,CHG,D1 mute
  • configMapGenerator/secretGenerator가 만든 이름에는 내용 해시가 붙는다
  • 그리고 참조하는 Deployment의 이름도 자동으로 갱신된다
  • 결과: ConfigMap이 바뀌면 Deployment가 자동으로 롤아웃된다
generatorOptions:
disableNameSuffixHash: true # 해시를 끄고 싶다면
flowchart TD
    Q{"누가 만든 것인가"}
    Q -->|"남이 만든 것<br/>Ingress 컨트롤러 · Prometheus · CNI"| H["Helm<br/>설정 표면이 넓고<br/>버전 관리·롤백이 필요하다"]
    Q -->|"내가 만든 앱"| K["Kustomize<br/>환경별 변형<br/>YAML 을 그대로 읽고 싶다"]
    BOTH["배타적이지 않다"] -.->|"helm template 결과를<br/>Kustomize 로 패치하는 조합도 흔하다"| Q

    classDef helm fill:#dbeafe,stroke:#2563eb,color:#1e3a8a
    classDef kust fill:#dcfce7,stroke:#16a34a,color:#14532d
    classDef mute fill:#f1f5f9,stroke:#94a3b8,color:#334155
    class H helm
    class K kust
    class Q,BOTH mute
Terminal window
helm template prom prometheus/kube-prometheus-stack > base/all.yaml
# → 이후 Kustomize 오버레이로 환경별 변형
  • 커리큘럼의 초점은 “설치하고 값을 바꾸기” — 차트 작성이 아니다
  • Helm: Chart(패키지) + Values(설정) + Release(인스턴스)
  • helm show values로 키를 찾고 --set 또는 -f로 덮어쓴다
  • 적용 전 확인은 helm template 또는 --dry-run --debug
  • helm uninstall은 CRD를 남긴다
  • Kustomize: 템플릿 없음. 베이스 + 오버레이 패치. kubectl -k에 내장
  • generator의 해시 접미사가 ConfigMap 변경 시 자동 롤아웃을 만든다
  • 남의 것은 Helm, 내 것은 Kustomize — 실무의 대략적 경계