Topik ini membahas Kustomize, yaitu alat penyesuaian manifest Kubernetes yang bekerja tanpa template, sehingga berkas yang dikelola tetap YAML biasa dari awal sampai akhir. Pembahasan dimulai dari struktur base yang memuat manifest asli, dilanjutkan overlay yang menampung perbedaan tiap lingkungan, kemudian patch strategis dan penyesuaian image, dan ditutup perbandingannya dengan Helm. Contoh di sepanjang topik menggunakan aplikasi catatan yang terdiri atas API dan web, dengan lingkungan staging dan produksi. Setelah topik ini dibaca, satu set manifest yang sama dapat dibangun menjadi varian per lingkungan melalui proses build yang deterministik.
Penyesuaian manifest tanpa template#
Setiap lingkungan membutuhkan manifest yang hampir sama dengan perbedaan kecil, misalnya jumlah replika, tag image, dan namespace. Salah satu cara yang lazim adalah menyalin manifest utuh untuk setiap lingkungan, tetapi cara itu menimbulkan duplikasi. Ketika satu perbaikan dilakukan pada berkas staging, berkas produksi mudah terlewat, sehingga kedua lingkungan perlahan menyimpang satu sama lain. Semakin banyak jenis objek yang dikelola, semakin besar biaya penjagaan salinan tersebut.
Kustomize menjawab masalah tersebut dengan memisahkan manifest asli dari perubahannya. Manifest asli diletakkan pada direktori yang disebut base, sedangkan perbedaan tiap lingkungan diletakkan pada overlay yang merujuk base tersebut. Pusat kendalinya adalah berkas kustomization.yaml, yaitu berkas yang mendeklarasikan daftar sumber daya dan daftar perubahan yang ingin diterapkan. Perintah kustomize build membaca berkas tersebut, menggabungkan seluruh sumber daya dengan perubahannya, lalu mencetak manifest hasilnya ke keluaran standar.
Proses gabungan tersebut adalah fungsi murni dari berkasnya. Masukan yang sama selalu menghasilkan keluaran yang sama, dan tidak ada keadaan yang disimpan di mana pun. Karena itu, hasil build dapat disimpan, dibandingkan antara revisi di git, dan ditinjau sebelum dikirim ke kluster. Penerapan ke kluster dilakukan dengan kubectl apply -k, yang menjalankan build yang sama sebelum mengirim manifestnya ke API server.
Struktur base dan overlay#
Struktur direktori berikut memuat satu base dan dua overlay untuk aplikasi catatan. Base menyimpan manifest yang berlaku untuk semua lingkungan, sedangkan setiap overlay menyimpan kustomization.yaml beserta berkas patch miliknya. Pada bundle topik ini, berkas-berkas tersebut ditampilkan datar di samping artikel dengan nama yang disesuaikan, misalnya kustomization-staging.yaml yang dalam pohon sesungguhnya tersimpan sebagai overlays/staging/kustomization.yaml.
catatan/
├── base/
│ ├── deployment.yaml
│ ├── service.yaml
│ └── kustomization.yaml
└── overlays/
├── staging/
│ ├── kustomization.yaml
│ └── patch-replika.yaml
└── produksi/
├── kustomization.yaml
└── patch-replika.yamlBase harus dapat dibangun sendiri tanpa overlay, karena base adalah titik awal yang berlaku apabila tidak ada penyesuaian apa pun. Berkas pertama pada base adalah manifest Deployment untuk API aplikasi catatan dengan satu replika dan image versi 1.0.0. Berkas ini tersimpan sebagai base/deployment.yaml pada pohon di atas.
apiVersion: apps/v1
kind: Deployment
metadata:
name: api-catatan
labels:
app: api-catatan
spec:
replicas: 1
selector:
matchLabels:
app: api-catatan
template:
metadata:
labels:
app: api-catatan
spec:
containers:
- name: api
image: registry.local/api-catatan:1.0.0
ports:
- containerPort: 8000Service berikut menghubungkan Pod API melalui port 80 yang diteruskan ke port 8000 pada container. Berkas ini tidak tersentuh oleh patch mana pun pada contoh topik ini, sehingga hasil build staging dan produksi hanya berbeda pada Deployment.
apiVersion: v1
kind: Service
metadata:
name: api-catatan
spec:
selector:
app: api-catatan
ports:
- port: 80
targetPort: 8000kustomization.yaml pada base mendaftarkan kedua berkas di atas melalui bidang resources, dan urutan penulisan menentukan urutan keluaran build.
resources:
- deployment.yaml
- service.yamlDiagram berikut merangkum alur gabungan dari base dan overlay menjadi satu set manifest hasil build.
Overlay staging mendeklarasikan base sebagai sumber dayanya, kemudian menambahkan patch jumlah replika dan penggantian tag image melalui bidang patches dan images.
resources:
- ../../base
patches:
- path: patch-replika.yaml
images:
- name: registry.local/api-catatan
newTag: "2.0.0-rc.1"Patch pada overlay staging hanya mengubah bidang spec.replicas pada Deployment bernama api-catatan.
apiVersion: apps/v1
kind: Deployment
metadata:
name: api-catatan
spec:
replicas: 2Overlay produksi mengikuti pola yang sama dengan dua perbedaan. Bidang namespace menambahkan metadata.namespace pada setiap objek hasil build, sehingga seluruh objek produksi berada pada namespace catatan-produksi. Tag image dituliskan secara eksplisit agar hasil build produksi tidak bergantung pada nilai default base.
resources:
- ../../base
namespace: catatan-produksi
patches:
- path: patch-replika.yaml
images:
- name: registry.local/api-catatan
newTag: "1.0.0"apiVersion: apps/v1
kind: Deployment
metadata:
name: api-catatan
spec:
replicas: 3Patch strategis dan penyesuaian image#
Patch strategis (strategic merge patch) adalah berkas YAML berbentuk manifest yang hanya menuliskan bidang yang ingin diubah. Saat build berjalan, bidang tersebut ditimpa pada manifest asal, sedangkan bidang yang tidak disebut tetap dipertahankan. Penggabungan berlaku bertingkat, termasuk pada daftar objek seperti spec.template.spec.containers yang disatukan berdasarkan nama container-nya. Karena bentuknya sama dengan manifest, patch strategis mudah dibaca dan mudah diperiksa di git.
Beberapa bidang lama pada kustomization.yaml masih dikenali banyak alat, tetapi padanannya pada sintaks saat ini menyatu pada bidang patches yang sama.
| Bidang lama | Padanan saat ini | Perilaku |
|---|---|---|
| bases | resources | menyatakan kustomization lain sebagai sumber daya |
| patchesStrategicMerge | patches dengan path | penggabungan berdasarkan kunci bidang |
| patchesJson6902 | patches dengan target | operasi JSON Patch RFC 6902, termasuk penghapusan bidang |
Bidang images menangani penyesuaian image tanpa menyentuh berkas patch. Setiap aturan menyebut nama image pada base, lalu mengganti bagian tag melalui newTag, mengganti seluruh nama melalui newName, atau menyematkan digest tertentu. Pada contoh topik ini, overlay staging mengganti tag menjadi 2.0.0-rc.1, sedangkan overlay produksi menuliskan 1.0.0 secara eksplisit.
Melihat hasil build sebelum diterapkan#
Perintah kustomize build mencetak hasil gabungan ke terminal tanpa mengirim apa pun ke kluster, sehingga cocok untuk peninjauan sebelum penerapan.
# tidak-dijalankan
# mencetak hasil build overlay staging ke terminal
kustomize build overlays/stagingapiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: api-catatan
name: api-catatanApabila keluarannya sudah sesuai, penerapan ke kluster menggunakan kubectl apply -k.
# tidak-dijalankan
# menerapkan seluruh hasil build overlay staging ke kluster
kubectl apply -k overlays/stagingdeployment.apps/api-catatan created
service/api-catatan createdKedua perintah di atas tidak dapat dijalankan pada sandbox artikel ini karena biner kustomize dan kubectl tidak tersedia, sehingga mekanisme gabungannya disimulasikan dengan Python menggunakan PyYAML. Skrip berikut membaca deployment-base.yaml dan berkas patch dari bundle, menerapkan penggabungan strategis sederhana, kemudian mengganti tag image dan menambahkan namespace sesuai isi kustomization-staging.yaml dan kustomization-produksi.yaml. Simulasi ini hanya memproses Deployment dan menyederhanakan penggabungan daftar, sedangkan alat asli juga menyatukan daftar container berdasarkan nama container.
# Simulasi kustomize build: manifest base digabung dengan patch overlay,
# lalu tag image dan namespace diperbarui mengikuti kustomization overlay.
import copy
import yaml
with open("deployment-base.yaml", encoding="utf-8") as berkas:
base = yaml.safe_load(berkas)
def gabung_strategis(asal, patch):
# bidang yang disebut patch menimpa nilai base, sisanya dipertahankan
hasil = copy.deepcopy(asal)
for kunci, nilai in patch.items():
if isinstance(nilai, dict) and isinstance(hasil.get(kunci), dict):
hasil[kunci] = gabung_strategis(hasil[kunci], nilai)
else:
hasil[kunci] = copy.deepcopy(nilai)
return hasil
for lingkungan in ("staging", "produksi"):
with open(f"kustomization-{lingkungan}.yaml", encoding="utf-8") as berkas:
kustomisasi = yaml.safe_load(berkas)
manifest = copy.deepcopy(base)
# berkas patch pada pohon tersimpan sebagai overlays/<lingkungan>/patch-replika.yaml
with open(f"patch-replika-{lingkungan}.yaml", encoding="utf-8") as berkas:
patch = yaml.safe_load(berkas)
manifest = gabung_strategis(manifest, patch)
for aturan in kustomisasi.get("images", []):
for container in manifest["spec"]["template"]["spec"]["containers"]:
nama, _, _ = container["image"].rpartition(":")
if nama == aturan["name"]:
container["image"] = f"{nama}:{aturan['newTag']}"
if kustomisasi.get("namespace"):
manifest["metadata"]["namespace"] = kustomisasi["namespace"]
print(f"--- hasil build overlay {lingkungan} ---")
print(yaml.dump(manifest, sort_keys=True, default_flow_style=False).rstrip())--- hasil build overlay staging ---
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: api-catatan
name: api-catatan
spec:
replicas: 2
selector:
matchLabels:
app: api-catatan
template:
metadata:
labels:
app: api-catatan
spec:
containers:
- image: registry.local/api-catatan:2.0.0-rc.1
name: api
ports:
- containerPort: 8000
--- hasil build overlay produksi ---
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: api-catatan
name: api-catatan
namespace: catatan-produksi
spec:
replicas: 3
selector:
matchLabels:
app: api-catatan
template:
metadata:
labels:
app: api-catatan
spec:
containers:
- image: registry.local/api-catatan:1.0.0
name: api
ports:
- containerPort: 8000Pada keluaran di atas, jumlah replika staging menjadi dua dan image berubah menjadi tag 2.0.0-rc.1, sedangkan bagian lain manifest dipertahankan dari base. Overlay produksi menambah namespace catatan-produksi dan menetapkan tiga replika. Penataan spasi pada keluaran simulasi dapat berbeda dari keluaran perintah kustomize asli, tetapi makna kedua keluaran tersebut sama.
Perbandingan Kustomize dan Helm#
Kustomize dan Helm menjawab persoalan yang sama, yaitu mengelola manifest dalam jumlah banyak tanpa duplikasi, tetapi keduanya memilih jalan yang berbeda. Kustomize menyesuaikan berkas YAML asli melalui overlay dan patch, sedangkan Helm merender template menggunakan values sebelum manifest dikirim ke kluster. Perbedaan lainnya terletak pada keadaan, karena Helm melacak setiap release di dalam kluster, sedangkan Kustomize tidak menyimpan keadaan apa pun.
| Aspek | Kustomize | Helm |
|---|---|---|
| Bentuk berkas | YAML murni tanpa template | template Go yang diisi values |
| Mekanisme penyesuaian | overlay dan patch deklaratif | values dan fungsi templating |
| Pelacakan keadaan | tidak menyimpan keadaan di kluster | release tersimpan dan memiliki riwayat revisi |
| Perintah utama | kubectl apply -k | helm install dan helm upgrade |
| Titik awal | manifest yang sudah ada | chart yang ditulis dari awal |
Tabel di atas juga menjelaskan alasan kedua alat ini sering ditemukan sekaligus dalam satu tim. Kustomize menambah nilai pada manifest yang sudah teruji karena tidak ada perubahan sintaks pada berkasnya, sedangkan Helm menambah nilai ketika penyesuaian perlu dinyatakan sebagai nilai yang diteruskan ke chart. Keduanya sama-sama deklaratif, sehingga hasil akhirnya tetap dapat diperiksa di git sebelum dikirim ke kluster.
Kesalahan umum#
Kesalahan pada pekerjaan Kustomize biasanya bukan pada sintaksnya, melainkan pada penjagaan struktur. Beberapa kesalahan berikut muncul ketika overlay mulai bertambah, dan semuanya dapat dicegah dengan membaca keluaran build secara rutin.
- Mengubah berkas base demi kebutuhan satu lingkungan. Perubahan tersebut ikut berlaku pada semua overlay, sehingga lingkungan lain diam-diam ikut berubah. Perbaikannya adalah memindahkan perbedaan tersebut menjadi patch pada overlay yang berkepentingan.
- Lupa mendaftarkan berkas baru pada bidang resources. Berkas manifest yang berada di folder base tetapi tidak terdaftar tidak ikut dibangun, sehingga objeknya tidak pernah diterapkan. Tambahkan berkas tersebut pada daftar resources, lalu jalankan build untuk memeriksa keluarannya.
- Menulis patch dengan nama atau kind yang tidak cocok dengan manifest asal. Penggabungan strategis mencari objek target berdasarkan apiVersion, kind, dan metadata.name, sehingga patch yang salah nama membatalkan build dengan error.
Ketiga kesalahan di atas berbagi satu gejala yang sama, yaitu keluaran build yang berbeda dari dugaan. Keluaran yang mencantumkan objek kurang atau lebih dari yang diharapkan adalah sinyal bahwa daftar resources atau isi patch perlu diperiksa ulang sebelum penerapan.
Ringkasan#
- Kustomize menyesuaikan manifest tanpa template, yaitu base berisi manifest asli dan overlay menampung perbedaan tiap lingkungan melalui kustomization.yaml.
- Patch strategis menimpa hanya bidang yang disebut, sedangkan bidang images mengganti tag, nama, atau digest image pada saat build.
- Hasil build adalah fungsi murni dari berkasnya, sehingga dapat ditinjau dengan kustomize build dan diterapkan dengan kubectl apply -k.
- Kustomize tidak menyimpan keadaan di kluster, sedangkan Helm menyimpan release beserta riwayat revisinya.
Referensi#
- Kustomization — Kubernetes Documentation — Panduan resmi penerapan dan penyesuaian objek Kubernetes menggunakan kustomization dan overlay.
- Kustomization Reference — kustomize — Rujukan resmi seluruh bidang kustomization.yaml, termasuk resources, patches, images, dan namespace.