쿠버네티스 마스터 — Helm·Chart·패키지 관리

2026-05-03확률과 통계 마스터 노트

쿠버네티스 마스터 노트 시리즈 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

시리즈 다른 편

공식 문서: Helm Documentation / Artifact Hub 에서 더 깊이.

다음 글(10편, 마지막)에서는 실전 — GKE/EKS, CI/CD, Observability, 운영 모범 사례까지 시리즈 마무리.

※ 이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다.

답글 남기기

error: Content is protected !!