Menguasai siklus rilis chart: Semantic Versioning yang disiplin, perbedaan version vs appVersion, pengemasan chart dengan helm package, penandatanganan provenance dengan GPG, hingga Chart.lock yang menjamin dependency dapat direproduksi.

Setelah di episode 15 sebelumnya kita membangun dokumentasi chart yang production-grade — README.md sebagai kontrak, NOTES.txt sebagai asisten pasca-instalasi, generasi otomatis tabel parameter dengan helm-docs, dan CHANGELOG.md sebagai catatan transparansi — pada episode kali ini kita mengubah chart dari sekadar folder berisi template menjadi artefak yang bisa didistribusikan: sebuah arsip .tgz dengan versi yang jelas, tanda tangan yang bisa diverifikasi, dan dependency yang bisa direproduksi.
Mengapa topik ini krusial? Karena sampai episode ini, chart kalian hanya hidup di satu folder lokal. Tapi dalam dunia nyata, chart tidak dijalankan — ia dikonsumsi. Tim lain memasangnya, CI memakainya, pipeline melepasnya ke cluster produksi. Supaya semua itu aman, ada tiga pertanyaan yang harus dijawab dengan tegas: versi berapa yang sedang dipakai? Apakah artefak ini asli dan tidak dirusak di tengah jalan? Apakah build ini bisa direproduksi? Jawaban pertama ditangani Semantic Versioning, jawaban kedua oleh penandatanganan provenance, dan jawaban ketiga oleh Chart.lock.
Di episode ini kita bedah ketiganya satu per satu. Kita mulai dari aturan semver yang disiplin dan perbedaan halus antara version dan appVersion, lalu mengemas chart dengan helm package, menandatanganinya dengan GPG dan memverifikasinya, dan menutup dengan mekanisme dependency locking yang membuat build chart bersifat deterministik.
Semantic Versioning (semver) adalah standar penomoran MAJOR.MINOR.PATCH yang mengubah penomoran versi menjadi kontrak: setiap angka menyampaikan makna tentang dampak perubahan terhadap pengguna. Ini bukan sekadar konvensi rapi — ini komunikasi risiko.
replicas yang dipakai orang lain, mengubah struktur values yang lama, menaikkan apiVersion yang tidak kompatibel — semuanya menaikkan MAJOR. Konsumen chart yang menggunakan constraint ^1.x tidak akan menerima 2.x secara otomatis.autoscaling.enabled baru tidak mematahkan siapa pun — yang memakai default lama tidak akan merasakan apa pun. Ini naik MINOR.Aturan emasnya: jika ada keraguan apakah suatu perubahan mematahkan, itu adalah MAJOR. Mengapa disiplin ini penting? Karena pengguna chart menaruh nyawa aplikasi mereka pada constraint versi. Bayangkan kalian memakai constraint >=1.0.0 <2.0.0 dan tim chart menaikkan versi ke 1.5.0 dengan sebenarnya berisi breaking change. Versi itu lolos constraint, pipeline produksi kalian otomatis mengambilnya, dan aplikasi meledak tanpa peringatan. Semver yang tidak disiplin bukan sekadar kesalahan penulisan — ia adalah kebohongan yang menghancurkan kepercayaan.
Tip
Terapkan aturan "publik vs privat": semver mengatur kontrak publik — parameter values.yaml, nama resource yang digenerate, template yang di-render. Perubahan internal seperti refactor _helpers.tpl yang tidak mengubah output render boleh naik PATCH. Cara paling obyektif untuk mengetahuinya adalah membandingkan output render versi lama vs baru: jika helm template menghasilkan YAML yang berbeda untuk nilai input yang sama, itu perubahan perilaku.
Salah satu kebingungan klasik di Helm adalah dua field yang namanya mirip tapi memiliki ritme yang berbeda: version dan appVersion di Chart.yaml.
version adalah versi paket chart — angka yang dipakai Helm untuk semver constraint, caching, dan pemilihan chart di repository. Inilah yang kalian lihat di helm search repo dan helm list. Ia berubah sesuai aturan semver di atas.appVersion adalah versi aplikasi yang dikemas di dalam chart — misalnya nginx:1.27.3. Ia adalah informasi, bukan penentu: Helm tidak pernah menggunakan appVersion untuk logika resolusi versi. Ia hanya muncul di metadata chart dan biasanya dirender ke label app.kubernetes.io/version.Poin kuncinya: kedua versi ini independen. Chart kalian bisa berada di version: 2.0.0 sementara appVersion: 1.27.3. Kenapa tidak disinkronkan? Karena chart dan aplikasi memiliki siklus hidup yang berbeda: kalian bisa merilis chart 1.0.0 yang mengemas nginx 1.25, lalu rilis chart 1.1.0 yang mengemas nginx 1.27 (fitur baru: upgrade aplikasi). Kedua angka naik, tapi dengan kecepatannya masing-masing.
apiVersion: v2
name: myapp
description: Chart aplikasi myapp
type: application
version: 2.3.1 # versi paket chart (semver, dipakai Helm)
appVersion: "1.27.3" # versi aplikasi nginx (informatif)Perhatikan appVersion ditulis dalam tanda kutip. Ini penting: nilai seperti 1.10 akan di-coerce YAML menjadi angka 1.1 tanpa tanda kutip — versi aplikasi yang salah dengan tenang. Selalu tulis appVersion sebagai string.
Folder chart yang kita kerjakan selama ini belum bisa didistribusikan — ia berisi banyak file dan direktori. helm package menggabungkan semuanya menjadi satu arsip .tgz bernama nama-chart-versi.tgz. Inilah unit distribusi chart: satu file, nama versi di dalam nama file, siap diunggah ke repository atau ditarik dengan helm pull.
helm package ./myapp
# Output:
# Successfully packaged chart and saved it to: /home/user/myapp-0.1.0.tgzPerhatikan detail arsipnya. File .tgz menyimpan nama folder chart, bukan nama file arsipnya. Di dalam arsip ada folder myapp/ berisi seluruh isi chart. Nama folder di dalam arsip inilah yang menentukan nama chart saat di-install — jika kalian mengganti nama folder di dalam arsip, Helm akan menganggap chart tersebut memiliki nama yang berbeda. Dan karena formatnya adalah tar.gz, kalian bisa memeriksa isinya langsung:
tar -tzf myapp-0.1.0.tgz
# myapp/Chart.yaml
# myapp/values.yaml
# myapp/templates/deployment.yaml
# myapp/templates/_helpers.tpl
# myapp/README.mdSebelum mengemas, biasakan dua ritual. Pertama, jalankan helm lint untuk memastikan chart tidak punya masalah struktural. Kedua, gunakan .helmignore untuk mengecualikan file yang tidak perlu masuk arsip — file local test, values-dev.yaml, screenshot, .git — supaya arsip bersih dan tidak mengandung informasi yang tidak seharusnya keluar. Setiap file yang lolos .helmignore ikut terkirim ke pengguna; file yang seharusnya tidak beredar di sini adalah risiko keamanan.
Sekarang chart sudah menjadi satu file. Pertanyaan berikutnya: bagaimana pengguna tahu bahwa file ini benar-benar dari kalian dan tidak diubah orang lain di tengah jalan? Jawabannya adalah provenance — bukti asal-usul.
Ketika kalian menandatangani chart, helm package menghasilkan file kedua bernama myapp-0.1.0.tgz.prov. File ini berisi digest SHA-256 dari arsip chart beserta metadata-nya, yang ditandatangani dengan kunci GPG kalian. Pengguna yang memegang kunci publik kalian bisa memverifikasi bahwa arsip itu persis seperti saat ditandatangani — satu bit saja berubah, verifikasi gagal.
Prosesnya dimulai dengan menyiapkan kunci GPG:
gpg --quick-generate-key "Helm Chart Signing" rsa4096 sign 0
# Simpan passphrase dalam file (jangan commit ke repo!)
echo -n "passphrase-anda" > /tmp/signing-key.pass
gpg --batch --pinentry-mode loopback --yes \
--export-secret-key --armor "Helm Chart Signing" > /tmp/signing-key.gpg
gpg --batch --pinentry-mode loopback --import /tmp/signing-key.gpgLalu tanda tangani saat mengemas:
helm package ./myapp \
--sign \
--key "Helm Chart Signing" \
--keyring ~/.gnupg/secring.gpg \
--passphrase-file /tmp/signing-key.pass
# ls: myapp-0.1.0.tgz myapp-0.1.0.tgz.provPengguna yang menerima chart bisa memverifikasi keasliannya dengan helm verify:
helm verify myapp-0.1.0.tgz
# Signed by: Helm Chart Signing <...>
# Using Key With Fingerprint: ABCD...
# Chart Hash Verified: myapp-0.1.0.tgzImportant
helm verify hanya membuktikan bahwa tanda tangan cocok dengan kunci yang kalian miliki di keyring — ia tidak menilai apakah kunci itu bisa dipercaya. Trust establishment adalah proses terpisah: kalian harus mendapatkan kunci publik pembuat chart melalui saluran yang aman, memverifikasi fingerprint-nya di luar band, dan menyimpannya sekali. Ini persis pola "trust on first use" yang dipakai SSH: mengunci fingerprint pertama kali, lalu semua verifikasi berikutnya merujuk padanya. Mendistribusikan kunci publik lewat repo chart yang sama dengan chart-nya sendiri menghancurkan nilai keamanannya — seperti menyimpan kunci gembok di dalam gembok.
Perlu jujur soal adopsi: penandatanganan provenance .prov masih jarang dipakai di ekosistem Helm klasik, dan untuk chart yang didistribusikan via OCI registry praktik modernnya bergeser ke Cosign (yang akan kita bahas di episode 18). Tapi mekanisme .prov tetap penting dipahami karena ia adalah fondasi konseptual yang sama: memisahkan artefak dari bukti keasliannya.
Pertanyaan terakhir yang dijawab episode ini: apakah build chart bersifat reproducible? Ini masalah yang dialami semua package manager — dan solusinya juga sama: lock file.
Ingat di episode 11 kita menambahkan dependency dengan constraint versi di Chart.yaml, misalnya version: "~1.2.0". Constraint seperti itu adalah rentang: ~1.2.0 berarti "1.2.x terbaru". Setiap kali helm dependency update dijalankan, Helm bisa saja menarik versi 1.2.9 hari ini dan 1.2.12 bulan depan — output render chart bisa berbeda, perilaku bisa berubah, dan bug yang kemarin tidak ada bisa muncul esok. Untuk produksi, itu tidak bisa diterima.
Solusinya adalah Chart.lock — file yang dihasilkan helm dependency update dan mencatat versi persis setiap dependency yang terpecahkan. Sama seperti package-lock.json di Node.js atau bun.lock yang kalian pakai di proyek ini, ia membekukan hasil resolusi sehingga dua orang yang menjalankan helm dependency build pada mesin berbeda (atau dua minggu berbeda) mendapatkan set dependency yang identik.
dependencies:
- name: redis
repository: https://charts.bitnami.com/bitnami
version: 19.6.4
digest: sha256:1f7a4b3c...9d2e0f1a
generated: "2026-08-02T10:15:00Z"Tiga field penting di sini: version yang sudah berupa versi pasti (bukan constraint), digest SHA-256 yang menjamin isi dependency tidak berubah, dan generated sebagai timestamp pembuatan. Alur kerjanya sederhana:
Chart.yaml, lalu jalankan helm dependency update untuk meng-generate ulang Chart.lock, dan commit keduanya.helm dependency build — ini membaca Chart.lock dan menarik versi yang persis tercatat, tanpa resolusi ulang.# Setelah mengubah Chart.yaml:
helm dependency update ./myapp
# Di CI / mesin baru - memakai Chart.lock yang sudah di-commit:
helm dependency build ./myappKonsekuensi yang harus kalian sadari: helm dependency update selalu men-resolve ulang dan menimpa Chart.lock; helm dependency build menghormati lock yang ada. Jika Chart.yaml berubah tapi Chart.lock tidak ikut di-commit, helm dependency build akan gagal dengan peringatan bahwa keduanya tidak sinkron — itu adalah fitur, bukan bug: ia memaksa kalian menangani perubahan dependency secara eksplisit. Reproducibility bukanlah sifat yang gratis; ia adalah disiplin yang dijaga oleh mekanisme.
Warning
Jangan pernah meletakkan Chart.lock di .gitignore kecuali chart kalian sengaja ingin menyelesaikan dependency secara dinamis setiap build (pola yang cocok hanya untuk chart pengembangan, bukan rilis). Untuk chart yang didistribusikan, Chart.lock yang di-commit adalah sumber kebenaran: tanpa itu, "build yang sama" adalah istilah yang tidak memiliki arti.
Kombinasi lengkap workflow rilis chart di episode ini: bump version di Chart.yaml sesuai aturan semver → helm lint → helm dependency update → helm package --sign → verifikasi helm verify. Hasilnya: satu arsip .tgz bernama deterministik, satu file .prov sebagai bukti keaslian, dan sebuah Chart.lock yang menjamin setiap orang membangun dari set dependency yang sama.
Pada episode 16 ini kita telah mengubah chart menjadi artefak yang layak didistribusikan. Kita memahami Semantic Versioning sebagai bahasa risiko: MAJOR untuk breaking changes, MINOR untuk fitur baru, PATCH untuk perbaikan bug — dan bahwa ketidakdisiplinan di sini adalah kebohongan yang menghancurkan kepercayaan pengguna. Kita membedakan version (versi paket yang dipakai Helm untuk resolusi) dari appVersion (versi aplikasi yang informatif), lalu mengemas chart menjadi .tgz dengan helm package, memeriksanya dengan tar -tzf, dan membersihkannya dengan .helmignore. Kita menandatangani chart dengan GPG menghasilkan file .prov, memverifikasinya dengan helm verify, dan memahami bahwa trust dibangun lewat fingerprint kunci yang diverifikasi di luar band. Terakhir, kita membekukan dependency dengan Chart.lock — dipisahkan antara helm dependency update (resolve ulang) dan helm dependency build (mengikuti lock) — sehingga build menjadi reproducible.
Inti yang harus kalian bawa:
version mengendalikan resolusi Helm; appVersion hanya informasi — tulis sebagai string.helm package --sign menghasilkan dua artefak: .tgz dan .prov; helm verify memeriksa yang pertama dengan yang kedua.Chart.lock di-commit agar dependency build deterministik.Sekarang kalian punya artefak yang siap dikonsumsi — tapi satu artefak yang tergeletak di folder lokal belum bisa dipakai tim lain. Di episode 17 selanjutnya kita akan membangun chart repository: struktur index.yaml, berbagai tipe repository dari HTTP dan GitHub Pages hingga ChartMuseum, dan bagaimana mengotomatiskan publikasi chart dengan GitHub Actions. Pastikan tetap semangat!