Mengelola logika template bersama lintas banyak chart: konsep chart bertipe library, membangun helper reusable dengan _helpers.tpl, memakai dependency di chart aplikasi, contoh real-world label dan security context, hingga praktik terbaik versioning dan pengujian library chart.

Setelah di episode 18 sebelumnya kita memindahkan distribusi chart ke OCI registry — alur helm push/helm pull, penandatanganan Cosign, dan strategi migrasi dari HTTP — pada episode kali ini kita masuk ke pola desain yang mengatasi masalah berbeda: bukan bagaimana mengirim chart, tapi bagaimana menjaga puluhan chart tetap konsisten. Jawabannya adalah library charts.
Cerita yang sangat familiar di dunia nyata: sebuah platform team mengelola 40 chart aplikasi — satu per microservice. Setiap chart punya _helpers.tpl yang hampir identik: label standar, fullname generator, security context. Lalu suatu hari kebijakan keamanan berubah: semua pod harus berjalan dengan runAsNonRoot: true dan seccompProfile tertentu. Sekarang 40 chart harus diubah, diuji, dan dirilis ulang satu per satu — dan pada chart ke-23, ada yang kelewat. Itu bukan sekadar pekerjaan yang membosankan; itu adalah cara paling efisien untuk menghasilkan drift antara apa yang disetujui security team dan apa yang benar-benar berjalan di produksi.
Library chart adalah jawabannya. Ia adalah chart yang tidak bisa di-install sendiri — tidak ada templates/*.yaml yang menghasilkan resource — karena isinya hanya definisi template yang siap di-include. Ketika library chart ini di-bump, semua chart aplikasi yang mengkonsumsinya menerima perbaikan label, security context, atau helper baru secara serentak. Di episode ini kita bedah konsepnya, cara membangun dan menggunakannya, contoh nyata yang langsung bisa dipakai, dan praktik terbaik yang membuat library chart aman untuk dijadikan fondasi.
Di Chart.yaml ada field type yang menentukan peran chart: application (default) atau library. Chart bertipe library adalah kumpulan named template yang dirancang untuk di-include oleh chart lain — seperti sebuah modul kode tanpa entry point. Perbedaan krusialnya:
templates/ yang merender resource ke API server.helm install padanya akan gagal dengan pesan bahwa chart library tidak mengandung manifest. Ia tidak punya resource sendiri; hanya punya definisi template yang bisa dipanggil via include.Bandingkan dengan _helpers.tpl di chart biasa (episode 10): setiap chart memang bisa punya helper lokal, tapi helper itu tidak bisa dipakai lintas chart kecuali disalin. Library chart menghilangkan salin-tempel itu: logika ditulis sekali, disebar via dependency, dan dipakai di mana pun. Ia adalah jawaban Helm untuk prinsip DRY (Don't Repeat Yourself) yang sudah lama dimiliki library biasa.
Untuk apa library chart dipakai dalam praktik:
Membangun library chart dimulai dari Chart.yaml — perhatikan type: library:
apiVersion: v2
name: myorg-common
description: Kumpulan helper template bersama untuk chart aplikasi myorg.
type: library
version: 1.2.0
appVersion: ""Isi utamanya adalah templates/_helpers.tpl — file yang mendefinisikan named template dengan define, yang nanti di-panggil chart lain dengan prefix nama library. Konvensi penamaan yang disepakati: setiap define diawali <nama-library>.<nama-helper>, misalnya myorg-common.labels. Ini bukan sekadar gaya — ini mencegah tabrakan nama saat beberapa library chart atau chart aplikasi mendefinisikan helper dengan nama yang sama.
{{- define "myorg-common.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}}
{{- end -}}
{{- define "myorg-common.fullname" -}}
{{- $name := default .Chart.Name .Values.nameOverride -}}
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}}
{{- end -}}
{{- define "myorg-common.labels" -}}
app.kubernetes.io/name: {{ include "myorg-common.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
app.kubernetes.io/part-of: {{ .Values.partOf | default "myorg" }}
helm.sh/chart: {{ printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
{{- end -}}
{{- define "myorg-common.selectorLabels" -}}
app.kubernetes.io/name: {{ include "myorg-common.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end -}}
{{- define "myorg-common.securityContext" -}}
runAsNonRoot: true
runAsUser: 10001
runAsGroup: 10001
allowPrivilegeEscalation: false
capabilities:
drop: ["ALL"]
seccompProfile:
type: RuntimeDefault
{{- end -}}Ada detail teknis yang menentukan: bagaimana . (root context) diteruskan. Saat chart aplikasi memanggil include "myorg-common.labels" ., nilai . yang masuk adalah context dari chart aplikasi — dengan .Release, .Chart, dan .Values dari chart aplikasi tersebut. Inilah yang membuat helper seperti myorg-common.labels bekerja: ia membaca .Release.Name dan .Chart.Name dari pemanggilnya, bukan dari library chart. Library chart harus menulis helper sebagai fungsi dari context yang diberikan, bukan dari contextnya sendiri — konsep yang sama dengan scope di Go template yang kita bahas di episode 8.
Note
Perhatikan bahwa _helpers.tpl di atas tidak mengakses .Values yang spesifik library chart — ia bergantung pada nilai yang datang dari pemanggil. Jika kalian butuh nilai default internal, definisikan di values.yaml library chart... tapi perlu diingat: nilai dari values.yaml library chart tidak otomatis ter-merge ke chart aplikasi. Pola yang umum adalah menambahkan konfigurasi eksplisit di values.yaml chart aplikasi (misalnya partOf) dan memanggilnya dengan default. Jangan berasumsi nilai library chart tersedia di sisi pemanggil.
Library chart juga boleh berisi templates/ lain, Chart.lock, dan bahkan dependency — tetapi karena ia tidak di-install, tidak ada yang di-render ke cluster. Semuanya hanya sumber definisi untuk di-include.
Sisi konsumen adalah tempat kekuatan library chart terasa. Chart aplikasi mendeklarasikan library chart sebagai dependency biasa:
apiVersion: v2
name: myapp
description: Chart aplikasi myapp
type: application
version: 2.0.0
appVersion: "1.27.3"
dependencies:
- name: myorg-common
version: 1.2.0
repository: https://charts.myorg.example.comKarena library chart adalah dependency biasa, alur episode 11 berlaku sepenuhnya — termasuk Chart.lock dari episode 16:
helm dependency update ./myapp
# ... menarik myorg-common-1.2.0 ke charts/
helm lint ./myapp
helm package ./myappLalu di dalam template chart aplikasi, helper dipanggil dengan include — dan inilah perbedaan dari pemakaian helper lokal: nama template dipanggil dengan prefix library:
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "myorg-common.fullname" . }}
labels:
{{- include "myorg-common.labels" . | nindent 4 }}
spec:
replicas: {{ .Values.replicaCount }}
selector:
matchLabels:
{{- include "myorg-common.selectorLabels" . | nindent 6 }}
template:
metadata:
labels:
{{- include "myorg-common.selectorLabels" . | nindent 8 }}
spec:
securityContext:
{{- include "myorg-common.securityContext" . | nindent 8 }}
containers:
- name: {{ .Chart.Name }}
securityContext:
{{- include "myorg-common.securityContext" . | nindent 12 }}Perhatikan pola yang konsisten: include "myorg-common.fullname" . memanggil helper dari library chart, dan hasilnya di-nindent ke posisi indentasi yang benar di struktur YAML — persis teknik whitespace management yang kita kuasai di episode 10. Tidak ada salin-tempel helper lagi: myapp kini memakai logika label dan security context yang sama dengan 39 chart lain di org.
Satu detail yang sering mengejutkan: dependency library chart tidak otomatis "terlihat" — template chart aplikasi tidak di-render bersamaan dengan dependency. include bekerja karena Helm me-render semua named template dari seluruh chart yang ikut di-bundle (chart aplikasi plus dependency-nya) ke dalam satu ruang nama. Konsekuensinya, helper dari library chart hanya bisa diakses lewat include "myorg-common.namaHelper" . — bukan dipanggil langsung sebagai bagian dari rendering subchart, karena library chart memang tidak menghasilkan manifest apa pun. Jika kalian ingin menguji helper sebelum memakainya di semua chart, rendernya lewat helm template ./myapp --show-only templates/deployment.yaml dan amati hasil include pada output.
Mari lihat satu pola end-to-end yang sering jadi alasan sebenarnya orang membangun library chart: kebijakan security yang berubah. Misalnya security team memutuskan semua workload harus berjalan dengan readOnlyRootFilesystem: true. Dengan pendekatan salin-tempel, tim harus mengedit 40 chart. Dengan library chart:
{{- define "myorg-common.securityContext" -}}
runAsNonRoot: true
runAsUser: 10001
runAsGroup: 10001
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop: ["ALL"]
seccompProfile:
type: RuntimeDefault
{{- end -}}Bump version library chart ke 1.3.0, lalu setiap chart aplikasi naikkan dependency dan rilis ulang sesuai ritmenya masing-masing. Satu perubahan, satu tempat, zero drift. Ini contoh paling jelas mengapa library chart bukan sekadar "biar rapi" — ia adalah mekanisme penegakan kebijakan.
Pola real-world lain yang umum ada di library chart:
fullname yang menormalisasi panjang label, menangani nameOverride, dan memenuhi batas 63 karakter.prometheus.io/scrape, checksum/config (restart pod saat ConfigMap berubah), atau annotation owner yang konsisten.repository:tag dengan default pull policy dari nilai chart.env standar (seperti NODE_ENV atau DD_SERVICE) dari nilai bersama.Membangun fondasi yang dipakai puluhan chart berarti kesalahan di sini diamplifikasi ke seluruh org. Lima praktik yang wajib dipegang:
Versioning yang konservatif. Library chart harus mengikuti semver ketat (episode 16). Menambah helper baru = MINOR; mengubah perilaku helper yang ada = MAJOR. Karena helper dipakai oleh banyak chart, perubahan MAJOR berarti semua konsumen harus menyesuaikan — selalu periksa bahwa helper dihapus atau diubah perilakunya hanya dengan bump yang sesuai.
Backward compatibility sebagai harga mati. Helper yang sudah dipakai chart lain adalah API publik. Jangan hapus helper lama; jika perlu perilaku baru, tambahkan helper baru dan biarkan yang lama dengan deprecation notice. Aturan yang sama dengan library kode: menghapus fungsi yang sedang dipakai orang lain adalah breaking change.
Dokumentasi yang ketat. Setiap helper — parameter yang dibutuhkannya dari context, nilai yang dihasilkannya, dan perilaku edge case-nya — harus terdokumentasi (episode 15). Karena helper ini dipakai lintas tim, dokumentasi adalah satu-satunya cara pengguna tahu cara memanggilnya tanpa membaca implementasi.
Testing yang serius. Library chart harus diuji seperti kode: helm-unittest (episode 14) bisa men-test include terhadap context buatan, memastikan helper menghasilkan output yang diharapkan untuk berbagai input. Karena kesalahan di sini menyebar, test coverage helper library layak diperlakukan lebih ketat daripada helper chart biasa.
Satu chart, satu tanggung jawab. Jangan menjadikan library chart sebagai tong sampah untuk semua helper. Pisahkan berdasarkan domain: myorg-common untuk label & penamaan, myorg-security untuk security context, myorg-observability untuk anotasi monitoring. Konsumen mengambil hanya yang mereka butuhkan, dan bump satu domain tidak memaksa semua orang menerima perubahan domain lain.
Warning
Jangan membangun library chart sebelum ada dua atau tiga chart yang benar-benar berbagi pola yang sama. Abstraction terlalu dini — memisahkan helper yang hanya dipakai satu chart — menambah biaya tanpa penghematan. Pola yang tepat muncul dari pengulangan; ekstrak ke library chart saat salinan ketiga muncul, bukan yang pertama.
Pada episode 19 ini kita telah menguasai pola yang mengubah cara tim besar menjaga konsistensi chart. Kita memahami konsep library chart sebagai chart type: library yang tidak bisa di-install, berisi named template yang di-include chart lain — jawaban Helm untuk prinsip DRY. Kita membangun library chart dengan Chart.yaml bertipe library dan _helpers.tpl yang setiap definenya ber-prefix nama library untuk mencegah tabrakan, lalu memakainya di chart aplikasi via dependency helm dependency update dan pemanggilan include "myorg-common.labels" .. Kita melihat kekuatannya lewat kasus nyata perubahan kebijakan security yang cukup diubah di satu tempat, dan menutup dengan praktik terbaik: semver konservatif, backward compatibility, dokumentasi, testing, dan satu-chart-satu-tanggung-jawab.
Inti yang harus kalian bawa:
type: library menegakkan itu..Release, .Chart, .Values dari chart aplikasi).Dengan ini, fase membangun chart kalian lengkap: dari templating, dependencies, testing, dokumentasi, packaging, distribusi, hingga pola berbagi logika. Di episode 20 selanjutnya kita menaikkan standar ke ranah yang tidak bisa ditawar: keamanan chart dan best practices — least privilege, security context, RBAC, manajemen secret tanpa hardcode, image security, supply chain, hingga policy enforcement dengan admission controllers. Pastikan tetap semangat!