Skip to content

Mastering Helm Charts: Stop Copy-Pasting YAML

🛠️ Góc nhìn Senior DevOps Tooling Engineer - HPN

Module này được viết với triết lý "Don't Repeat Yourself". Mục tiêu: Loại bỏ việc copy-paste YAML vô tận và quản lý Kubernetes resources một cách thông minh.

🔥 Vấn Đề: "YAML Hell"

Tình huống thực tế

Bạn có 3 môi trường: Dev, Staging, Production. Chúng gần như 99% giống nhau, chỉ khác:

Môi trườngreplicasimageTagresources.limits.memory
Dev1latest256Mi
Staging2v1.2.3512Mi
Production5v1.2.31Gi
text
❌ ANTI-PATTERN: Copy-Paste Nightmare

k8s/
├── dev/
│   ├── deployment.yaml      # 👈 99% giống staging
│   ├── service.yaml
│   └── configmap.yaml
├── staging/
│   ├── deployment.yaml      # 👈 Copy từ dev, sửa vài dòng
│   ├── service.yaml
│   └── configmap.yaml
└── production/
    ├── deployment.yaml      # 👈 Copy từ staging, sửa vài dòng
    ├── service.yaml
    └── configmap.yaml

Vấn đề:
- Sửa 1 chỗ → phải sửa 3 file
- Dễ quên sync → Drift between environments
- Review code kiểu gì? Diff 3 file 99% giống nhau?

💀 HẬU QUẢ THỰC TẾ

bash
# Dev team sửa port trong dev/deployment.yaml
# Quên sửa ở staging và production
# 3 tuần sau: "Tại sao Production vẫn dùng port cũ?"

🍪 Giải Pháp: Helm Templates

Helm là gì?

Helm = Package Manager for Kubernetes (như apt cho Ubuntu, npm cho Node.js)

💡 PHÉP SO SÁNH: KHUÔN BÁNH (Cookie Cutter)

  • Template (.tpl files) = Khuôn bánh - Định nghĩa hình dạng
  • Values (values.yaml) = Bột bánh - Thay đổi theo ý muốn
  • Chart = Bộ khuôn hoàn chỉnh - Template + giá trị mặc định

Cùng 1 khuôn, thay đổi bột (values) → ra bánh khác nhau!

Một file, nhiều môi trường

yaml
# ✅ HELM WAY: 1 Template, 3 Values files

charts/myapp/
├── Chart.yaml           # ID Card của chart
├── values.yaml          # Default values
├── values-dev.yaml      # Override cho Dev
├── values-staging.yaml  # Override cho Staging
├── values-prod.yaml     # Override cho Production
└── templates/
    ├── deployment.yaml  # Template với {{ .Values.xxx }}
    └── service.yaml

📦 Core Components

1. Chart.yaml - The ID Card

yaml
# Chart.yaml - Metadata của chart
apiVersion: v2
name: myapp
description: Backend API service cho HPN Platform
type: application
version: 1.2.0        # Version của CHART (thay đổi khi sửa chart)
appVersion: "3.5.1"   # Version của APPLICATION (image tag)

# Dependencies (optional)
dependencies:
  - name: postgresql
    version: "12.x.x"
    repository: "https://charts.bitnami.com/bitnami"
FieldÝ nghĩa
nameTên chart (dùng trong helm install)
versionVersion của chart structure
appVersionVersion của ứng dụng bên trong
dependenciesCharts khác mà chart này cần

2. values.yaml - The Configuration

yaml
# values.yaml - Default configuration
# ĐÂY LÀ FILE DUY NHẤT DEVS CẦN QUAN TÂM

replicaCount: 2

image:
  repository: gcr.io/hpn/myapp
  tag: "latest"
  pullPolicy: IfNotPresent

resources:
  limits:
    cpu: 500m
    memory: 512Mi
  requests:
    cpu: 100m
    memory: 128Mi

service:
  type: ClusterIP
  port: 8080

# Feature flags
features:
  enableCache: true
  debugMode: false

3. templates/ - The Logic Engine

yaml
# templates/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{ .Release.Name }}-{{ .Chart.Name }}
  labels:
    app: {{ .Chart.Name }}
    version: {{ .Chart.AppVersion }}
spec:
  replicas: {{ .Values.replicaCount }}  # 👈 Từ values.yaml
  selector:
    matchLabels:
      app: {{ .Chart.Name }}
  template:
    metadata:
      labels:
        app: {{ .Chart.Name }}
    spec:
      containers:
        - name: {{ .Chart.Name }}
          image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
          ports:
            - containerPort: {{ .Values.service.port }}
          resources:
            {{- toYaml .Values.resources | nindent 12 }}
          {{- if .Values.features.debugMode }}
          env:
            - name: DEBUG
              value: "true"
          {{- end }}

🔧 Template Syntax Essentials

Variables & Objects

yaml
# Truy cập values
{{ .Values.replicaCount }}           # → 2
{{ .Values.image.repository }}       # → gcr.io/hpn/myapp

# Built-in objects
{{ .Release.Name }}                  # → tên release (helm install NAME)
{{ .Release.Namespace }}             # → namespace được deploy
{{ .Chart.Name }}                    # → tên chart từ Chart.yaml
{{ .Chart.AppVersion }}              # → appVersion từ Chart.yaml

Conditionals: if

yaml
# Chỉ thêm resources nếu được định nghĩa
{{- if .Values.resources }}
resources:
  {{- toYaml .Values.resources | nindent 2 }}
{{- end }}

# If-else
{{- if eq .Values.environment "production" }}
replicas: 5
{{- else }}
replicas: 1
{{- end }}

Loops: range

yaml
# values.yaml
env:
  - name: DB_HOST
    value: localhost
  - name: CACHE_TTL
    value: "300"

# template
env:
{{- range .Values.env }}
  - name: {{ .name }}
    value: {{ .value | quote }}
{{- end }}

Scope: with

yaml
# Thay vì lặp lại .Values.image nhiều lần
{{- with .Values.image }}
image: "{{ .repository }}:{{ .tag }}"
imagePullPolicy: {{ .pullPolicy }}
{{- end }}

🚀 Essential Commands

Install, Upgrade, Rollback

bash
# 🆕 Install chart lần đầu
helm install myapp ./charts/myapp \
  --namespace production \
  --values values-prod.yaml

# 🔄 Upgrade (thay đổi values hoặc chart)
helm upgrade myapp ./charts/myapp \
  --namespace production \
  --values values-prod.yaml

# ⏪ Rollback về revision trước
helm rollback myapp 1 --namespace production

# 📜 Xem history
helm history myapp --namespace production

⏰ HELM = TIME MACHINE CHO APPS

text
Revision 1: v1.0.0 (deployed 3 days ago)
Revision 2: v1.1.0 (deployed 2 days ago)  ← Bug!
Revision 3: v1.0.0 (rollback, deployed now) ✅

helm rollback myapp 1  →  Quay về Revision 1 trong 5 giây

Debug & Dry-run

bash
# 🔍 Xem YAML sẽ được generate (không apply)
helm template myapp ./charts/myapp \
  --values values-prod.yaml

# 🧪 Dry-run với cluster validation
helm install myapp ./charts/myapp \
  --dry-run --debug \
  --values values-prod.yaml

# ✅ Validate chart syntax
helm lint ./charts/myapp

Managing Releases

bash
# Liệt kê releases
helm list --all-namespaces

# Xem values đang được sử dụng
helm get values myapp --namespace production

# Xóa release
helm uninstall myapp --namespace production

🏁 Quick Start: helm create

⚠️ LỜI KHUYÊN TỪ PRODUCTION

"Đừng viết chart từ đầu. Dùng helm create rồi dọn dẹp."

bash
# Tạo chart scaffold
helm create myapp

# Kết quả:
myapp/
├── Chart.yaml
├── values.yaml
├── charts/              # Dependencies
├── templates/
   ├── NOTES.txt        # Post-install message
   ├── _helpers.tpl     # Template helpers
   ├── deployment.yaml
   ├── hpa.yaml
   ├── ingress.yaml
   ├── service.yaml
   └── serviceaccount.yaml
└── .helmignore

Quy trình làm việc


📊 Tổng Kết

ComponentVai tròAi quản lý?
Chart.yamlMetadata (name, version)DevOps Engineer
values.yamlDefault configDevOps Engineer
values-{env}.yamlEnvironment overridesDev Team / DevOps
templates/YAML templatesDevOps Engineer

Essential Commands Cheatsheet

CommandMục đích
helm create <name>Tạo chart skeleton
helm install <release> <chart>Deploy chart lần đầu
helm upgrade <release> <chart>Cập nhật deployment
helm rollback <release> <rev>Quay về revision cũ
helm template <chart>Preview YAML output
helm lint <chart>Validate chart
helm list -ALiệt kê tất cả releases

⚠️ QUY TẮC VÀNG TẠI HPN

  1. Values là thứ duy nhất Devs cần sửa - Templates là "black box" do Platform team quản lý
  2. Không bao giờ hardcode - Mọi thứ có thể thay đổi cần đưa vào values
  3. Luôn dùng helm diff trước khi upgrade (plugin: helm-diff)
  4. Version control cả Chart - Chart cũng là code, cần review như code

🔗 Liên kết