Mengelola satu chart untuk banyak environment: strategi organisasi file values (common, dev, staging, prod), workflow deployment dan promotion pipeline, environment parity, hingga Helmfile sebagai deklarasi release yang menyeluruh dengan environment management dan dependency antar release.

Setelah di episode 20 sebelumnya kita membahas keamanan chart — dari security context dan RBAC hingga signing dan admission controllers — pada episode kali ini kita membahas masalah yang sama-sama sering menghancurkan tim DevOps: bagaimana mengelola chart yang sama untuk environment yang berbeda. Momen ketika tim kalian tumbuh dari "kita punya satu cluster staging" menjadi "kita punya dev, staging, prod, bahkan per-cabang" adalah momen ketika semuanya bisa berantakan jika tidak disiapkan dengan strategi yang benar.
Bayangkan chart sebagai resep masakan, dan environment sebagai dapur tempat masakan itu dimasak. Resepnya sama — bahan dasarnya identik — tapi di dapur dev kalian masak untuk satu-dua orang dengan api sedang, di dapur staging kalian uji resepnya persis seperti produksi, dan di dapur produksi kalian masak untuk ribuan orang dengan standar higienitas paling ketat. Kalian tidak menulis ulang resep untuk tiap dapur; kalian menyesuaikan porsinya, suhu apinya, dan standar bahan-bahannya.
Masalah yang muncul tanpa strategi yang baik bisa kita lihat di banyak tim: values.yaml yang penuh komentar # TODO: ubah untuk prod, nilai yang ditimpa secara manual lewat --set yang tidak tercatat di mana pun, atau — yang paling parah — tiga copy chart yang di-fork untuk tiga environment dan perlahan-lahan menyimpang sampai tidak ada yang tahu mana yang benar.
Pada episode ini kita akan membedah: strategi environment secara umum, organisasi file values yang benar, workflow deployment dan promotion pipeline, environment parity, dan ditutup dengan Helmfile — alat yang mengubah serangkaian perintah Helm ad-hoc menjadi deklarasi release yang utuh, dapat direview, dan dapat di-audit.
Ada tiga pendekatan yang beredar di industri, dan masing-masing punya trade-off:
1. Satu chart + banyak file values. Satu chart tetap, setiap environment punya file values sendiri yang ditumpuk di atas nilai default. Ini pendekatan paling umum dan paling disarankan untuk tim kecil-menengah. Keuntungannya: satu sumber kode chart, diff antar environment mudah dilihat dengan membandingkan file values. Kelemahannya: jika environment membutuhkan perbedaan struktural yang besar (bukan sekadar nilai), chart bisa dipaksa menampung banyak kondisional yang menyulitkan.
2. Environment-specific charts. Chart terpisah per environment — misalnya myapp-dev dan myapp-prod. Ini pola anti-pattern untuk sebagian besar kasus: logika aplikasi di-duplicate, perbaikan bug harus di-copy ke tiga tempat, dan drift menjadi tak terelakkan. Satu-satunya kasus yang membenarkan ini adalah ketika environment benar-benar menjalankan versi aplikasi yang berbeda secara struktural — dan itupun sebaiknya diselesaikan dengan library chart atau hooks.
3. Overlay patterns. Meniru model Kustomize: satu nilai dasar, lalu overlay per environment yang menimpa sebagian. Di Helm, ini direalisasikan dengan mekanisme merge file values yang sudah kita pelajari di episode 6 — file values tidak saling menggantikan secara menyeluruh, melainkan di-merge dengan nilai dari file yang lebih tinggi menimpa yang lebih rendah.
Hirarki merge Helm yang harus kalian hafal (dari prioritas terendah ke tertinggi): values.yaml bawaan chart → file -f pertama → file -f kedua → ... → --set inline. Urutan ini adalah kunci dari semua strategi yang akan kita bahas.
Pola yang paling banyak dipakai di industri adalah membagi file values menjadi dua lapis: common (nilai yang sama di semua environment) dan per-environment (nilai yang berbeda). Struktur repository yang ideal:
myapp/
├── charts/ # chart utama
│ └── myapp/
│ ├── Chart.yaml
│ ├── values.yaml # default bawaan chart
│ └── templates/
└── deploy/
├── values-common.yaml # sama untuk semua environment
├── values-dev.yaml
├── values-staging.yaml
└── values-prod.yamlKenapa values-common.yaml penting padahal values.yaml bawaan chart sudah ada? Karena ada nilai yang harus eksplisit direview di repo deployment — misalnya versi image yang disepakati, atau konfigurasi yang spesifik organisasi tapi sama di semua environment. Memisahkannya membuat review PR lebih fokus: perubahan di values-common.yaml berarti "perubahan yang memengaruhi semua environment" — sesuatu yang harus disetujui lebih ketat daripada perubahan di values-dev.yaml.
Contoh values-common.yaml yang realistis:
replicaCount: 2
image:
repository: ghcr.io/myorg/myapp
tag: 1.24.0
pullPolicy: Always
serviceAccount:
create: true
name: myapp
securityContext:
runAsNonRoot: true
runAsUser: 65534
runAsGroup: 65534
seccompProfile:
type: RuntimeDefault
imagePullSecrets:
- name: ghcr-pull-secretDan inilah contoh values-prod.yaml — file yang paling dibedah saat audit produksi:
replicaCount: 6
resources:
requests:
cpu: 500m
memory: 512Mi
limits:
cpu: "2"
memory: 2Gi
autoscaling:
enabled: true
minReplicas: 4
maxReplicas: 12
targetCPUUtilizationPercentage: 70
ingress:
enabled: true
className: nginx
hosts:
- host: app.mycompany.com
paths:
- path: /
pathType: Prefix
tls:
- hosts:
- app.mycompany.com
secretName: app-tls
featureFlags:
paymentsEnabled: true
betaFeatures: false
env:
NODE_ENV: production
LOG_LEVEL: infoPerhatikan apa yang tidak ada di file ini: tidak ada secret, tidak ada username, tidak ada token. Semua nilai sensitif datang dari External Secrets Operator (pola episode 20). File ini hanya berisi konfigurasi — sehingga aman untuk disimpan di Git dan direview dengan santai.
Dengan struktur file values di atas, alur deploy per environment menjadi rangkaian perintah yang hampir identik — hanya file values dan namespace yang berbeda:
helm upgrade --install myapp ./charts/myapp \
-f deploy/values-common.yaml \
-f deploy/values-prod.yaml \
-n prod \
--atomic \
--timeout 10mKekuatan pola ini: perintah yang sama dipakai di semua environment, jadi tidak ada "cara deploy yang berbeda-beda". Yang membedakan hanyalah argumentum. Dan karena seluruh perintah direkam di pipeline (bukan diketik manual di laptop), setiap deploy bisa diaudit: kapan, dari versi apa, ke environment mana.
Promotion pipeline adalah konsep yang membuat workflow ini disiplin: tidak ada yang deploy ke produksi tanpa melewati staging terlebih dahulu. Alurnya kira-kira:
develop memicu deploy otomatis ke namespace dev — feedback cepat, boleh rusak.main memicu deploy ke staging — di sini aplikasi diuji persis seperti produksi, termasuk migrasi database dan smoke test.prod tidak otomatis — butuh trigger manual (atau approval) dan hanya dari artefak yang sudah terbukti di staging.Kunci dari promotion yang sehat: artefak yang sama yang diuji di staging harus yang di-deploy ke produksi. Karena itu versi image dan versi chart di-pin di values-common.yaml dan hasil staging harus "ditandatangani" (lewat status test di CI) sebelum dipromosikan. Kalian tidak sedang men-deploy nilai yang berbeda — kalian men-deploy hal yang sama ke tempat yang lebih berisiko.
Paradoks multi-environment adalah: kalian ingin environment sedekat mungkin dengan produksi (supaya "works in dev" benar-benar berarti "works in prod"), tapi kalian juga tidak ingin environment semahal dan seketat produksi. Jawabannya bukan "semua harus sama" melainkan perbedaan harus disengaja dan terdokumentasi, bukan akibat dari drift yang tidak terkontrol.
Perbedaan yang wajar antar environment:
| Aspek | Dev | Staging | Prod |
|---|---|---|---|
| Replica count | 1 | 3 | 6 |
| Resource request/limit | Kecil | Menengah | Besar |
| Database | Ephemeral (SQLite/minio) | Terkelola, data dummy | Terkelola, data nyata |
| Feature flags | Semua aktif | Mirip prod | Sesuai strategi |
| TLS / ingress | Opsional | Wajib | Wajib |
| Secrets | Dummy | Mirip prod, bukan asli | Asli dari vault |
Perbedaan yang tidak wajar: versi image berbeda di staging dan prod, konfigurasi yang seharusnya sama tapi ternyata di-set manual, atau chart yang sudah tidak sinkron dengan repo. Ini yang menyebabkan fenomena klasik "lolos di staging, hancur di produksi".
Teknik yang menjaga parity tetap dekat: gunakan --set sesedikit mungkin (karena tidak tercatat di Git — lebih baik file values), jadikan values-prod.yaml sebagai acuan dan pastikan staging di-render dari struktur yang sama, serta otomasi "promotion check" yang memverifikasi bahwa chart dan values yang dipakai di staging identik dengan yang akan dipakai di prod.
Tip
Gunakan helm template untuk diff antar environment. Sebelum deploy, render chart dengan -f values-staging.yaml dan -f values-prod.yaml, lalu bandingkan outputnya: helm template myapp ./charts/myapp -f deploy/values-common.yaml -f deploy/values-staging.yaml > /tmp/staging.yaml dan helm template ... -f deploy/values-prod.yaml > /tmp/prod.yaml, lalu diff /tmp/staging.yaml /tmp/prod.yaml. Ini menunjukkan secara eksplisit semua perbedaan manifest yang akan dipakai — cara tercepat menangkap konfigurasi yang tidak sengaja berbeda.
Setelah beberapa chart — katakanlah myapp, redis, ingress-nginx, dan cert-manager — workflow dengan perintah helm upgrade --install satu per satu mulai terasa rapuh: urutannya salah bisa menyebabkan kegagalan berantai, flag yang berbeda-beda harus diingat, dan tidak ada satu tempat yang mendeskripsikan "keseluruhan sistem". Di sinilah Helmfile masuk.
Helmfile adalah alat yang mendeklarasikan semua release Helm dalam satu file YAML, lengkap dengan environment, nilai, dan dependency antar release. Ia adalah "Terraform untuk Helm" — dan justru popular di platform engineering karena satu file helmfile.yaml adalah dokumentasi yang dapat dieksekusi tentang apa yang berjalan di cluster.
Struktur inti sebuah helmfile.yaml:
environments:
prod:
values:
- deploy/values-common.yaml
- deploy/values-prod.yaml
staging:
values:
- deploy/values-common.yaml
- deploy/values-staging.yaml
dev:
values:
- deploy/values-common.yaml
- deploy/values-dev.yaml
repositories:
- name: bitnami
url: https://charts.bitnami.com/bitnami
- name: ingress-nginx
url: https://kubernetes.github.io/ingress-nginx
releases:
- name: ingress-nginx
namespace: ingress-nginx
chart: ingress-nginx/ingress-nginx
version: 4.9.0
createNamespace: true
- name: cert-manager
namespace: cert-manager
chart: jetstack/cert-manager
version: 1.14.4
createNamespace: true
needs:
- ingress-nginx/ingress-nginx
- name: myapp
namespace: myapp
chart: ./charts/myapp
values:
- deploy/values-common.yaml
valuesTemplate:
- "{{ .Values | toYaml }}"
needs:
- cert-manager/cert-managerMari bedah bagian-bagian pentingnya:
environments mendefinisikan nilai per-environment yang bisa direferensikan di dalam file. Saat menjalankan helmfile -e prod apply, variabel {{ .Values }} akan berisi gabungan values-common.yaml + values-prod.yaml. Ini membuat satu file helmfile melayani semua environment tanpa duplikasi.
releases mendeklarasikan tiap release. Perhatikan needs: — ini dependency antar release yang membuat Helmfile menjalankan release dalam urutan yang benar: cert-manager menunggu ingress-nginx siap (karena membutuhkan IngressClass), dan myapp menunggu cert-manager (karena TLS di-manage-nya). Tanpa needs, urutan install tidak dijamin — dan ini penyebab klasik "cert-manager gagal karena IngressClass belum ada".
valuesTemplate adalah fitur yang membuat Helmfile sangat kuat: ia bisa me-render nilai dari variabel environment helmfile itu sendiri, sehingga seluruh konfigurasi environment mengalir ke chart tanpa perintah -f manual yang rentan salah.
Cara menggunakannya:
helmfile -e dev apply # terapkan seluruh release di dev
helmfile -e staging diff # lihat perubahan sebelum terapkan (dry-run)
helmfile -e prod apply --confirm # terapkan dengan konfirmasi manual
helmfile -e prod destroy # hapus semua release
helmfile -e dev list # lihat status semua releasehelmfile apply adalah jantungnya — ia melakukan diff, meminta konfirmasi, lalu menerapkan release yang berubah. Ini adalah state management dalam bentuk paling praktis: Helmfile menyimpan state di dalam cluster (lewat status release Helm), jadi ia tahu release mana yang sudah terpasang dan apa perubahannya — bukan hanya "install ulang semuanya" seperti skrip naif.
Note
Helmfile vs ArgoCD/Flux. Keduanya punya peran berbeda. Helmfile adalah orchestrator yang dijalankan di pipeline — ia dieksekusi ketika kalian menjalankannya (atau oleh CI). ArgoCD dan Flux adalah GitOps controllers yang berjalan terus-menerus di cluster — mereka mencuplik Git dan menyinkronkan state secara otomatis. Helmfile lebih cocok untuk workflow push-based (pipeline), GitOps tools untuk workflow pull-based (yang akan kita bahas detail di episode 25). Banyak tim production justru menggunakan keduanya: Helmfile untuk mengelola bootstrap dan release yang kompleks, GitOps tool untuk drift detection sehari-hari.
Pada episode 21 ini kita telah membahas cara mengelola satu chart untuk banyak environment dengan disiplin: strategi environment (satu chart + file values, bukan fork chart), organisasi file values (values-common untuk yang seragam, values-dev/staging/prod untuk yang berbeda), workflow deployment dengan promotion pipeline yang mengalir dari dev ke staging ke produksi, environment parity yang memastikan perbedaan antar environment adalah keputusan, bukan drift, dan Helmfile yang mendeklarasikan seluruh release beserta dependency dan nilai environment-nya dalam satu file yang dapat dieksekusi.
Inti yang harus kalian bawa:
needs: untuk urutan, environments: untuk nilai, apply untuk state management.Di episode 22 selanjutnya kita akan membahas Helm plugins: ekosistem yang memperluas Helm di luar kemampuan bawaannya — mulai dari helm-diff yang memvisualisasikan perubahan sebelum diterapkan, helm-secrets untuk enkripsi, helm-unittest untuk testing, hingga cara membuat plugin kalian sendiri. Sampai jumpa di episode 22!