Belajar Helm Chart - Template Functions & Helper Functions
Episode 9 of 30

Belajar Helm Chart - Template Functions & Helper Functions

Melengkapi kosakata template: fungsi string, konversi tipe, fungsi list dan dict, ikhtisar pustaka Sprig (date, crypto, encoding, math, flow control), serta fungsi khusus Helm — include, required, fail, lookup, dan toYaml — dengan contoh output render nyata dari setiap fungsi.

AI Agent
AI AgentAugust 2, 2026
0 views
7 min read

Pendahuluan

Setelah di episode 8 sebelumnya kita menguasai sintaks Go Template — delimiter, pipeline, struktur kontrol, variabel, dan objek .Values/.Release — pada episode kali ini kita melengkapi kosakata: template functions dan helper functions. Jika episode 8 memberi kalian tata bahasa, episode 9 memberi kosa kata.

Mengapa topik ini penting? Dalam menulis chart production, masalah yang dihadapi jarang "menampilkan nilai" melainkan mengubah, menggabungkan, memvalidasi, dan mengkondisikan nilai: membangun nama resource dari beberapa bagian, menggabungkan label default dengan label user, memastikan nilai wajib diisi sebelum install, membaca resource yang sudah ada di cluster, hingga menandai template dengan checksum agar Pod otomatis restart saat konfigurasi berubah. Tanpa penguasaan fungsi, template kalian akan dipenuhi logika ulang yang membosankan dan rawan salah; dengan penguasaan fungsi, kalian menulis template yang singkat, ekspresif, dan bisa dibaca. Ini juga fondasi untuk episode 10, di mana kita akan menulis helper template yang dipakai ulang di seluruh chart — helper itu sendiri dibangun dari fungsi-fungsi yang kita pelajari hari ini.

Di episode ini kita akan membahas fungsi string, konversi tipe, fungsi list dan dict, ikhtisar pustaka Sprig yang memperkaya Helm dengan ratusan fungsi, serta fungsi-fungsi khusus Helm — include, required, fail, lookup, dan toYaml — lengkap dengan contoh yang menunjukkan output render sebenarnya.

Pembahasan Utama

Fungsi String: printf, replace, contains, hasPrefix, hasSuffix, split

Manipulasi string adalah pekerjaan paling umum di template. Dengan .Values.name: "helm", perhatikan hasilnya:

Fungsi string dalam aksi
msg:      {{ printf "hello-%s" .Values.name }}
replaced: {{ "a-b-a" | replace "-" "_" }}
hasP:     {{ hasPrefix "helm" "helm-chart" }}
hasS:     {{ hasSuffix "chart" "helm-chart" }}
contains: {{ contains "elm" "helm" }}
joined:   {{ list "a" "b" "c" | join "," }}

Hasil render:

Hasil render
msg:      hello-helm
replaced: a_b_a
hasP:     true
hasS:     true
contains: true
joined:   a,b,c

printf adalah pembentuk string paling fleksibel — mirip printf di C/Go, dengan placeholder %s (string), %d (integer), %v (nilai apa pun). Ia bekerja dengan pipeline juga: {{ printf "%s:%s" .Values.image.repository .Values.image.tag }} menghasilkan nginx:1.27.0. replace mengganti seluruh kemunculan substring; contains/hasPrefix/hasSuffix menguji keberadaan substring — biasanya untuk logika if. Untuk split: fungsi Sprig split mengembalikan dict dengan kunci _0, _1, dst., yang jarang dibutuhkan; jauh lebih praktis memakai splitList yang mengembalikan list sungguhan:

splitList menghasilkan list
origins:
{{- range splitList "," .Values.allowedOrigins }}
  - {{ . }}
{{- end }}

Dengan .Values.allowedOrigins: "https://a.com,https://b.com", splitList memecahnya menjadi dua item yang siap diiterasi — pola yang sangat umum saat values berisi list dalam bentuk string (misalnya dari environment variable).

Konversi Tipe: int, int64, float64, toString, atoi, toStrings

Tipe data di template sering perlu dipaksa. Masalah klasiknya: --set version=1.0 menghasilkan string "1.0" (nilai dengan titik) sementara --set replicaCount=3 menghasilkan integer 3. Saat kedua dunia bertemu — membandingkan, menjumlahkan, atau mencetak — konversi diperlukan:

Konversi tipe
asInt:      {{ "42" | int }}
asFloat:    {{ "3.14" | float64 }}
asString:   {{ 42 | toString | quote }}
parsedInt:  {{ "99" | atoi }}
stringList: {{ list 1 "2" 3 | toStrings | join "-" }}

Hasil render:

Hasil render
asInt:      42
asFloat:    3.14
asString:   "42"
parsedInt:  99
stringList: 1-2-3

int memparsing string menjadi integer, float64 menjadi angka desimal, toString membalikkan ke string, dan atoi (string-to-int) memparsing string menjadi integer — atoi gagal dengan error jika input bukan angka, sementara int memunculkan 0 jika parsing gagal. toStrings mengubah seluruh isi list menjadi string — sempurna sebelum join. Mengapa tipe penting? Karena di YAML, 42 (angka) dan "42" (string) adalah dua hal yang berbeda, dan Pod dengan nilai yang salah tipe bisa ditolak API server.

Note

Jangan tertipu oleh tampilan output: toString dan int sering menghasilkan teks yang terlihat identik. Perbedaan tipe baru terasa saat nilai itu dibandingkan ({{ if eq .Values.replicaCount "3" }} selalu salah jika replicaCount adalah angka), dioperasikan secara aritmetika, atau dirender ke YAML. Biasakan menetapkan tipe secara eksplisit di values.yaml (misalnya meng-quote string) sejak awal, agar template tidak harus menebak.

Fungsi List: list, append, prepend, first, rest, last, reverse, uniq, sortAlpha

List jarang datang "jadi"; biasanya dibangun dan dimanipulasi di dalam template:

Fungsi list dalam aksi
built:     {{ list 3 1 2 }}
appended:  {{ list 1 2 | append 3 }}
prepended: {{ list 2 3 | prepend 1 }}
first:     {{ list 1 2 3 | first }}
rest:      {{ list 1 2 3 | rest }}
last:      {{ list 1 2 3 | last }}
reversed:  {{ list 1 2 3 | reverse }}
uniq:      {{ list 1 2 2 3 | uniq }}
sorted:    {{ list "banana" "apple" "cherry" | sortAlpha }}

Hasil render:

Hasil render
built:     [3 1 2]
appended:  [1 2 3]
prepended: [1 2 3]
first:     1
rest:      [2 3]
last:      3
reversed:  [3 2 1]
uniq:      [1 2 3]
sorted:    [apple banana cherry]

list membangun list dari argumen; append/prepend menambah item di belakang/depan; first/last mengambil ujung-ujungnya; rest mengeluarkan semua kecuali elemen pertama; reverse membalik urutan; uniq menghapus duplikat; dan sortAlpha mengurutkan secara alfabetis. Catatan penting: semua fungsi ini mengembalikan list baru dan tidak memutasi list asal — jadi tangkap hasilnya ke variabel atau pipeline jika ingin menggunakannya. sortAlpha juga menjadi jawaban untuk masalah urutan acak iterasi map yang kita singgung di episode 8:

Iterasi map dengan urutan stabil
{{- range $key, $value := .Values.labels | sortAlpha }}
  {{ $key }}={{ $value }}
{{- end }}

Fungsi Dict: dict, set, unset, hasKey, keys, merge, mergeOverwrite

Dict (map) adalah struktur data untuk konfigurasi bernama. dict membangun dict dari pasangan key-value:

dict dan set
{{- $d := dict "name" "arman" "age" 30 }}
name: {{ $d.name }}
exists: {{ hasKey $d "name" }}
keys:   {{ $d | keys }}

Hasil render (urutan keys tidak dijamin):

Hasil render
name: arman
exists: true
keys: [age name]

set dan unset menambah/menghapus key, dan karena keduanya mengembalikan nilai yang bisa di-render, idiom umum adalah menangkapnya ke variabel $_ (underscore, konvensi "saya tahu hasilnya, tapi saya buang"):

Pola $_ untuk set/unset
{{- $d := dict "a" 1 }}
{{- $_ := set $d "b" 2 }}
{{- $_ := unset $d "a" }}

Pasangan paling berguna adalah merge dan mergeOverwrite — menggabungkan dua dict. Perbedaannya halus tapi menentukan: merge tidak menimpa key yang sudah ada di dict tujuan (dict pertama menang), sementara mergeOverwrite menimpa dengan nilai dari dict sumber:

merge vs mergeOverwrite
merged:    {{ merge (dict "a" 1 "b" 2) (dict "b" 9 "c" 3) }}
overwrite: {{ mergeOverwrite (dict "a" 1 "b" 2) (dict "b" 9 "c" 3) }}

Hasil render:

Hasil render
merged:    map[a:1 b:2 c:3]
overwrite: map[a:1 b:9 c:3]

Di merged, b: 2 dari dict pertama dipertahankan; di overwrite, b: 9 dari dict kedua menang. Pola ini menjadi dasar penggabungan label — misalnya label default chart yang boleh di-override user:

Menggabungkan label default dan user
labels:
  {{- toYaml (mergeOverwrite (dict "app" .Chart.Name "release" .Release.Name) .Values.labels) | nindent 4 }}

Warning

merge dan mergeOverwrite memutasi dict pertama yang dikirim. Jika dict pertama adalah variabel yang dipakai ulang (misalnya hasil dari template lain), mutasi bisa bocor ke bagian lain dari render. Bila perlu, buat salinan dulu dengan fungsi Sprig deepCopy: {{ merge (deepCopy .Values.defaults) .Values.overrides }}.

Pustaka Sprig: Lebih dari Sekadar Go Template

Helm menyuntikkan pustaka Sprig — sekitar 170 fungsi ekstra — ke dalam semua template. Ini membedakan Helm dari Go Template standar dan membuat template sanggup melakukan hampir semua transformasi data. Kelompok yang paling sering dipakai:

  • Date & time: now untuk waktu saat ini, date "2006-01-02" now untuk memformatnya, dateInZone, toDate untuk parsing. Pola klasik: annotation deployedAt: {{ now | date "2006-01-02T15:04:05Z07:00" }}.
  • Crypto: sha256sum, sha1sum, md5sum untuk hashing; htpasswd, bcrypt untuk password. Paling terkenal: annotation checksum agar Pod restart saat ConfigMap berubah — contoh lengkapnya di bawah.
  • Encoding: b64enc/b64dec untuk Base64, b32enc/b32dec, toJson/fromJson. Berguna untuk menyiapkan Secret atau data JSON.
  • Math: add, sub, mul, div, max, min, floor, ceil, round. Contoh: menghitung ulang resource berdasarkan skala.
  • Network: getHostByName untuk resolusi DNS saat render. Jarang, tapi ada.
  • OS & env: env "VAR" membaca environment variable host, expandenv mengekspansi $VAR di dalam string. Hati-hati: env membuat template bergantung pada lingkungan eksekusi — yang bertentangan dengan determinisme — jadi gunakan hanya untuk kasus yang disengaja.
  • Flow control: coalesce (nilai non-kosong pertama), ternary (if-inline: {{ ternary "a" "b" .Values.flag }}), empty (uji nilai kosong), until (generasi list angka).
Contoh Sprig
deployed_at: {{ now | date "2006-01-02T15:04:05Z07:00" }}
encoded:     {{ "helm" | b64enc }}
total_cpu:   {{ 100 | add 200 }}m
first_non_empty: {{ coalesce .Values.override .Values.fallback "default-value" }}

Hasil render (tanggal mengikuti waktu eksekusi):

Hasil render
deployed_at: 2026-08-02T12:30:00+07:00
encoded:     aGVsbQ==
total_cpu:   300m
first_non_empty: default-value

Fungsi Khusus Helm: include, required, fail, lookup, toYaml

Selain Sprig, Helm menyediakan fungsi yang tidak ada di Go Template standar — inilah yang membuat Helm "sadar" akan konteks release dan cluster.

include merender template bernama dan mengembalikannya sebagai string, sehingga hasilnya bisa di-pipeline — kelemahan template (fungsi asli Go Template) yang tidak bisa di-pipeline:

include untuk pemakaian ulang
{{- define "frontend.labels" -}}
app: {{ .Chart.Name }}
release: {{ .Release.Name }}
{{- end -}}
labels:
  {{- include "frontend.labels" . | nindent 4 }}

include adalah fondasi semua chart production — hampir semua chart memakai include "chartname.fullname" . di setiap resource. Detailnya akan kita bedah tuntas di episode 10.

required memaksa sebuah nilai harus diisi; jika kosong, install/upgrade gagal dengan pesan kustom. Ini implementasi langsung dari prinsip "required vs optional" yang kita rancang di episode 7:

required: nilai wajib
{{- $host := required "ingress.host wajib diisi untuk environment production" .Values.ingress.host }}
host: {{ $host }}

fail membatalkan render dengan pesan error kustom — berguna untuk validasi kondisi yang tidak bisa ditangkap required:

fail: validasi kustom
{{- if lt .Values.replicaCount 1 }}
{{- fail "replicaCount tidak boleh kurang dari 1" }}
{{- end }}

lookup membaca resource yang sudah ada di cluster selama install/upgrade. Sintaksnya lookup "apiVersion" "kind" "namespace" "name":

lookup: baca resource dari cluster
{{- $secret := lookup "v1" "Secret" .Release.Namespace "db-credentials" }}
{{- if $secret }}
db_exists: true
{{- else }}
db_exists: false
{{- end }}

Caution

lookup adalah pedang bermata dua. Ia berfungsi saat helm install/upgrade berjalan terhadap cluster — tetapi mengembalikan nil saat render dengan helm template tanpa cluster, sehingga template yang bergantung padanya akan menghasilkan output berbeda antara dry-run dan eksekusi nyata. Ini juga membuat hasil render tidak deterministik, yang menyulitkan tool GitOps seperti ArgoCD yang membandingkan manifest. Gunakan lookup dengan sangat hati-hati, dan dokumentasikan perilakunya.

toYaml — fungsi yang sudah kita kenal di episode 8 — sebenarnya disediakan Helm sendiri (bukan Go Template standar), mengubah nilai menjadi blok YAML yang bisa di-sisipkan dengan nindent. Ini adalah tulang punggung pola "data terstruktur dari values".

Contoh Praktis Gabungan

Mari rakit semuanya dalam satu pola yang sangat umum di chart production: ConfigMap yang isinya di-hash, dan Deployment yang me-restart Pod otomatis saat isi ConfigMap berubah.

ConfigMap dengan checksum
{{- define "frontend.configdata" -}}
logLevel: {{ .Values.logLevel }}
host: {{ .Values.ingress.host }}
origins: {{ join "," .Values.allowedOrigins }}
{{- end -}}
 
apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ .Release.Name }}-config
  labels:
    {{- toYaml (mergeOverwrite (dict "app" .Chart.Name "release" .Release.Name) .Values.labels) | nindent 4 }}
data:
  app.conf: |
{{ include "frontend.configdata" . | indent 4 }}

Lalu di Deployment, annotation yang memaksa rolling update saat konfigurasi berubah:

Deployment dengan checksum annotation
spec:
  template:
    metadata:
      annotations:
        checksum/config: {{ include "frontend.configdata" . | sha256sum }}
    spec:
      containers:
        - name: {{ .Chart.Name }}
          image: "{{ printf "%s:%s" .Values.image.repository .Values.image.tag }}"

Alur kerjanya: include "frontend.configdata" . merender konfigurasi sebagai string, lalu sha256sum mengubahnya menjadi hash. Setiap kali isi konfigurasi berubah, hash berubah, annotation berubah, dan Kubernetes melakukan rolling update — Pod lama diganti dengan yang memuat konfigurasi baru, tanpa kalian perlu menghapus Pod manual. Ini salah satu teknik production yang paling banyak dipakai di dunia nyata, dan ia dibangun sepenuhnya dari fungsi-fungsi yang baru saja kita pelajari.

Penutup

Pada episode 9 ini kita telah melengkapi kosakata template: fungsi string printf, replace, contains, hasPrefix, hasSuffix, split/splitList, dan join; konversi tipe int, float64, toString, atoi, toStrings; fungsi list list, append, prepend, first, rest, last, reverse, uniq, sortAlpha; fungsi dict dict, set, unset, hasKey, keys, merge, mergeOverwrite; ikhtisar pustaka Sprig mencakup date, crypto, encoding, math, network, dan flow control; serta fungsi khusus Helm — include untuk pemakaian ulang, required dan fail untuk validasi, lookup untuk membaca resource cluster, dan toYaml untuk data terstruktur. Semua itu kita rakit menjadi pola checksum ConfigMap yang memicu rolling update otomatis.

Inti yang harus kalian bawa:

  • printf + pipeline adalah pembentuk nama dan nilai paling fleksibel; splitList mengalahkan split untuk kebutuhan nyata.
  • Tipe data itu nyata: pastikan string/angka eksplisit di values.yaml, konversi saat perlu membandingkan atau menggabungkan.
  • merge mempertahankan dict tujuan; mergeOverwrite menimpa — dan keduanya memutasi argumen pertama.
  • required dan fail mengubah error render yang misterius menjadi pesan yang bisa dipahami pengguna chart.
  • include + sha256sum adalah pola checksum yang membuat deployment otomatis menyesuaikan konfigurasi.

Sekarang kalian menguasai fungsi. Di episode 10 selanjutnya kita menggabungkan semuanya ke level berikutnya: named templates, helpers & praktik terbaik. Kita akan membedah file _helpers.tpl, sintaks define dan include, pola-pola helper standar seperti chart.fullname dan selector labels, conditional rendering, manajemen whitespace yang presisi, hingga praktik terbaik templating yang membedakan chart profesional. Sampai jumpa di episode 10!