쿠버네티스 마스터 노트 시리즈 9편. Helm이 K8s의 패키지 매니저로 등장한 배경, Chart 구조(Chart.yaml·values.yaml·templates/), Go 템플릿 + Sprig 함수, Release와 Revision 개념, helm install/upgrade/rollback 운영 흐름, Kustomize와의 결정적 차이, Helm vs Kustomize 선택 기준까지.
이 글은 쿠버네티스 마스터 노트 시리즈의 아홉 번째 편입니다. 1~8편이 K8s 자체였다면, 이번엔 그것을 패키지로 관리 — Helm.
같은 앱을 dev·staging·prod 3 환경에 배포하면 YAML이 3 묶음. 변수·환경별 값 어떻게? Helm이 답.
처음 Helm이 어렵게 느껴지는 이유
처음 이 단원이 어렵게 느껴지는 이유는 두 가지예요. 첫째, Go 템플릿 문법이 익숙하지 않습니다. {{ .Values.foo }}. 둘째, Helm vs Kustomize 선택이 막연합니다.
해결법은 한 가지예요. "Helm = 템플릿 엔진 + 패키지 / Kustomize = YAML overlay" 한 줄. Helm = 변수 많고 복잡 OK, Kustomize = 단순 환경별 차이만. 이 그림이 잡히면 선택이 명확.
Helm 등장 배경
# Pod·Service·ConfigMap·Ingress·HPA·NetworkPolicy ...
# 환경별로 같은 YAML 3개 (dev·staging·prod)
# 환경별로 image tag·replicas·resources 다름
문제 — 복사·붙여넣기 → 휴먼 에러. 변경 시 모든 환경 수정.
해결 — 템플릿 + 변수:
templates/deployment.yaml (한 번 정의)
values-dev.yaml (개발 값)
values-staging.yaml (스테이징 값)
values-prod.yaml (운영 값)
Helm 설치·기본
brew install helm
# 저장소 추가
helm repo add bitnami https://charts.bitnami.com/bitnami
helm repo update
# 검색
helm search repo nginx
# 설치
helm install my-nginx bitnami/nginx
# 목록
helm list
# 업그레이드
helm upgrade my-nginx bitnami/nginx --set replicaCount=3
# 롤백
helm rollback my-nginx 1
# 삭제
helm uninstall my-nginx
Chart 구조
my-app/
├── Chart.yaml # 메타데이터
├── values.yaml # 기본 값
├── templates/ # K8s YAML 템플릿
│ ├── deployment.yaml
│ ├── service.yaml
│ ├── ingress.yaml
│ ├── configmap.yaml
│ ├── _helpers.tpl # 재사용 함수
│ ├── NOTES.txt # 설치 후 메시지
│ └── tests/ # helm test
├── charts/ # 의존성 sub-chart
└── .helmignore
Chart.yaml
apiVersion: v2
name: my-app
description: My application
type: application
version: 1.0.0 # Chart 버전
appVersion: "2.5.0" # 앱 버전
dependencies:
- name: postgres
version: 12.x.x
repository: https://charts.bitnami.com/bitnami
values.yaml — 기본 값
replicaCount: 1
image:
repository: nginx
tag: 1.25
pullPolicy: IfNotPresent
service:
type: ClusterIP
port: 80
ingress:
enabled: false
hosts:
- host: chart-example.local
resources:
requests:
cpu: 100m
memory: 128Mi
템플릿 (templates/deployment.yaml)
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "my-app.fullname" . }}
labels:
{{- include "my-app.labels" . | nindent 4 }}
spec:
replicas: {{ .Values.replicaCount }}
selector:
matchLabels:
{{- include "my-app.selectorLabels" . | nindent 6 }}
template:
metadata:
labels:
{{- include "my-app.selectorLabels" . | nindent 8 }}
spec:
containers:
- name: {{ .Chart.Name }}
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
ports:
- containerPort: {{ .Values.service.port }}
resources:
{{- toYaml .Values.resources | nindent 12 }}
여기서 정말 중요한 시험 함정 — Go 템플릿 + Sprig 함수. {{ ... }} 표현, {{- ... -}} 공백 제거. nindent·toYaml 같은 Sprig 함수 자주.
Go 템플릿 핵심 문법
# 변수 참조
{{ .Values.replicaCount }}
# 파이프
{{ .Values.name | upper | quote }}
# 조건
{{ if .Values.ingress.enabled }}
...
{{ end }}
# 반복
{{ range .Values.hosts }}
- host: {{ .host }}
{{ end }}
# 기본값
{{ .Values.image.tag | default "latest" }}
# 들여쓰기
{{ toYaml .Values.resources | nindent 12 }}
# 헬퍼 함수
{{ include "my-app.fullname" . }}
_helpers.tpl
{{- define "my-app.fullname" -}}
{{- printf "%s-%s" .Release.Name .Chart.Name | trunc 63 | trimSuffix "-" -}}
{{- end -}}
{{- define "my-app.labels" -}}
app.kubernetes.io/name: {{ .Chart.Name }}
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/version: {{ .Chart.AppVersion }}
{{- end -}}
재사용 가능한 함수.
환경별 values
# 개발
helm install my-app ./my-app -f values-dev.yaml
# 운영
helm install my-app ./my-app -f values-prod.yaml
# CLI 오버라이드
helm install my-app ./my-app --set replicaCount=5 --set image.tag=v2.0
# values-prod.yaml (개발과 다른 부분만)
replicaCount: 5
resources:
requests:
cpu: 500m
memory: 512Mi
ingress:
enabled: true
hosts:
- host: api.example.com
Release · Revision
각 helm install = 하나의 Release. 각 helm upgrade = 새 Revision.
helm history my-app
# REVISION STATUS CHART DESCRIPTION
# 1 deployed my-app-1.0 Install complete
# 2 deployed my-app-1.1 Upgrade complete
# 3 deployed my-app-1.2 Upgrade complete
# 롤백
helm rollback my-app 2
여기서 시험 함정이 하나 있어요. Helm은 K8s 객체에 라벨 추가 (release name·version). Helm으로 만든 것 = kubectl get all -l app.kubernetes.io/instance=my-app.
의존성 — Sub Chart
# Chart.yaml
dependencies:
- name: postgres
version: 12.x.x
repository: https://charts.bitnami.com/bitnami
- name: redis
version: 18.x.x
repository: https://charts.bitnami.com/bitnami
helm dependency update
helm install my-app ./my-app
PostgreSQL·Redis 같은 외부 차트를 함께 설치.
Hooks — 라이프사이클
metadata:
annotations:
"helm.sh/hook": pre-install
"helm.sh/hook-weight": "1"
"helm.sh/hook-delete-policy": hook-succeeded
| Hook | 시점 |
|---|---|
| pre-install | 설치 전 |
| post-install | 설치 후 |
| pre-upgrade | 업그레이드 전 |
| post-upgrade | 업그레이드 후 |
| pre-delete | 삭제 전 |
| post-delete | 삭제 후 |
용도 — DB 마이그레이션·백업·검증.
Helm Test
# templates/tests/test-connection.yaml
apiVersion: v1
kind: Pod
metadata:
name: "{{ include "my-app.fullname" . }}-test-connection"
annotations:
"helm.sh/hook": test
spec:
containers:
- name: wget
image: busybox
command: ['wget']
args: ['{{ include "my-app.fullname" . }}:{{ .Values.service.port }}']
restartPolicy: Never
helm test my-app
디버깅·검증
# 템플릿 렌더링만 (적용 X)
helm template my-app ./my-app -f values-prod.yaml
# 실제 적용 시뮬레이션
helm install my-app ./my-app --dry-run --debug
# 차트 검증
helm lint ./my-app
Helm 저장소
# 공식 차트들
helm repo add bitnami https://charts.bitnami.com/bitnami
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
helm repo add jetstack https://charts.jetstack.io # cert-manager
# 자체 저장소 — Chart Museum 또는 OCI
helm push my-app-1.0.0.tgz oci://registry.example.com/charts
Helm vs Kustomize
| 측면 | Helm | Kustomize |
|---|---|---|
| 방식 | 템플릿 + 변수 | YAML overlay·patch |
| 학습 곡선 | 높음 (Go 템플릿) | 낮음 |
| 유연성 | 매우 높음 | 중간 |
| 패키지 | 차트 저장소·재배포 | 없음 |
| 의존성 | sub-chart | 없음 |
| 사용처 | 복잡 앱·재배포 | 환경별 단순 차이 |
여기서 정말 중요한 시험 함정 — 선택 기준:
- 외부 패키지로 배포할 차트 = Helm
- 자체 앱 + 환경별 차이만 = Kustomize
- 둘 결합도 OK (
helm template | kustomize)
Kustomize 단순 예시
# base/kustomization.yaml
resources:
- deployment.yaml
- service.yaml
# overlays/prod/kustomization.yaml
namespace: prod
bases: [../../base]
patchesStrategicMerge:
- replicas-patch.yaml
images:
- name: my-app
newTag: v2.0
kubectl apply -k overlays/prod/
운영 배포 패턴
1. GitOps + Helm
Git Repo
├── chart/
└── values/
├── dev.yaml
├── staging.yaml
└── prod.yaml
ArgoCD / Flux → Git 변경 감지 → 자동 배포
2. CI/CD 파이프라인
# 빌드 후
helm package ./chart
helm push ./chart-1.2.3.tgz oci://registry/charts
# 환경별 배포
helm upgrade --install my-app oci://registry/charts/my-app \
--version 1.2.3 \
-f values-prod.yaml \
--namespace prod
여기서 시험 함정이 하나 있어요. upgrade --install = 없으면 설치, 있으면 업그레이드. CI/CD 표준 패턴 (idempotent).
자주 쓰는 패키지
| 카테고리 | 차트 |
|---|---|
| Ingress | ingress-nginx |
| TLS 인증서 | cert-manager |
| 모니터링 | kube-prometheus-stack |
| 로깅 | loki·promtail |
| GitOps | argo-cd / flux |
| Secret | external-secrets / sealed-secrets |
| DB | postgresql·mysql·mongodb (bitnami) |
| 메시지 | kafka·rabbitmq |
| 캐시 | redis |
시험 직전 한 번 더 — 자주 헷갈리는 함정 모음
여기까지가 9편의 핵심입니다. 시험 직전 또는 실무에서 헷갈릴 때 다시 펼쳐 볼 수 있게 압축 노트로 마무리할게요.
- Helm = K8s 패키지 매니저
- 템플릿 + 변수 + 환경별 values
- Chart 구조 — Chart.yaml / values.yaml / templates/ / charts/ (sub-chart)
- 템플릿 = Go 템플릿 + Sprig 함수
{{ .Values.x }}/{{ if }} ... {{ end }}/{{ range }} ... {{ end }}{{ ... | nindent 4 }}·{{ toYaml ... }}_helpers.tpl= 재사용 함수- values 환경별 분리 —
-f values-prod.yaml또는--set - Release = install 단위 / Revision = upgrade 단위
helm history/helm rollback- 의존성 — sub-chart (PostgreSQL·Redis 등)
- Hooks — pre-install / post-install / pre-upgrade / pre-delete
- 마이그레이션·백업·검증
- 디버깅 —
helm template/helm install --dry-run --debug/helm lint - 저장소 — Bitnami·ingress-nginx·prometheus·cert-manager
- OCI registry 푸시 가능
- Helm vs Kustomize — 템플릿 vs overlay
- 외부 패키지·복잡 = Helm / 환경별 단순 차이 = Kustomize
- 둘 결합도 가능
helm upgrade --install= idempotent (CI/CD 표준)- GitOps + ArgoCD/Flux
시리즈 다른 편
- 1편 — 아키텍처·Control Plane
- 2편 — Pod
- 3편 — Workloads
- 4편 — Services·Networking
- 5편 — ConfigMap·Secret
- 6편 — Storage
- 7편 — Scaling·Scheduling
- 8편 — Security
- 9편 — Helm (현재 글)
- 10편 — 실전 (매니지드·GitOps·Observability)
공식 문서: Helm Documentation / Artifact Hub 에서 더 깊이.
다음 글(10편, 마지막)에서는 실전 — GKE/EKS, CI/CD, Observability, 운영 모범 사례까지 시리즈 마무리.