Belajar Helm Chart - Hooks & Manajemen Lifecycle
Episode 12 of 30

Belajar Helm Chart - Hooks & Manajemen Lifecycle

Memanfaatkan siklus hidup release: konsep pre/post-install, upgrade, rollback, dan delete hooks; annotation helm.sh/hook, hook-weight, dan hook-delete-policy; implementasi migration Job, backup, smoke test, cleanup, hingga praktik terbaik idempotency dan timeout.

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

Pendahuluan

Setelah di episode 11 sebelumnya kita membangun chart dari komponen-komponen lewat dependencies dan subcharts — dan di episode-episode 3 sampai 5 kita mempelajari instalasi, upgrade, dan rollback — pada episode kali ini kita membahas apa yang membuat release menjadi lebih dari sekadar kumpulan manifest: hooks, mekanisme Helm untuk menjalankan tindakan di titik-titik kritis siklus hidup sebuah release.

Kenapa ini penting? Pikirkan aplikasi database yang nyata. Sebelum versi baru aplikasi di-deploy, skema database harus di-migrasi lebih dulu — jika tidak, versi baru yang butuh kolom baru akan error begitu berjalan. Setelah aplikasi ter-deploy, tim ingin memastikan smoke test berjalan sebelum trafik dialihkan. Sebelum release dihapus, mungkin data sementara perlu dibersihkan. Semua tindakan ini tidak bisa diwakili oleh Deployment atau Service biasa — ia butuh urutan eksekusi yang tepat relatif terhadap resource lain, dan berjalan hanya pada titik tertentu. Tanpa hooks, tim harus mengelola migrasi, backup, dan smoke test secara manual di luar Helm — rapuh dan mudah terlewat. Dengan hooks, seluruh urutan itu menjadi bagian dari definisi chart itu sendiri, deterministik dan terdokumentasi. Inilah yang membuat Helm benar-benar menjadi package manager, bukan sekadar templating engine.

Konsep Hooks

Hook adalah resource Kubernetes biasa (biasanya Job atau Pod) yang ditandai dengan annotation khusus. Saat Helm melakukan sebuah event dalam siklus hidup release, ia mencari template yang memiliki annotation helm.sh/hook yang cocok dengan event tersebut, merender-nya, dan mengeksekusinya pada waktu yang tepat.

Helm mendefinisikan sepuluh jenis hook:

HookKapan Dieksekusi
pre-installSetelah template dirender, sebelum resource apapun dibuat
post-installSetelah semua resource release berhasil dibuat
pre-deleteSebelum resource apapun dihapus
post-deleteSetelah semua resource release dihapus
pre-upgradeSebelum resource release di-upgrade
post-upgradeSetelah semua resource release berhasil di-upgrade
pre-rollbackSebelum resource release di-rollback
post-rollbackSetelah semua resource release berhasil di-rollback
pre-crd-installSebelum CRD (Custom Resource Definition) di-install
testSaat helm test dijalankan (dibahas di episode 14)

Bayangkan hooks sebagai middleware atau lifecycle callbacks dalam framework web: aplikasi utama tidak peduli detailnya, tapi setiap fase punya titik penyisipan yang bisa dimanfaatkan. Bedanya, titik penyisipan ini dijalankan oleh Helm dengan semantik yang ketat — gagal satu hook berarti operasi gagal.

Implementasi Hooks: Annotation dan Atribut

Sebuah template menjadi hook cukup dengan menambahkan annotation helm.sh/hook. Tiga annotation yang mengendalikan perilakunya:

  • helm.sh/hook — daftar event yang memicu resource ini, dipisahkan koma. Contoh: helm.sh/hook: pre-upgrade,post-install.
  • helm.sh/hook-weight — bilangan bulat yang menentukan urutan eksekusi antar hook pada event yang sama. Semakin kecil angka, semakin dulu dijalankan. Defaultnya 0, bisa negatif.
  • helm.sh/hook-delete-policy — menentukan kapan resource hook dihapus setelah dieksekusi. Nilai yang tersedia: before-hook-creation (hapus hook lama sebelum membuat yang baru — berguna untuk upgrade berulang), hook-succeeded (hapus setelah sukses), hook-failed (hapus setelah gagal). Bisa digabungkan dengan koma.

Resource hook tidak dikelola sebagai bagian dari release seperti resource biasa. Ia dibuat, dieksekusi, dan dihapus sesuai delete-policy; saat helm rollback atau helm uninstall, hook lama tidak ikut di-rollback. Inilah mengapa helm get manifest tidak menampilkan hook — untuk melihatnya gunakan helm get hooks.

templates/hooks/migrate.yaml - contoh hook structure
apiVersion: batch/v1
kind: Job
metadata:
  name: {{ include "myapp.fullname" . }}-migrate
  annotations:
    "helm.sh/hook": pre-upgrade
    "helm.sh/hook-weight": "-5"
    "helm.sh/hook-delete-policy": hook-succeeded,before-hook-creation
    "helm.sh/hook-ttl": "0"
spec:
  template:
    spec:
      restartPolicy: Never
      containers:
        - name: migrate
          image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
          command: ["/bin/sh", "-c", "npm run migrate -- --force"]

Perhatikan dua annotation tambahan di atas: helm.sh/hook-ttl memberi tahu Helm untuk membersihkan Job yang sudah selesai setelah TTL tertentu (fitur Kubernetes), berguna jika delete-policy tidak menangani kasus kegagalan. Dan restartPolicy: Never — Job tidak boleh menggunakan Always, karena Job yang selesai dengan sukses tidak boleh restart.

Sumber Daya Hook: Job, Pod, dan Perilakunya

Helm menjalankan hook dengan cara yang berbeda tergantung jenis resource:

  • Job — cara yang paling umum dan paling disarankan. Helm menunggu Job selesai (status Succeeded) sebelum melanjutkan operasi utama. Jika Job Failed, operasi dianggap gagal dan (tergantung flag) bisa di-rollback otomatis.
  • Pod — dijalankan, dan Helm menunggu Pod selesai. Kurang ideal dibanding Job karena Pod tidak punya retry semantics bawaan.
  • Resource lain (ConfigMap, Secret, PVC) — dibuat sebagai hook, tapi tidak "menunggu" apapun; fungsinya hanya menyediakan objek yang dibutuhkan hook lain (misalnya ConfigMap konfigurasi migrasi yang dibaca Job).

Output hook disimpan oleh Helm dalam ConfigMap/Secret bernama <release>-<hook-name>.hooks — ini yang memungkinkan kalian melihat log hook setelah selesai dengan helm get hooks. Dan kegagalan hook tercatat di status release: release akan berstatus failed, dan helm list --failed akan menampilkannya.

Warning

Jika hook gagal saat install, Helm tidak meng-uninstall hook-nya secara otomatis jika delete-policy tidak mengaturnya. Job yang menggantung akan tetap ada dan memakan resource. Kombinasi restartPolicy: Never, backoffLimit yang wajar, helm.sh/hook-delete-policy yang tepat, dan (jika perlu) helm.sh/hook-ttl adalah pertahanan standar terhadap job zombie. Selalu periksa dengan kubectl get jobs --all-namespaces setelah kegagalan.

Use Case Hooks yang Umum

Hooks menjadi alat yang benar-benar berguna ketika diterapkan pada kebutuhan nyata. Lima pola berikut adalah yang paling sering ditemui di production:

1. Database Migration (pre-upgrade dan pre-install)

Pola paling klasik — dan contoh yang sudah kita lihat. Sebelum versi aplikasi baru di-deploy, jalankan migrasi skema. Penting: migrasi sebaiknya idempotent (aman dijalankan ulang), karena pre-upgrade akan berjalan setiap kali chart di-upgrade, dan jika hook gagal lalu retry, migrasi bisa dijalankan dua kali. Strategi umum: tambahkan flag seperti --force untuk migrasi yang dirancang idempotent, atau pisahkan script migrasi dalam container yang sama.

templates/hooks/migrate-job.yaml
apiVersion: batch/v1
kind: Job
metadata:
  name: {{ include "myapp.fullname" . }}-migrate
  annotations:
    "helm.sh/hook": pre-upgrade,pre-install
    "helm.sh/hook-weight": "-5"
    "helm.sh/hook-delete-policy": hook-succeeded,before-hook-creation
spec:
  template:
    spec:
      restartPolicy: OnFailure
      containers:
        - name: migrate
          image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
          env:
            - name: DATABASE_URL
              valueFrom:
                secretKeyRef:
                  name: {{ .Values.database.existingSecret }}
                  key: url
          command: ["/bin/sh", "-c", "npx prisma migrate deploy"]

2. Backup Sebelum Upgrade (pre-upgrade)

"Better safe than sorry" dalam bentuk yang otomatis. Hook dengan weight kecil (-10) menjalankan dump database ke storage eksternal sebelum resource apa pun berubah:

templates/hooks/backup.yaml
apiVersion: batch/v1
kind: Job
metadata:
  name: {{ include "myapp.fullname" . }}-backup
  annotations:
    "helm.sh/hook": pre-upgrade
    "helm.sh/hook-weight": "-10"
    "helm.sh/hook-delete-policy": hook-succeeded
spec:
  template:
    spec:
      restartPolicy: OnFailure
      containers:
        - name: backup
          image: "postgres:16"
          command: ["/bin/sh", "-c"]
          args:
            - |
              pg_dump "$DATABASE_URL" | gzip | \
              aws s3 cp - "s3://myapp-backups/$(date -u +%F).sql.gz"
          env:
            - name: DATABASE_URL
              valueFrom:
                secretKeyRef:
                  name: {{ .Values.database.existingSecret }}
                  key: url

3. Smoke Test Setelah Install (post-install)

Memastikan aplikasi benar-benar merespons sebelum dianggap sukses. Hook ini membuat Pod yang meng-curl endpoint aplikasi:

templates/hooks/smoke-test.yaml
apiVersion: batch/v1
kind: Job
metadata:
  name: {{ include "myapp.fullname" . }}-smoke-test
  annotations:
    "helm.sh/hook": post-install
    "helm.sh/hook-weight": "5"
    "helm.sh/hook-delete-policy": hook-succeeded
spec:
  template:
    spec:
      restartPolicy: Never
      containers:
        - name: smoke
          image: curlimages/curl:latest
          command:
            - /bin/sh
            - -c
            - |
              code=$(curl -s -o /dev/null -w "%{http_code}" \
                http://{{ include "myapp.fullname" . }}:{{ .Values.service.port }}/healthz)
              test "$code" = "200" || exit 1

4. Cleanup Job (post-delete)

Saat release di-uninstall, resource utama dihapus — tapi data eksternal (misalnya bucket S3, atau catatan di database pusat) tidak ikut terhapus. Hook post-delete menutup celah ini:

templates/hooks/cleanup.yaml
apiVersion: batch/v1
kind: Job
metadata:
  name: {{ include "myapp.fullname" . }}-cleanup
  annotations:
    "helm.sh/hook": post-delete
    "helm.sh/hook-delete-policy": hook-succeeded
spec:
  template:
    spec:
      restartPolicy: Never
      containers:
        - name: cleanup
          image: "curlimages/curl:latest"
          command:
            - /bin/sh
            - -c
            - 'curl -X DELETE "https://api.internal/cleanup?release={{ .Release.Name }}"'

5. Secret Generation (pre-install)

Generate secret sekali sebelum release di-install, lalu biarkan resource lain membacanya:

templates/hooks/secret-generator.yaml
apiVersion: v1
kind: Secret
metadata:
  name: {{ include "myapp.fullname" . }}-session-secret
  annotations:
    "helm.sh/hook": pre-install
    "helm.sh/hook-weight": "-5"
type: Opaque
data:
  sessionKey: {{ randAlphaNum 32 | b64enc | quote }}

Pola ini memastikan secret dibuat sebelum Deployment merujuknya — karena deployment hook dijalankan setelah semua resource normal, tapi secret ini dipaksa ada lebih dulu berkat hook pre-install.

6. Debugging Hooks yang Gagal

Hook yang gagal adalah salah satu debugging tersulit dalam Helm — bukan karena mekanismenya rumit, tapi karena resource hook bersifat sementara dan bisa lenyap sebelum sempat diperiksa. Urutan langkah berikut akan menyelamatkan kalian dari frustrasi:

  1. Lihat status release. helm status <release> (atau helm list --failed) memberi tahu hook mana yang gagal — pesan error biasanya menyebut nama Job yang bermasalah.
  2. Periksa Job sebelum dihapus. Jika delete-policy tidak menghapus job gagal, kubectl get jobs -n <ns> akan menampilkannya. Baca log kontainernya dengan kubectl logs job/<nama> -n <ns>.
  3. Paksa hook tetap ada untuk inspeksi. Saat debug, set helm.sh/hook-delete-policy: hook-succeeded (tanpa hook-failed) agar job yang gagal tidak dihapus setelah inspeksi. Jangan lupa menghapus manual setelah selesai.
  4. Gunakan --debug. helm upgrade <release> <chart> --debug --dry-run menampilkan hook yang dirender beserta annotation-nya, memastikan hook benar-benar terdefinisi dengan event yang tepat.
Alur debugging hook
helm list --failed -A
helm status <release> -n <ns>
kubectl get jobs -n <ns>
kubectl logs job/<job-name> -n <ns> --tail=50

Satu kesalahan penulisan annotation — misalnya pre-install di template yang seharusnya pre-upgrade — adalah penyebab paling umum hook tidak pernah jalan. Selalu verifikasi dengan --dry-run --debug yang menampilkan annotation hasil render, sebelum mengejar misteri di dalam cluster.

Praktik Terbaik Hooks

Hooks adalah mekanisme yang kuat, dan kekuatan itu datang dengan tanggung jawab. Berikut disiplin yang menjaga hooks tetap aman di production:

  1. Idempotency adalah hukum pertama. Hook bisa berjalan lebih dari sekali (retry, upgrade berulang, rollback). Migration, backup, dan cleanup harus aman dijalankan berulang — gunakan --force migration yang idempotent, nama file backup ber-timestamp, dan cleanup yang tidak error saat data sudah tidak ada.
  2. Gunakan hook-weight untuk urutan eksplisit. Urutan eksekusi antar hook pada event yang sama ditentukan weight, bukan urutan deklarasi di template. Tetapkan weight dengan sengaja dan dokumentasikan di komentar: backup -10, migrate -5, smoke test 5.
  3. Atur delete-policy dengan cermat. hook-succeeded,before-hook-creation adalah kombinasi paling aman untuk upgrade berulang: hook lama dihapus sebelum yang baru dibuat, dan hook yang sukses tidak menumpuk. Untuk debugging kegagalan, tambahkan hook-failed agar job yang gagal tetap bisa diinspeksi.
  4. Konfigurasi timeout. Operasi Helm memiliki timeout global (--timeout). Job migrasi yang butuh waktu lama bisa melewatinya. Beri Job activeDeadlineSeconds dan sesuaikan timeout Helm, atau jalankan migrasi sebagai operasi asinkron yang dipantau di luar hook.
  5. Error handling yang eksplisit. Gunakan restartPolicy: OnFailure atau Never, dan backoffLimit yang masuk akal. Script di dalam container harus keluar dengan kode non-zero saat gagal — jangan menelan error.
  6. Jangan menyimpan data penting di hook. Hook bersifat sementara; jika butuh persistensi, gunakan PVC atau storage eksternal. Dan jangan pernah meletakkan secret statis di template hook — baca dari Secret yang sudah ada.
  7. Pertimbangkan --atomic. Saat upgrade, kombinasi --atomic --timeout 5m memastikan bahwa jika hook atau resource gagal, seluruh operasi di-rollback ke revisi sebelumnya — termasuk resource yang sudah dibuat — sehingga cluster tidak dibiarkan dalam keadaan setengah jadi.
Upgrade yang aman dengan hooks
helm upgrade myapp ./myapp \
  --namespace staging \
  --atomic \
  --timeout 10m

Penutup

Pada episode 12 ini kalian telah memahami hooks sebagai titik penyisipan dalam siklus hidup release: sepuluh jenis hook (dari pre-install, post-install, pre-upgrade, post-upgrade, hingga pre-delete, post-delete, pre-rollback, post-rollback, pre-crd-install, dan test), cara menandai template dengan annotation helm.sh/hook, mengatur urutan dengan hook-weight, dan mengendalikan pembersihan dengan hook-delete-policy. Kalian juga telah melihat lima use case production yang nyata — migrasi database, backup sebelum upgrade, smoke test, cleanup, dan secret generation — beserta praktik terbaik yang menjaganya tetap idempotent, terukur, dan aman.

Hooks adalah salah satu alasan utama mengapa tim memilih Helm dibanding sekadar kubectl apply: urutan operasi yang sebelumnya dijalankan manual oleh engineer (migrasi dulu, deploy lalu) kini terdokumentasi di dalam chart itu sendiri dan dieksekusi secara konsisten setiap kali. Di episode 13 selanjutnya kita akan menambahkan lapisan pertahanan berikutnya dengan schema validation menggunakan JSON Schema — cara Helm memvalidasi input values sebelum render, sehingga typo dan konfigurasi salah tertangkap dengan pesan error yang jelas, bukan setelah aplikasi gagal di cluster. Sampai jumpa di episode 13!

Belajar Helm Chart - Hooks & Manajemen Lifecycle | Belajar Helm Chart