Mengotomasi seluruh siklus hidup chart dalam CI/CD: pipeline GitHub Actions (lint, unittest, package, push ke OCI GHCR, deploy ke cluster), GitLab CI/CD dengan environment management dan review apps, Jenkins dan Tekton, serta pengujian chart dengan chart-testing (ct) dan praktik terbaik versioning.

Setelah di episode 23 sebelumnya kita membahas Helm SDK — menggunakan Helm sebagai library Go di dalam tooling kalian — pada episode kali ini kita membungkus semua yang sudah dipelajari ke dalam satu sistem: pipeline CI/CD yang mengotomasi seluruh siklus hidup chart. Jika sebelumnya kalian men-deploy manual dengan helm upgrade di terminal, sekarang kita masuk ke dunia di mana setiap commit yang masuk ke repo memicu rangkaian langkah otomatis: lint, test, package, push chart ke registry, dan — jika lolos — deploy ke cluster.
Kenapa ini penting? Karena manual deployment adalah tempat kesalahan dan bottleneck paling besar di tim. Perintah helm upgrade yang diketik manusia bisa salah flag, salah environment, atau tidak tercatat di mana pun. Pipeline mengubahnya menjadi prosedur yang terdokumentasi, dapat diaudit, dan berulang tanpa lelah. Bayangkan pabrik yang merakit mobil: setiap mobil melewati jalur produksi yang sama — pengecekan, perakitan, uji, pengiriman. Tidak ada karyawan yang merakit mobil di meja kerjanya masing-masing dengan cara yang berbeda. Pipeline CI/CD adalah jalur produksi untuk chart kalian.
Ekosistem CI/CD untuk Helm sangat kaya — dan ini bisa membingungkan: ada GitHub Actions, GitLab CI/CD, Jenkins, Tekton, belum lagi ArgoCD dan Flux (yang akan kita bahas di episode 25). Setiap alat punya pendekatan berbeda terhadap masalah yang sama. Pada episode ini kita akan membedahnya satu per satu, dengan fokus pada apa yang unik di masing-masing, lalu menutup dengan praktik terbaik yang berlaku di semua platform.
Sebelum membedah alat-alatnya, ada baiknya kita sepakati dulu apa yang seharusnya terjadi di pipeline Helm yang sehat. Terlepas dari platformnya, rangkaian ini selalu muncul:
helm lint memeriksa validitas struktural chart.helm-unittest menguji render template tanpa cluster.kubeconform memvalidasi manifest terhadap skema Kubernetes.helm package menghasilkan .tgz yang versinya sudah benar.Batas antara "proses" dan "deploy" itu penting: yang diuji dan di-push adalah artefak yang sama yang di-deploy. Chart yang sudah melewati langkah 1–5 adalah artefak produksi; langkah 6 hanya mengambil artefak tersebut. Ini menghindari masalah "saya lint di mesin saya tapi ternyata berbeda di pipeline".
GitHub Actions adalah pilihan paling populer untuk repo chart di GitHub. Dua action komunitas yang wajib kalian kenal: azure/setup-helm untuk menginstal binary Helm di runner, dan azure/k8s-set-context untuk menghubungkan workflow ke cluster. Mari kita lihat workflow lengkapnya:
name: Chart Release
on:
push:
branches: [main]
paths: ["charts/**"]
jobs:
test-and-package:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Helm
uses: azure/setup-helm@v4
with:
version: v3.14.0
- name: Setup ct (chart-testing)
uses: helm/chart-testing-action@v2
- name: Install kubeconform
run: |
curl -sL https://github.com/yannh/kubeconform/releases/download/v0.6.6/kubeconform-linux-amd64.tar.gz \
| tar xz -C /usr/local/bin kubeconform
- name: Run chart-testing lint
run: ct lint --config .github/ct.yaml --check-version-increment=true
- name: Run helm lint
run: helm lint ./charts/myapp
- name: Run unit tests
run: helm unittest ./charts/myapp
- name: Validate manifests with kubeconform
run: |
helm template myapp ./charts/myapp --validate=false > /tmp/rendered.yaml
kubeconform -strict -summary /tmp/rendered.yaml
- name: Package chart
run: |
helm package ./charts/myapp -d ./artifacts
echo "PACKAGE=$(ls ./artifacts/*.tgz | head -1)" >> "$GITHUB_ENV"
- name: Login to GHCR
run: echo "${{ secrets.GITHUB_TOKEN }}" | helm registry login ghcr.io -u ${{ github.actor }} --password-stdin
- name: Push chart to OCI registry
run: helm push "${{ env.PACKAGE }}" oci://ghcr.io/${{ github.repository_owner }}/charts
deploy:
needs: test-and-package
runs-on: ubuntu-latest
environment: staging
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Helm
uses: azure/setup-helm@v4
- name: Set kubeconfig context
uses: azure/k8s-set-context@v4
with:
method: kubeconfig
kubeconfig: ${{ secrets.STAGING_KUBECONFIG }}
- name: Deploy to staging
run: |
helm upgrade --install myapp oci://ghcr.io/${{ github.repository_owner }}/charts/myapp \
--version 1.24.0 \
-f deploy/values-common.yaml \
-f deploy/values-staging.yaml \
-n staging \
--atomic \
--timeout 10mMari bedah bagian-bagian pentingnya. ct lint --check-version-increment=true adalah penjaga pertama: chart-testing memeriksa bahwa setiap perubahan chart menaikkan versi di Chart.yaml — mencegah "re-deploy chart yang sama dengan kode berbeda", yang membuat rollback mustahil. kubeconform -strict memvalidasi bahwa manifest yang di-render sesuai dengan skema Kubernetes yang valid — menangkap API yang di-deprecate sebelum sampai ke cluster. environment: staging di job deploy adalah fitur GitHub Environments — memungkinkan proteksi (required reviewers) dan menyimpan secret khusus environment.
Perhatikan pola push OCI: kita login ke GHCR dengan GITHUB_TOKEN, lalu helm push ke oci://ghcr.io/.... Ini mengikuti pola yang kita bahas di episode 18 — chart didistribusikan sebagai artefak OCI, dan job deploy menariknya dari registry (oci://ghcr.io/.../myapp --version 1.24.0), bukan dari source tree. Inilah kunci konsistensi: pipeline tidak men-deploy dari ./charts/myapp di repo (yang bisa saja sudah berubah), melainkan dari artefak yang sudah di-publish dan diberi versi.
GitLab CI/CD memiliki pendekatan yang berbeda: semua pipeline didefinisikan dalam file .gitlab-ci.yml dengan konsep stages (urutan fase) dan environments (target deployment). Kekuatan GitLab di sini adalah review apps — kemampuan mendeploy versi setiap merge request ke environment sementara sehingga developer bisa melihat hasilnya sebelum merge.
Contoh inti pipeline GitLab untuk Helm:
stages:
- test
- build
- deploy
variables:
CHART: myapp
HELM_VERSION: "3.14.0"
before_script:
- curl -fsSL https://get.helm.sh/helm-v${HELM_VERSION}-linux-amd64.tar.gz | tar xz
- mv linux-amd64/helm /usr/local/bin/helm
test-chart:
stage: test
script:
- helm lint ./charts/$CHART
- helm unittest ./charts/$CHART
- helm template $CHART ./charts/$CHART > /tmp/rendered.yaml
- kubeconform -strict -summary /tmp/rendered.yaml
artifacts:
paths:
- /tmp/rendered.yaml
expire_in: 1 week
package-chart:
stage: build
script:
- helm package ./charts/$CHART -d ./artifacts
artifacts:
paths:
- artifacts/*.tgz
expire_in: 1 week
deploy-staging:
stage: deploy
environment:
name: staging
url: https://staging.mycompany.com
rules:
- if: $CI_COMMIT_BRANCH == "main"
script:
- helm upgrade --install $CHART ./artifacts/$CHART-*.tgz \
-f deploy/values-common.yaml \
-f deploy/values-staging.yaml \
-n staging --atomic --timeout 10m
deploy-prod:
stage: deploy
environment:
name: production
url: https://app.mycompany.com
rules:
- if: $CI_COMMIT_BRANCH == "main"
- when: manual
script:
- helm upgrade --install $CHART ./artifacts/$CHART-*.tgz \
-f deploy/values-common.yaml \
-f deploy/values-prod.yaml \
-n prod --atomic --timeout 15mPerhatikan perbedaan krusial antara dua job deploy. deploy-staging berjalan otomatis saat branch main di-push. deploy-prod juga terpicu oleh push main, tapi karena when: manual, ia menunggu klik manusia di UI GitLab — inilah promotion gate yang kita bahas di episode 21, dibangun langsung ke pipeline. environment: memberi GitLab informasi tentang target deployment, lengkap dengan URL, sehingga GitLab menampilkan riwayat deploy per environment di UI — siapa, kapan, dan dari commit mana.
Jenkins adalah veteran CI/CD. Pendekatan Helm di Jenkins dilakukan lewat Jenkinsfile (Declarative Pipeline) dengan beberapa cara: memanggil sh 'helm ...' di node, atau menggunakan Jenkins Helm Plugin yang membungkus operasi Helm sebagai step-nya sendiri. Contoh ringkas:
pipeline {
agent any
environment {
HELM_HOME = '/usr/local/helm'
}
stages {
stage('Lint & Test') {
steps {
sh 'helm lint ./charts/myapp'
sh 'helm unittest ./charts/myapp'
}
}
stage('Package') {
steps {
sh 'helm package ./charts/myapp -d artifacts/'
archiveArtifacts artifacts: 'artifacts/*.tgz'
}
}
stage('Deploy to Staging') {
steps {
sh 'helm upgrade --install myapp artifacts/myapp-*.tgz -f deploy/values-staging.yaml -n staging'
}
}
stage('Deploy to Production') {
input 'Approve deploy to production?'
steps {
withCredentials([string(credentialsId: 'prod-kubeconfig', variable: 'KUBECONFIG')]) {
sh 'helm upgrade --install myapp artifacts/myapp-*.tgz -f deploy/values-prod.yaml -n prod'
}
}
}
}
}Pola input 'Approve...' di atas adalah mekanisme approval manual Jenkins — pipeline berhenti dan menunggu manusia menekan tombol. withCredentials menjaga kubeconfig produksi tetap sebagai credential Jenkins, tidak pernah tertulis di repo atau log. Ini pola penting: kredensial cluster tidak pernah ada di pipeline definition, hanya referensinya.
Tekton adalah pendekatan cloud-native: pipeline dijalankan sebagai Kubernetes resources (Tasks, Pipelines, Workspaces) di dalam cluster itu sendiri. Setiap langkah adalah sebuah container dalam pod. Untuk Helm, kalian menulis Tekton Task yang menjalankan perintah Helm dalam container:
apiVersion: tekton.dev/v1
kind: Task
metadata:
name: helm-upgrade
spec:
params:
- name: release
type: string
- name: namespace
type: string
- name: chart
type: string
workspaces:
- name: source
steps:
- name: helm-upgrade
image: alpine/helm:3.14.0
script: |
helm upgrade --install "$(params.release)" "$(params.chart)" \
-n "$(params.namespace)" \
-f "$(workspaces.source.path)/deploy/values-staging.yaml" \
--atomic --timeout 10m
securityContext:
runAsNonRoot: trueKeunikan Tekton: Workspaces adalah penyimpanan bersama antar task (bisa berupa PersistentVolume atau ConfigMap), jadi artefak yang di-package di satu task bisa dipakai task berikutnya tanpa harus di-upload ke registry perantara. Dan karena semuanya berjalan sebagai resource Kubernetes, pipeline Tekton bisa memakai RBAC, network policies, dan admission controllers yang sama dengan aplikasi lain — integrasi keamanan yang alami. Perhatikan juga pola di atas sudah menerapkan securityContext: runAsNonRoot: true dari episode 20 bahkan di pipeline itu sendiri.
Kita sudah menyentuh masing-masing, tapi mari satukan peran mereka agar jelas. chart-testing (ct) adalah tool khusus Helm yang mengotomasi alur "lint semua chart yang berubah dalam PR". Ia perlu config file:
chart-dirs:
- charts
chart-repos:
- bitnami=https://charts.bitnami.com/bitnami
helm-extra-args: --timeout 600s
validate-maintainers: false
target-branch: mainct lint --check-version-increment=true memeriksa: chart yang berubah harus menaikkan versinya, Chart.yaml valid, README ada, dan nilai di values.yaml bisa di-render. Ini adalah gate kualitas pertama di PR — sebelum review manusia bahkan melihat diff-nya.
helm-unittest (dari episode 14 dan 22) menguji perilaku template dengan assertion yang eksplisit. kubeconform memvalidasi bahwa apa yang di-render benar-benar sesuai skema Kubernetes — menangkap kesalahan yang tidak terlihat oleh lint (misalnya field yang salah tipe, atau API yang sudah tidak ada). Ketiganya adalah lapisan yang berbeda: lint memeriksa struktur chart, unittest memeriksa logika render, kubeconform memeriksa validitas terhadap API server yang sebenarnya.
Tip
Jalankan helm template --debug di CI dan simpan outputnya sebagai artifact. Ketika chart gagal di produksi, kalian tidak akan punya akses cepat ke manifest yang sebenarnya — tapi artifact CI menyimpan rendering yang valid untuk setiap commit. Ini membuat debugging "chart yang bekerja di staging tapi gagal di prod" jauh lebih cepat: kalian bisa membandingkan output render kedua environment secara langsung.
Menutup episode ini dengan daftar praktik yang harus menjadi kebiasaan di semua pipeline:
secrets.*, di GitLab pakai CI variables dengan protection, di Jenkins pakai withCredentials. Setiap platform punya mekanismenya — gunakan selalu.ct lint --check-version-increment memaksa bump versi di Chart.yaml, dan tools seperti semantic-release atau helm-release bisa mengotomasinya dari conventional commits — chart versi 1.24.0 dihasilkan dari commit feat:, 1.24.1 dari fix:, dst.latest di mana pun.helm template dan menjalankan kubeconform — tanpa deploy. Ini mendeteksi masalah jauh sebelum merge.oci://), bukan dari source.--atomic --timeout pada upgrade sehingga kegagalan memicu rollback otomatis, dan release tidak pernah ditinggalkan dalam status failed yang membingungkan.Pada episode 24 ini kita telah membedah integrasi Helm ke dalam empat ekosistem CI/CD: GitHub Actions dengan azure/setup-helm, ct lint, kubeconform, push OCI ke GHCR, dan azure/k8s-set-context untuk deploy; GitLab CI/CD dengan stages, environments, review apps, dan promotion manual; Jenkins dengan Jenkinsfile dan approval gate; serta Tekton dengan Tasks dan Workspaces sebagai pipeline cloud-native. Kita juga menetapkan peran chart-testing, helm-unittest, dan kubeconform, plus praktik terbaik tentang secrets, versioning, dan tagging.
Inti yang harus kalian bawa:
ct lint (struktur) → helm-unittest (logika) → kubeconform (skema).Di episode 25 selanjutnya kita akan membahas GitOps dengan Helm: menjadikan Git sebagai source of truth dan membiarkan ArgoCD atau Flux menyinkronkan chart ke cluster secara otomatis — drift detection, helm parameters, dan praktik terbaik yang mengubah pipeline push-based menjadi pull-based. Sampai jumpa di episode 25!