Menggunakan Helm sebagai library Go, bukan sekadar CLI: inisialisasi action client, instalasi dan upgrade release secara programatik, listing release, dan rendering template — dasar untuk membangun operator, tools platform engineering, dan self-service portal, plus overview language bindings.

Setelah di episode 22 sebelumnya kita membahas Helm plugins — memperluas CLI Helm dengan perintah kustom — pada episode kali ini kita mengambil langkah lebih dalam: menggunakan Helm sebagai library Go di dalam program kalian sendiri. Selama ini kita memanggil Helm dari luar — lewat terminal, skrip, atau pipeline. Namun Helm 3 dibangun sebagai library Go yang nyata, dan CLI-nya (helm) hanyalah salah satu "klien" dari library tersebut. Ketika kalian memanggil helm upgrade, sebenarnya kalian menjalankan fungsi Go dari package helm.sh/helm/v3/pkg/action.
Mengapa ini penting? Karena ada kelas masalah yang tidak bisa diselesaikan dengan memanggil CLI:
helm sama sekali.Bayangkan Helm CLI sebagai mesin kendaraan, dan Helm SDK sebagai mesin yang sama, tanpa bodi dan dashboard — kalian bisa memasangnya ke kendaraan apa pun yang kalian bangun sendiri. Semua fitur yang kalian pelajari 22 episode — install, upgrade, rollback, template, values precedence — tersedia sebagai fungsi Go yang bisa kalian panggil dari kode.
Penting: episode ini sengaja high-level dan praktis, bukan tur mendalam ke dalam kode sumber Helm. Tujuannya agar kalian tahu apa yang bisa dilakukan, mengapa melakukannya programatik, dan bagaimana memulai — bukan untuk memahami setiap baris implementasi Helm.
Package Go Helm terbagi menjadi beberapa bagian yang masing-masing punya tanggung jawab. Yang perlu kalian kenali sebagai pengguna SDK:
pkg/action — API tingkat tinggi untuk operasi user-facing: action.NewInstall, action.NewUpgrade, action.NewUninstall, action.NewList. Inilah yang paling sering dipakai, karena ini adalah versi programatik dari perintah CLI.pkg/cli — helper untuk membangun environment standar: membaca kubeconfig, namespace, dan konfigurasi koneksi cluster. Ini setara dengan "bagaimana Helm tahu harus bicara ke cluster mana".pkg/chart dan pkg/chart/loader — struktur data chart dan cara memuatnya (dari direktori, tarball, atau registry).pkg/action + pkg/release — aksi konkret dan representasi release (status, manifest, values).pkg/engine — mesin rendering template Go.Mentality yang harus dibentuk: SDK Helm bukan "menjalankan perintah helm dari Go", melainkan "membangun objek aksi, mengonfigurasinya, lalu mengeksekusinya terhadap cluster". Perbedaannya halus tapi penting — dengan SDK kalian mengendalikan seluruh lifecycle secara langsung, bukan sekadar memunculkan subproses.
Langkah pertama setiap program yang memakai SDK Helm adalah membangun action.Configuration — objek yang menghubungkan aksi dengan cluster, penyimpanan release, dan logger. Pola standarnya:
package main
import (
"context"
"fmt"
"log"
"helm.sh/helm/v3/pkg/action"
"helm.sh/helm/v3/pkg/chart/loader"
"helm.sh/helm/v3/pkg/cli"
"k8s.io/cli-runtime/pkg/genericclioptions"
)
func main() {
settings := cli.New()
// 1. Bangun konfigurasi aksi yang terhubung ke cluster
config := new(action.Configuration)
if err := config.Init(settings.RESTClientGetter(), "myapp", "secrets", log.Printf); err != nil {
log.Fatalf("gagal inisialisasi konfigurasi: %v", err)
}
// 2. Definisikan aksi install dan konfigurasinya
install := action.NewInstall(config)
install.Namespace = "myapp"
install.ReleaseName = "myapp"
install.Wait = true
install.Timeout = 10 * 60 * 1e9
// 3. Muat chart dari direktori
chart, err := loader.Load("./charts/myapp")
if err != nil {
log.Fatalf("gagal memuat chart: %v", err)
}
// 4. Eksekusi install terhadap cluster
rel, err := install.Run(chart, map[string]interface{}{
"replicaCount": 3,
"image": map[string]interface{}{
"tag": "1.24.0",
},
})
if err != nil {
log.Fatalf("instalasi gagal: %v", err)
}
fmt.Printf("Release %q terinstall (status: %s)\n", rel.Name, rel.Info.Status)
}Mari bedah langkah demi langkah. Langkah 1 membangun action.Configuration — perhatikan settings.RESTClientGetter() yang menghasilkan koneksi dari kubeconfig yang sama yang dipakai kubectl. Ini berarti program kalian otomatis menghormati konteks, namespace, dan credential cluster yang sudah dikonfigurasi. Parameter kedua ("myapp") adalah namespace untuk penyimpanan state release, dan "secrets" memilih backend penyimpanan release Helm 3.
Langkah 2 adalah action.NewInstall(config) — objek install adalah versi programatik dari flag-flag helm install: Wait, Timeout, Atomic, DryRun, semuanya field struct. Langkah 3 memuat chart dari direktori lewat loader.Load. Langkah 4 adalah jantungnya: install.Run(chart, values) — parameter kedua adalah map Go yang setara dengan nilai --set dan file -f yang kalian kenal. Perhatikan nilai bisa berupa map[string]interface{} bersarang — inilah cara programatik menyalurkan values.
Ada dua detail pada contoh di atas yang patut diperhatikan karena membedakan pemakaian SDK dari CLI. Pertama, install.Timeout ditulis sebagai 10 * 60 * 1e9 — Go memakai satuan nanosecond untuk durasi, jadi ekspresi itu adalah 10 menit dalam nanodetik; dalam praktik nyata kebanyakan orang menulis 10 * time.Minute dengan import time agar terbaca. Kedua, error dari Run membawa informasi lebih kaya daripada output CLI: selain pesan, kalian bisa mengakses rel.Info.Description atau status untuk logika programatik — misalnya menentukan apakah kegagalan layak di-retry, di-rollback, atau perlu dihentikan. Di sinilah SDK menang: keputusan itu bisa dikodekan, bukan diserahkan ke mata manusia yang membaca log.
Note
Values precedence sama seperti CLI. Nilai yang kalian berikan langsung ke Run menimpa values bawaan chart, dan untuk menimpa dengan file kalian tetap bisa memakai loader/values.Options — misalnya values.Options{ValueFiles: []string{"deploy/values-prod.yaml"}} yang kemudian di-merge. Seluruh aturan prioritas dari episode 6 tetap berlaku; yang berubah hanyalah mediumnya: dari file dan flag menjadi objek Go.
Pola yang sama berlaku untuk semua operasi — buat objek aksi, konfigurasikan, jalankan. Untuk upgrade:
upgrade := action.NewUpgrade(config)
upgrade.Namespace = "myapp"
upgrade.Wait = true
upgrade.Timeout = 10 * 60 * 1e9
chart, _ := loader.Load("./charts/myapp")
rel, err := upgrade.Run("myapp", chart, map[string]interface{}{
"replicaCount": 6,
})
if err != nil {
log.Fatalf("upgrade gagal: %v", err)
}
fmt.Printf("Release %q ter-upgrade ke revisi %d\n", rel.Name, rel.Version)Perbedaan kunci dengan install: Run menerima nama release yang sudah ada, dan Helm melakukan upgrade dengan three-way merge seperti yang kita pelajari di episode 5 — ia membandingkan manifest lama, manifest baru, dan state aktual di cluster. Revisi bertambah setiap kali, dan history tetap tersimpan.
Untuk listing semua release di cluster:
list := action.NewList(config)
list.AllNamespaces = true
list.StateMask = action.ListDeployed | action.ListFailed
releases, err := list.Run()
if err != nil {
log.Fatalf("gagal listing release: %v", err)
}
for _, rel := range releases {
fmt.Printf("%s\t%s\t%s\t%d\n", rel.Name, rel.Namespace, rel.Info.Status, rel.Version)
}Dan untuk rendering template tanpa cluster — setara helm template — kalian tidak perlu konfigurasi cluster sama sekali. Cukup action.Install dengan DryRun=true dan ClientOnly=true, atau memakai package pkg/engine secara langsung:
i := action.NewInstall(config)
i.DryRun = true
i.ClientOnly = true
i.ReleaseName = "myapp"
rel, err := i.Run(chart, values)
if err != nil {
log.Fatalf("render gagal: %v", err)
}
fmt.Println(rel.Manifest)rel.Manifest berisi seluruh YAML hasil render — sama persis dengan output helm template --debug. Pola ini sangat berguna untuk tool yang perlu memvalidasi atau meng-inspect manifest sebelum benar-benar mendeploy.
Selama ini contoh memakai loader.Load dari direktori lokal. Di produksi, tool sering harus memuat chart dari repository HTTP (episode 17) atau registry OCI (episode 18) — dan SDK menyediakan jalurnya. Untuk repository klasik, gunakan repo.FindChartInRepoURL yang menerima URL, nama chart, dan versi, lalu mengunduh tarballnya:
import "helm.sh/helm/v3/pkg/getter"
import "helm.sh/helm/v3/pkg/repo"
chartURL, err := repo.FindChartInRepoURL(
"https://charts.bitnami.com/bitnami", "nginx", "15.11.2",
getter.All(settings),
)
if err != nil {
log.Fatalf("chart tidak ditemukan: %v", err)
}
chart, err := loader.Load(chartURL)Perhatikan getter.All(settings) — ini membuat kumpulan client unduh yang menghormati konfigurasi repository (credentials, proxy, TLS) yang sama dengan CLI. Hasilnya adalah path ke tarball yang sudah diunduh ke cache, dan loader.Load kemudian membacanya seperti halnya direktori lokal.
Untuk registry OCI, alurnya sedikit berbeda: kalian memuat langsung dari referensi oci:// memakai action.NewRegistryClient untuk autentikasi, lalu registryClient.Fetch / chart.Chart di-resolve. Prinsipnya sama — buat objek, konfigurasi, jalankan — hanya medium pengambilannya yang berbeda. Ini penting untuk tool yang harus mengelola release dari chart yang sudah dipublikasikan, bukan dari source chart lokal.
Agar tidak abstrak, mari lihat tiga use case nyata yang hampir selalu menjadi alasan tim menggunakan SDK:
Custom operator. Sebuah operator Kubernetes dibuat dengan controller-runtime (Kubebuilder/Operator SDK). Di dalam reconcile-nya, operator memanggil Helm SDK untuk mengelola release aplikasi: saat CustomResource MyApp dibuat, operator meng-install chart; saat spec-nya berubah, operator me-render dan meng-upgrade; saat resource dihapus, operator meng-uninstall. Inilah fondasi pola yang dipakai banyak "app-of-apps" internal. Keuntungan utama: operator bisa bereaksi terhadap perubahan tanpa intervensi manusia atau pipeline — sesuatu yang mustahil dengan CLI.
Self-service portal. Tim platform membangun UI internal tempat developer memilih nama service, namespace, dan resource sizing — lalu backend Go-nya memanggil SDK Helm dengan pilihan itu. Developer tidak pernah menyentuh helm; risiko miskonfigurasi berkurang drastis karena UI hanya menawarkan opsi yang divalidasi, bukan string bebas.
CI/CD integrations. Pipeline yang perlu logika lebih dari sekadar helm upgrade: validasi bahwa perubahan hanya pada release tertentu, gating berdasarkan hasil smoke test, atau update otomatis ke beberapa cluster dari satu commit. Dengan SDK, logika ini hidup di kode yang teruji, bukan di rangkaian perintah shell yang rapuh.
Helm SDK resmi adalah Go, tapi ekosistem sudah menyediakan jalur dari bahasa lain:
Python (helm-py) — binding resmi yang memakai cgo untuk menjembatani library Helm ke Python. Memungkinkan tools Python (misalnya Airflow tasks, tooling data) mengelola release tanpa menulis Go. Kelemahannya: butuh build toolchain C dan versi Helm yang kompatibel di lingkungan target.
JavaScript/TypeScript — tidak ada binding resmi yang setara helm-py. Pilihan yang umum: membungkus CLI Helm dalam subproses (misalnya lewat child_process), atau menggunakan library seperti @helm/kind untuk penggunaan lokal. Untuk produksi, banyak tim TypeScript justru memanggil service yang dibangun Go di belakangnya.
Alternatif REST API — untuk arsitektur yang tidak bisa memakai library sama sekali, ada beberapa jalur: ChartMuseum menyediakan API untuk manajemen chart (upload, download, metadata) yang kita bahas di episode 17; beberapa project membungkus Helm dalam HTTP service (misalnya helm-repo-service atau solusi platform internal); dan untuk GitOps, ArgoCD serta Flux mengekspos API untuk mengelola aplikasi yang berbasis Helm (akan kita bahas detail di episode 25). Pendekatan REST berguna ketika konsumen adalah frontend atau bahasa yang tidak didukung langsung.
Warning
Hati-hati dengan subproses CLI sebagai "SDK". Mengganti command helm di dalam pipeline dengan exec("helm", "upgrade", ...) terlihat mudah, tapi rapuh: tidak ada type checking, error parsing berbasis teks, state harus dipertahankan lewat file sementara, dan upgrade yang dijalankan secara paralel bisa saling menginjak. Jika kalian hanya butuh satu atau dua perintah, CLI cukup. Jika kalian mulai membangun logika (list → filter → upgrade → verifikasi), itu tanda kalian harus pindah ke SDK.
Pada episode 23 ini kita telah membedah Helm SDK Go: struktur package (action, cli, chart/loader, engine), inisialisasi action.Configuration yang terhubung ke cluster, instalasi dengan action.NewInstall, upgrade dengan action.NewUpgrade, listing dengan action.NewList, dan rendering template tanpa cluster — ditutup dengan use case nyata (operator, self-service portal, CI/CD) dan gambaran bahasa lain (helm-py, TypeScript, jalur REST).
Inti yang harus kalian bawa:
Run.action.NewInstall + loader.Load + Run(chart, values) adalah tiga serangkai yang menyelesaikan 90% kebutuhan.helm template di dalam kode.Di episode 24 selanjutnya kita akan membahas integrasi CI/CD pipeline: menggabungkan semua yang sudah kalian pelajari — linting, testing, packaging, push chart ke registry, dan deploy ke cluster — ke dalam pipeline yang otomatis dengan GitHub Actions, GitLab CI/CD, Jenkins, dan Tekton. Sampai jumpa di episode 24!