10 KiB
10 KiB
id, title, category, status, source_trust_level, verification_status, created_at, updated_at, tags, tech_stack, applied_in, aliases
| id | title | category | status | source_trust_level | verification_status | created_at | updated_at | tags | tech_stack | applied_in | aliases | |||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| devops-helm-deep | Helm 깊이 — Chart / Templating / Hook | Coding | draft | B | conceptual | 2026-05-09 | 2026-05-09 |
|
|
|
Helm Deep
Kubernetes package manager. Chart = template + values. 환경별 다른 values + dependency + hook + rollback. 큰 프로덕션 K8s 의 표준.
📖 핵심 개념
- Chart: package (templates / values / metadata).
- Values: 환경별 config.
- Template: Go template + Helm functions.
- Release: cluster 안 deployed instance.
💻 코드 패턴
Chart 구조
my-app/
├── Chart.yaml
├── values.yaml
├── values-prod.yaml
├── values-dev.yaml
├── templates/
│ ├── deployment.yaml
│ ├── service.yaml
│ ├── ingress.yaml
│ ├── configmap.yaml
│ ├── secret.yaml
│ ├── serviceaccount.yaml
│ ├── _helpers.tpl
│ └── tests/
│ └── connection-test.yaml
└── charts/ # dependency
Chart.yaml
apiVersion: v2
name: my-app
description: Acme API service
version: 1.0.0 # chart version
appVersion: "1.5.0" # app version
type: application
dependencies:
- name: postgresql
version: 13.2.0
repository: https://charts.bitnami.com/bitnami
condition: postgresql.enabled
- name: redis
version: 18.0.0
repository: https://charts.bitnami.com/bitnami
values.yaml (default)
replicaCount: 2
image:
repository: ghcr.io/myorg/my-app
tag: "" # default = appVersion
pullPolicy: IfNotPresent
service:
type: ClusterIP
port: 80
ingress:
enabled: true
className: nginx
hosts:
- host: api.example.com
resources:
requests:
cpu: 100m
memory: 256Mi
limits:
cpu: 500m
memory: 512Mi
postgresql:
enabled: true
auth:
username: app
database: app
env:
NODE_ENV: production
values-prod.yaml (override)
replicaCount: 5
resources:
requests:
cpu: 500m
memory: 1Gi
limits:
cpu: 2
memory: 4Gi
postgresql:
enabled: false # External RDS
env:
DATABASE_URL: postgresql://prod...
Deployment template
# 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 | default .Chart.AppVersion }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
ports:
- containerPort: 8080
env:
{{- range $k, $v := .Values.env }}
- name: {{ $k }}
value: {{ $v | quote }}
{{- end }}
resources:
{{- toYaml .Values.resources | nindent 12 }}
livenessProbe:
httpGet:
path: /healthz
port: 8080
readinessProbe:
httpGet:
path: /readyz
port: 8080
Helpers (_helpers.tpl)
{{/* Common labels */}}
{{- define "my-app.labels" -}}
helm.sh/chart: {{ include "my-app.chart" . }}
app.kubernetes.io/name: {{ .Chart.Name }}
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/version: {{ .Chart.AppVersion }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
{{- end }}
{{/* Selector labels */}}
{{- define "my-app.selectorLabels" -}}
app.kubernetes.io/name: {{ .Chart.Name }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end }}
{{/* Fullname */}}
{{- define "my-app.fullname" -}}
{{- if .Values.fullnameOverride }}
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
{{- else }}
{{- printf "%s-%s" .Release.Name .Chart.Name | trunc 63 | trimSuffix "-" }}
{{- end }}
{{- end }}
명령
# Render local
helm template my-app . -f values-prod.yaml
# Lint
helm lint .
# Install
helm install my-app . -f values-prod.yaml -n prod
# Upgrade
helm upgrade my-app . -f values-prod.yaml -n prod
# Diff (변경 미리)
helm plugin install https://github.com/databus23/helm-diff
helm diff upgrade my-app . -f values-prod.yaml -n prod
# Rollback
helm rollback my-app 5 -n prod # revision 5
# Uninstall
helm uninstall my-app -n prod
Conditional render
{{- if .Values.ingress.enabled }}
apiVersion: networking.k8s.io/v1
kind: Ingress
...
{{- end }}
{{- if .Values.podAnnotations }}
annotations:
{{- toYaml .Values.podAnnotations | nindent 4 }}
{{- end }}
Loop
spec:
template:
spec:
containers:
{{- range .Values.sidecars }}
- name: {{ .name }}
image: {{ .image }}
{{- end }}
Secret (sealed / external)
# templates/secret.yaml
apiVersion: v1
kind: Secret
metadata:
name: {{ include "my-app.fullname" . }}
type: Opaque
stringData:
{{- range $k, $v := .Values.secrets }}
{{ $k }}: {{ $v | quote }}
{{- end }}
⚠️ Secret in values.yaml prod = bad. Sealed Secrets / External Secrets Operator.
Hooks (lifecycle)
# Pre-install / pre-upgrade — DB migration
apiVersion: batch/v1
kind: Job
metadata:
name: {{ include "my-app.fullname" . }}-migrate
annotations:
"helm.sh/hook": pre-upgrade,pre-install
"helm.sh/hook-weight": "1"
"helm.sh/hook-delete-policy": before-hook-creation
spec:
template:
spec:
containers:
- name: migrate
image: ...
command: ["yarn", "migrate:up"]
restartPolicy: Never
→ Helm install / upgrade 전 자동 migration.
Test
# templates/tests/connection.yaml
apiVersion: v1
kind: Pod
metadata:
name: "{{ .Release.Name }}-test-connection"
annotations:
"helm.sh/hook": test
spec:
containers:
- name: wget
image: busybox
command: ['wget', '{{ include "my-app.fullname" . }}:{{ .Values.service.port }}/healthz']
restartPolicy: Never
helm test my-app
Dependency
# Chart.yaml
dependencies:
- name: postgresql
version: ~13.0.0
repository: oci://registry-1.docker.io/bitnamicharts
helm dependency update
helm install my-app . -f values.yaml
→ Postgres 자동 같이 install.
Helmfile (multiple chart)
# helmfile.yaml
releases:
- name: my-app
namespace: prod
chart: ./charts/my-app
values: [values-prod.yaml]
- name: monitoring
namespace: monitoring
chart: prometheus-community/kube-prometheus-stack
values: [monitoring-values.yaml]
helmfile sync
helmfile diff
→ 여러 chart 한 번에.
Multi-environment
values.yaml # baseline / dev
values-staging.yaml # staging
values-prod.yaml # prod
helm upgrade my-app . -f values-staging.yaml -n staging
helm upgrade my-app . -f values-prod.yaml -n prod
Chart museum / OCI registry
# Push to OCI
helm package .
helm push my-app-1.0.0.tgz oci://registry.example.com/charts
# Install from OCI
helm install my-app oci://registry.example.com/charts/my-app --version 1.0.0
Sub-chart override
# 자식 chart 의 values
postgresql:
primary:
persistence:
size: 100Gi
auth:
database: app
Common functions
{{ .Values.x | default "fallback" }}
{{ .Values.x | quote }}
{{ .Values.x | nindent 4 }}
{{ tpl .Values.x . }} # template within value
{{ include "common.template" . }}
{{ required "x is required" .Values.x }}
{{ printf "%s-%s" .a .b }}
{{ toYaml .Values.complex | nindent 4 }}
{{ b64enc "secret" }}
{{ randAlphaNum 32 }}
Values schema validation
// values.schema.json
{
"$schema": "https://json-schema.org/draft-07/schema#",
"properties": {
"replicaCount": { "type": "integer", "minimum": 1 },
"image": {
"type": "object",
"required": ["repository"],
"properties": {
"repository": { "type": "string" },
"tag": { "type": "string" }
}
}
},
"required": ["replicaCount"]
}
→ helm install 시 자동 검증.
CI
- run: helm lint .
- run: helm template . -f values-prod.yaml | kubectl --dry-run=server apply -f -
- run: helm upgrade --install my-app . -f values-prod.yaml -n prod --atomic --timeout 5m
--atomic flag
helm upgrade --install --atomic
→ 실패 시 자동 rollback. 안전.
Chart vs Kustomize
Helm: Template engine. Complex logic.
Kustomize: Overlay (patch) — declarative, no logic.
KCL / CUE: New schema lang.
→ Helm 가 가장 인기. Kustomize 가 단순.
ArgoCD + Helm (GitOps)
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: my-app
spec:
source:
repoURL: https://github.com/myorg/charts
chart: my-app
targetRevision: 1.0.0
helm:
valueFiles: [values-prod.yaml]
destination:
server: https://kubernetes.default.svc
namespace: prod
→ Git = truth. Argo 가 sync.
🤔 의사결정 기준
| 상황 | 추천 |
|---|---|
| K8s app 배포 | Helm |
| 단순 / overlay | Kustomize |
| Multi-cluster / GitOps | ArgoCD + Helm |
| 매우 dynamic | Helm + Helmfile |
| 사내 chart 공유 | OCI registry |
| Public chart | Artifact Hub |
❌ 안티패턴
- Secret in values.yaml + git: leak.
- --atomic 없이 prod: 실패 시 broken state.
- Chart version + appVersion 같음: chart 변경도 app version bump 필요.
- Single huge values.yaml: 분리.
- Hook 가 idempotent X: 재시도 시 깨짐.
- No values.schema: 잘못된 values 통과.
- 모든 env 같은 chart: dev / prod 차이 안 됨.
🤖 LLM 활용 힌트
- Chart + values per env + atomic upgrade.
- Sealed Secrets / External Secrets.
- ArgoCD GitOps.
- Helmfile 여러 chart.