Helm #
Menyebarkan (deploy) sebuah aplikasi mikroservis tingkat produksi ke dalam kluster Kubernetes bukanlah tugas yang sederhana. Satu aplikasi biasanya tidak hanya terdiri dari satu manifest Deployment, melainkan sekumpulan manifest terikat yang saling bergantung: Deployment (workload), Service (network access), ConfigMap dan Secret (konfigurasi), HorizontalPodAutoscaler (scaling), Ingress (routing eksternal), serta ServiceAccount, Role, dan RoleBinding (RBAC). Jika kita mengelola seluruh file manifest YAML ini secara manual di setiap lingkungan (development, staging, production), kita akan terjebak dalam proses duplikasi kode yang melelahkan dan rawan memicu kesalahan konfigurasi manusia (human error). Helm hadir sebagai manajer paket (package manager) standar untuk Kubernetes yang mengabstraksikan sekumpulan manifest tersebut menjadi satu unit modular yang dapat di-package, di-version-control, dan di-deploy dengan satu perintah tunggal.
Arsitektur dan Alur Kerja Helm #
Helm bekerja di sisi client (client-side tool) sejak versi Helm 3 dirilis (menghapus komponen server-side Tiller yang memiliki masalah celah keamanan RBAC pada versi terdahulu). Helm Client berinteraksi langsung dengan Kubernetes API Server menggunakan kredensial konfigurasi lokal (kubeconfig).
flowchart TD
ChartSource["Helm Chart Source Directory (templates/, values.yaml)"] -->|"helm package"| ChartTgz["Chart Archive (.tgz File)"]
ChartTgz -->|"helm push"| OCIRegistry["OCI Container Registry (ECR / Harbor)"]
subgraph DeployCycle["Siklus Deployment (CI/CD / Developer Machine)"]
direction TB
HelmClient["Helm Client CLI"] -->|"Download Chart"| OCIRegistry
HelmClient -->|"Kompilasi: Templates + values.yaml"| YAMLOutput["Manifest YAML Teks (Plain Text)"]
YAMLOutput -->|"Kirim Payload HTTP POST"| K8sAPI["Kube-API Server"]
end
subgraph ClusterStorage["Namespace Kubernetes (Penyimpanan Keadaan)"]
direction LR
K8sResources["Active Resources (Pods, Services, Ingress)"]
ReleaseSecret["Helm Release History (Stored as Secret in target Namespace)"]
end
K8sAPI --> K8sResources
K8sAPI --> ReleaseSecret
Mekanisme Rilis dan Penyimpanan State #
Setiap kali kita menjalankan perintah helm install atau helm upgrade, Helm melakukan kompilasi antara file template manifest dengan nilai konfigurasi (values.yaml), kemudian mengirimkan payload YAML hasil kompilasi tersebut ke Kubernetes API Server untuk diterapkan.
Helm mencatat riwayat rilis (release history) kluster secara native di dalam Kubernetes. Setiap versi rilis disimpan sebagai Secret di dalam namespace target (berlabel sh.helm.release.v1.<release-name>.<version>). Informasi ini berisi seluruh snapshot manifest yang diterapkan, mempermudah proses pemulihan (rollback) secara instan tanpa perlu melacak kembali riwayat commit Git di pipa CI/CD.
Anatomi Struktur Helm Chart #
Sebuah paket Helm disebut dengan Chart. Chart adalah direktori terstruktur yang memisahkan antara template manifest dengan nilai-nilai variabel dinamis.
Struktur Direktori Helm Chart Standar:
my-app/
├── Chart.yaml # Metadata utama chart (nama, deskripsi, versi chart, versi app)
├── values.yaml # Nilai konfigurasi default (dapat di-override saat deployment)
├── charts/ # Sub-charts/dependencies yang dibutuhkan (file .tgz)
├── templates/ # Direktori file template manifest Kubernetes
│ ├── _helpers.tpl # Template helper global (blok define template yang dapat digunakan kembali)
│ ├── deployment.yaml # Template Deployment aplikasi
│ ├── service.yaml # Template Service
│ ├── ingress.yaml # Template Ingress
│ ├── NOTES.txt # Skrip teks yang otomatis tercetak setelah instalasi sukses
└── .helmignore # Pola file yang diabaikan saat chart di-package
Penulisan Chart.yaml (SemVer Versioning) #
File Chart.yaml berisi identitas dan dependensi chart. Kita harus memisahkan secara jelas antara versi kemasan chart dengan versi kode aplikasi.
apiVersion: v2 # Wajib v2 untuk penggunaan Helm 3
name: billing-service
description: Layanan pemrosesan pembayaran mikroservis e-commerce.
type: application # 'application' untuk deployable chart, 'library' untuk helper shared chart
version: 1.4.2 # Versi Chart (Mengikuti SemVer - dinaikkan jika struktur template berubah)
appVersion: "2.1.0" # Versi Aplikasi (Mencerminkan tag image kontainer docker aplikasi)
dependencies:
- name: redis
version: "17.3.0"
repository: "https://charts.bitnami.com/bitnami"
condition: redis.enabled # Hanya diinstal jika parameter redis.enabled bernilai true di values.yaml
Mesin Template Go dan Pustaka Fungsi Sprig #
Helm memanfaatkan mesin template teks bawaan bahasa Go (text/template) yang diperkaya dengan fungsi-fungsi manipulasi string dari pustaka Sprig.
File values.yaml: Abstraksi Nilai Konfigurasi #
Semua konfigurasi yang bervariasi antar lingkungan (seperti dev, staging, prod) tidak boleh ditulis keras (hardcoded) di dalam file template manifest. Konfigurasi tersebut wajib didefinisikan sebagai variabel di dalam values.yaml.
# File: values.yaml (Nilai default)
replicaCount: 2
image:
repository: registry.company.com/apps/billing
pullPolicy: IfNotPresent
tag: "" # Jika kosong, default ke appVersion di Chart.yaml
service:
type: ClusterIP
port: 8080
resources:
limits:
cpu: "500m"
memory: "512Mi"
requests:
cpu: "200m"
memory: "256Mi"
ingress:
enabled: false
hosts:
- host: billing.company.com
paths:
- path: /
pathType: ImplementationSpecific
Implementasi Templating Manifest (templates/deployment.yaml)
#
Kita menulis template manifest menggunakan sintaksis evaluasi double curly braces {{ }}.
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "billing.fullname" . }}
namespace: {{ .Release.Namespace }}
labels:
# Sisipkan label standar yang didefinisikan di _helpers.tpl
{{- include "billing.labels" . | nindent 4 }}
spec:
replicas: {{ .Values.replicaCount }}
selector:
matchLabels:
{{- include "billing.selectorLabels" . | nindent 6 }}
template:
metadata:
labels:
{{- include "billing.selectorLabels" . | nindent 8 }}
spec:
containers:
- name: {{ .Chart.Name }}
# Default tag ke appVersion jika tag kosong di values.yaml
image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
ports:
- containerPort: 8080
name: http
resources:
# Salin blok resources YAML secara utuh dengan penataan indentasi 10 spasi
{{- toYaml .Values.resources | nindent 10 }}
Pembuatan Template Helpers (_helpers.tpl)
#
Blok template pembantu (helper templates) digunakan untuk membungkus kode label dan penamaan standard agar tidak terjadi duplikasi penulisan kode manifest.
[!IMPORTANT] Perbedaan Kritis
templatevsinclude: Di dalam mesin template Helm, kita harus menggunakan fungsiincludealih-alih perintah bawaantemplatesaat memanggil helper template. Perintahtemplatetidak dapat dialirkan (pipeline) ke fungsi manipulasi string lainnya sepertinindent(new indent). Penggunaanincludememungkinkan kita mengatur tata letak spasi YAML secara akurat.
# File: templates/_helpers.tpl
{{/*
1. Menentukan nama lengkap aplikasi (Release Name + Chart Name)
*/}}
{{- define "billing.fullname" -}}
{{- printf "%s-%s" .Release.Name .Chart.Name | trunc 63 | trimSuffix "-" -}}
{{- end -}}
{{/*
2. Label standar untuk standarisasi monitoring dan compliance
*/}}
{{- define "billing.labels" -}}
helm.sh/chart: {{ printf "%s-%s" .Chart.Name .Chart.Version }}
app.kubernetes.io/name: {{ .Chart.Name }}
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
{{- end -}}
{{/*
3. Selector labels untuk pencocokan service dan pod
*/}}
{{- define "billing.selectorLabels" -}}
app.kubernetes.io/name: {{ .Chart.Name }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end -}}
Perintah Operasional Helm Tingkat Produksi #
Berikut adalah daftar perintah baris perintah (CLI) Helm yang wajib diintegrasikan ke dalam pipa CI/CD atau digunakan oleh administrator kluster:
1. Uji Coba Kompilasi dan Dry-Run (Deteksi Dini) #
Sebelum menerapkan perubahan di produksi, kita dapat melihat hasil rendering YAML teks secara lokal tanpa menyentuh kluster untuk memeriksa sintaksis spasi YAML.
# Uji rendering manifest secara lokal
helm template billing-release ./my-chart --values values-production.yaml
# Uji rendering langsung ke API Server dengan mode dry-run (validasi schema API)
helm install billing-release ./my-chart --values values-production.yaml --dry-run
2. Pengecekan Selisih Konfigurasi (Helm Diff Plugin) #
Gunakan plugin helm-diff untuk melihat selisih konfigurasi persis (diff output) antara manifest yang sedang berjalan di produksi dengan manifest baru yang akan di-deploy.
# Instalasi plugin diff
helm plugin install https://github.com/databus23/helm-diff
# Bandingkan perubahan sebelum melakukan upgrade
helm diff upgrade billing-release ./my-chart --values values-production.yaml
3. Penerapan Rilis Aman (Safe Deployment Flags) #
Di tingkat produksi, kita harus mengonfigurasi mekanisme proteksi otomatis agar jika kontainer baru mengalami crash-loop, sistem secara otomatis melakukan pembatalan (rollback) ke revisi sehat sebelumnya.
# Upgrade dengan proteksi otomatis
helm upgrade billing-release ./my-chart \
--namespace production \
--values values-production.yaml \
--set image.tag=v2.1.2 \
--wait \ # Tunggu hingga semua Pod berstatus Ready
--timeout 10m0s \ # Batasi waktu tunggu maksimal 10 menit
--atomic \ # Hapus resource baru dan rollback otomatis jika proses gagal/timeout
--cleanup-on-fail # Bersihkan sisa resource yatim jika upgrade gagal
Menyimpan Helm Chart di OCI Registry (Helm 3.8+) #
Di masa lalu, mendistribusikan Helm Chart membutuhkan server repositori khusus dengan file index.yaml. Mulai dari Helm 3.8+, kita dapat memperlakukan Helm Chart sebagai objek OCI (OCI Artifacts) dan menyimpannya di dalam kontainer registry modern yang sama dengan image aplikasi kita (seperti Harbor, AWS ECR, atau GCP Artifact Registry).
# 1. Login ke OCI Container Registry menggunakan kredensial resmi
helm registry login registry.company.com -u ci-user -p secret-token
# 2. Kemas direktori chart menjadi file arsip terkompresi (.tgz)
helm package ./my-chart
# Menghasilkan file: billing-service-1.4.2.tgz
# 3. Push file arsip ke OCI registry menggunakan skema url oci://
helm push billing-service-1.4.2.tgz oci://registry.company.com/helm-charts
Untuk menginstalnya kembali dari OCI registry:
helm install billing-release oci://registry.company.com/helm-charts/billing-service --version 1.4.2 -n production
Anti-Pattern dalam Praktik Manajemen Helm Chart #
Hindari kesalahan operasional berikut saat membangun dan mengelola Helm Chart:
1. Modifikasi Manual Pasca-Deployment (Ad-Hoc Drifts) #
Melakukan perubahan manifest secara langsung menggunakan perintah kubectl edit atau kubectl patch setelah aplikasi di-deploy melalui Helm.
Risiko Modifikasi Manual:
- State di dalam Kubernetes API Server menjadi tidak sinkron (*drift*) dengan state rilis Helm.
- Saat proses 'helm upgrade' berikutnya dijalankan, Helm akan menimpa seluruh perubahan manual tersebut, menyebabkan hilangnya patch konfigurasi darurat secara tiba-tiba di produksi.
✓ SOLUSI: Seluruh perubahan konfigurasi harus melalui values.yaml dan di-commit ke Git (GitOps flow).
2. Menyimpan Secret Plain-Text di values.yaml #
# ANTI-PATTERN: Menyimpan password database plain-text langsung di values.yaml
db:
password: "super-secret-password-123" # JANGAN: File ini disimpan di Git repositori publik/internal
# ==============================================================================
# BENAR: Menggunakan referensi eksternal atau enkripsi SOPS.
# Kita hanya menyimpan referensi nama Secret yang dibuat secara aman oleh operator eksternal (ESO).
db:
secretName: billing-database-credentials
Checklist Audit Helm Chart Produksi #
Gunakan daftar checklist berikut sebelum merilis Helm Chart Anda ke repositori pusat:
STRUKTUR & TATA LETAK KODE:
□ File Chart.yaml mendefinisikan versi chart (version) dan versi aplikasi (appVersion) secara terpisah.
□ Versi chart ditingkatkan secara konsisten mengikuti aturan Semantic Versioning (SemVer).
□ Variabel dinamis tidak di-hardcode di folder templates; melainkan dideklarasikan di values.yaml.
□ Helper templates (_helpers.tpl) digunakan untuk standarisasi nama dan labels global.
□ Penggunaan helper template dipanggil menggunakan fungsi 'include', bukan perintah 'template'.
PENGAMANAN & PROTEKSI OPERASIONAL:
□ Nilai rahasia (Secret) tidak disimpan secara plain-text di file values.yaml.
□ Pipa CI/CD menggunakan perintah 'helm upgrade' dengan flag '--atomic' dan '--wait'.
□ Menggunakan plugin 'helm-diff' di dalam pipeline untuk memvalidasi perubahan sebelum deployment.
□ Helm Chart dikemas dan didistribusikan menggunakan OCI Registry resmi.
□ Perubahan manifest tidak pernah dilakukan menggunakan kubectl edit secara langsung di produksi.
Ringkasan #
- Helm Mengelola Kompleksitas Manifest — Abstraksikan kumpulan manifest Kubernetes menjadi satu paket modular (Chart) untuk mempermudah replikasi antar lingkungan (Dev/Prod).
- Gunakan include untuk Tata Letak Spasi — Selalu gunakan fungsi
includeuntuk memanggil helper template di_helpers.tplagar format indentasi YAMLnindentbekerja sempurna.- Aktifkan Proteksi –atomic — Pastikan flag
--atomic,--wait, dan--timeoutselalu aktif saat rilis di produksi agar Helm memicu auto-rollback jika pod baru gagal start.- Pisahkan Chart Version dan App Version — Pahami perbedaannya;
versionmewakili perubahan file template Helm, sedangkanappVersionmewakili tag kontainer image aplikasi.- Terapkan OCI Registry untuk Chart — Hilangkan infrastruktur repositori chart tambahan; simpan arsip
.tgzHelm secara native di dalam OCI Container Registry.- Hindari Ad-Hoc Drift Pasca Deploy — Seluruh modifikasi manifest kluster wajib dideklarasikan melalui
values.yamldan dilarang keras melakukankubectl editmanual di produksi.
← Sebelumnya: Anti-Pattern Observability Berikutnya: Kustomize →