Dynamic Provisioning #

Ketika kita pertama kali belajar mengelola penyimpanan (storage) di Kubernetes, kita diperkenalkan pada konsep penyediaan statis (static provisioning). Pada model tersebut, administrator kluster harus membuat PersistentVolume (PV) secara manual terlebih dahulu di infrastruktur cloud atau lokal, baru kemudian developer membuat PersistentVolumeClaim (PVC) untuk mengklaim volume tersebut.

Meskipun metode ini berfungsi untuk kluster skala kecil, ia dengan cepat menjadi bottleneck operasional yang besar saat kluster kita tumbuh. Memaksa administrator membuat PV secara manual untuk setiap aplikasi baru menghambat kelincahan developer dan memperlambat proses deployment.

Di sinilah Dynamic Provisioning (Penyediaan Dinamis) masuk sebagai solusi penyelamat. Dengan dynamic provisioning, kita tidak perlu lagi membuat PV secara manual. Saat developer membuat objek PVC, Kubernetes akan berkolaborasi dengan driver penyimpanan eksternal untuk membuat volume fisik di cloud provider atau lokal, lalu membuat objek PV yang sesuai secara otomatis di API Server. Artikel ini akan membedah secara menyeluruh bagaimana dynamic provisioning bekerja, arsitektur driver CSI, serta praktik terbaik konfigurasinya untuk produksi.


Alur Kerja End-to-End Dynamic Provisioning #

Untuk memahami keindahan dari dynamic provisioning, mari kita telusuri alur kerja pembuatannya dari detik pertama developer menerapkan manifes PVC hingga volume siap digunakan di dalam Pod.

Mari kita perhatikan representasi visual dari alur kerja ini melalui diagram berikut:

flowchart TD
    Dev["Developer (PVC)"] -. Menerapkan .-> API["Kubernetes API Server"]
    API -. Mengecek .-> SC["StorageClass Resource"]
    SC -. Mengarahkan .-> CSI["CSI External Provisioner"]
    CSI -. Panggil RPC CreateVolume .-> Cloud["Cloud Provider API (e.g. AWS EBS)"]
    Cloud -. Membuat disk fisik .-> Disk["Physical Disk (e.g. gp3 Volume)"]
    Disk -. Lapor volume-id .-> CSI
    CSI -. Buat objek PV .-> API
    API -. Melakukan Binding .-> Bind["PVC <=> PV (Bound)"]

Mari kita bedah proses di atas langkah demi langkah:

  1. Developer Membuat PVC: Developer menerapkan manifes PVC yang mencantumkan nama storageClassName (misalnya: premium-ssd) dan ukuran yang diminta (misalnya: 50Gi).
  2. Pencarian PV yang Cocok: Kubernetes Controller Manager memeriksa apakah ada PV statis berstatus Available yang memenuhi kriteria PVC tersebut. Jika tidak ditemukan, Kubernetes beralih ke dynamic provisioning.
  3. Evaluasi StorageClass: Kubernetes membaca definisi StorageClass bernama premium-ssd. Di dalam objek ini, Kubernetes melihat parameter provisioner (contoh: ebs.csi.aws.com) yang bertanggung jawab menangani penyediaan disk.
  4. Komunikasi CSI: Kontroler External Provisioner milik driver CSI yang berjalan di kluster menangkap pembuatan PVC baru tersebut. Kontroler ini mengirimkan panggilan Remote Procedure Call (RPC) berupa fungsi CreateVolume ke plugin driver CSI.
  5. Pembuatan Storage Fisik: Driver CSI memanggil API internal cloud provider (misalnya API AWS EC2 CreateVolume atau API GCP Compute Engine) untuk membuat disk fisik dengan ukuran 50Gi dan tipe SSD.
  6. Pendaftaran PV: Cloud provider mengembalikan ID volume unik (misalnya vol-0a1b2c3d...). Driver CSI kemudian membuat objek PersistentVolume (PV) baru secara otomatis di Kubernetes dengan spesifikasi volume backend tersebut.
  7. Proses Binding: Kubernetes Controller Manager melakukan binding antara objek PVC milik developer dengan objek PV baru yang dibuat secara otomatis tersebut. Status PVC berubah menjadi Bound.
  8. Pemberian Akses ke Pod: Pod yang meminta PVC tersebut kini dapat dijalankan di worker node. Kubelet di worker node akan menginstruksikan driver CSI lokal untuk melakukan attach dan mount disk fisik tersebut ke dalam filesystem container.

Arsitektur CSI (Container Storage Interface) #

Standardisasi dynamic provisioning di Kubernetes saat ini sepenuhnya bertumpu pada Container Storage Interface (CSI). Sebelum adanya CSI, kode driver penyimpanan ditulis secara langsung di dalam kode inti Kubernetes (in-tree drivers). Ini berarti, jika AWS atau NetApp ingin merilis fitur baru pada driver mereka, mereka harus menunggu siklus rilis Kubernetes utama yang membutuhkan waktu berbulan-bulan.

Dengan CSI (out-of-tree drivers), vendor penyimpanan dapat mengembangkan, merilis, dan memelihara driver mereka secara independen tanpa menyentuh kode inti Kubernetes.

Driver CSI modern terdiri dari beberapa komponen controller yang dideploy sebagai pod di dalam kluster kita:

Komponen Utama Driver CSI:
  ├── [Control Plane] CSI Controller (Deployment / StatefulSet)
  │     ├── External Provisioner ──> Memonitor PVC, membuat/menghapus volume fisik.
  │     ├── External Attacher ─────> Menangani attach/detach volume ke node worker.
  │     └── External Resizer ──────> Memproses permintaan ekspansi ukuran volume.
  └── [Data Plane] CSI Node Plugin (DaemonSet)
        └── CSI Node Agent ────────> Berjalan di tiap node, memproses mount filesystem ke container.
  1. CSI External Provisioner: Kontroler ini bertindak sebagai jembatan antara API Server Kubernetes dan driver CSI. Ia memonitor objek PVC baru, lalu memanggil fungsi CreateVolume dari driver CSI untuk membuat penyimpanan fisik di cloud atau lokal.
  2. CSI External Attacher: Bertanggung jawab memonitor objek VolumeAttachment di Kubernetes. Ia bertugas memanggil API cloud provider untuk menempelkan (attach) disk fisik ke mesin virtual (node worker) tempat Pod akan dijadwalkan.
  3. CSI External Resizer: Memonitor jika ada perubahan ukuran kapasitas pada objek PVC. Jika developer memperbesar ukuran PVC (misalnya dari 50Gi menjadi 100Gi), kontroler ini akan memanggil API cloud untuk memperbesar disk fisik tanpa menghentikan Pod.
  4. CSI Node Plugin (DaemonSet): Berjalan di setiap worker node kluster. Komponen ini berinteraksi langsung dengan kubelet lokal melalui UNIX domain socket. Saat Pod dijalankan di node tersebut, DaemonSet ini akan memformat disk fisik (misalnya dengan ext4 atau xfs) dan me-mount volume tersebut ke direktori container Pod.

StorageClass: Cetak Biru Dynamic Provisioning #

Pilar utama dari dynamic provisioning adalah resource StorageClass. StorageClass mendefinisikan “kelas” penyimpanan yang dapat diminta oleh developer. Kita bisa menganggap StorageClass sebagai katalog layanan penyimpanan (misalnya kelas SSD cepat untuk database, atau kelas HDD murah untuk backup).

Mari kita pelajari manifes StorageClass produksi berikut beserta penjelasan parameter kuncinya:

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: production-gp3-sc
  annotations:
    storageclass.kubernetes.io/is-default-class: "false"
provisioner: ebs.csi.aws.com
volumeBindingMode: WaitForFirstConsumer
reclaimPolicy: Delete
allowVolumeExpansion: true
parameters:
  type: gp3
  iops: "3000"
  throughput: "125"
  encrypted: "true"

1. parameter provisioner #

Menentukan driver CSI mana yang bertanggung jawab untuk membuat volume. Untuk AWS EBS, kita menggunakan ebs.csi.aws.com. Untuk Google Cloud Persistent Disk, kita menggunakan pd.csi.storage.gke.io.

2. parameter volumeBindingMode #

Ini adalah salah satu parameter paling krusial untuk kestabilan aplikasi kita. Terdapat dua pilihan:

  • Immediate (Default): Begitu PVC dibuat, PV akan langsung dibuat saat itu juga di cloud provider. Namun, pada infrastruktur multi-zona (multi-AZ), hal ini berisiko tinggi. Cloud provider mungkin membuat PV di zona ap-southeast-1a, sedangkan scheduler Kubernetes kemudian menjadwalkan Pod kita di zona ap-southeast-1b karena keterbatasan resource CPU. Karena volume cloud bertipe block storage tidak bisa melintasi batas zona, Pod kita akan stuck selamanya dengan error VolumeAttachment failed.
  • WaitForFirstConsumer: Kubernetes tidak akan membuat PV ketika PVC dibuat. Kubernetes akan menunggu hingga ada Pod yang menggunakan PVC tersebut dijadwalkan ke node tertentu. Setelah scheduler menentukan node mana yang ideal bagi Pod, scheduler akan menginformasikan zona node tersebut kepada driver CSI. Driver CSI kemudian membuat PV tepat di zona tempat Pod dijadwalkan. Kita wajib menggunakan opsi ini untuk seluruh lingkungan produksi di cloud.

3. parameter reclaimPolicy #

Menentukan apa yang terjadi pada volume fisik di cloud provider ketika developer menghapus objek PVC di Kubernetes:

  • Delete (Default): Volume fisik di cloud akan langsung ikut terhapus secara otomatis. Ini sangat efisien untuk menghemat biaya pada environment testing atau staging.
  • Retain: Volume fisik di cloud akan tetap dipertahankan meskipun objek PVC dan PV di Kubernetes telah dihapus. Status PV fisik berubah menjadi Released. Administrator harus menghapus disk fisik secara manual setelah memastikan data di dalamnya sudah tidak dibutuhkan atau telah dipindahkan. Opsi ini direkomendasikan untuk database produksi guna mencegah kehilangan data fatal akibat ketidaksengajaan.

Dynamic Provisioning di Lingkungan On-Premise / Bare-Metal #

Jika kita membangun kluster Kubernetes secara mandiri di atas server bare-metal lokal (on-premise), kita tidak memiliki integrasi API Cloud otomatis seperti AWS atau GCP. Namun, kita tetap bisa menikmati fitur dynamic provisioning dengan menggunakan solusi penyimpanan lokal yang andal.

1. NFS Subdir External Provisioner #

Ini adalah solusi paling sederhana bagi kita yang sudah memiliki server penyimpanan bersama (NFS server) di jaringan lokal. Provisioner ini akan memonitor PVC, lalu membuat sub-direktori baru secara dinamis di dalam share folder NFS kita untuk dialokasikan ke PV baru.

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: nfs-dynamic-sc
provisioner: cluster.local/nfs-subdir-external-provisioner
reclaimPolicy: Delete
parameters:
  archiveOnDelete: "true" # Jika PVC dihapus, ganti nama folder (jangan langsung hapus fisik)

2. Longhorn (Distributed Block Storage) #

Longhorn adalah proyek CNCF sandbox yang dikembangkan oleh Rancher. Ia menyediakan penyimpanan blok terdistribusi di atas worker node lokal kita. Longhorn mereplikasi data block storage kita ke beberapa worker node yang berbeda untuk menjamin ketersediaan tinggi (High Availability).

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: longhorn-ssd
provisioner: driver.longhorn.io
allowVolumeExpansion: true
reclaimPolicy: Delete
volumeBindingMode: WaitForFirstConsumer
parameters:
  numberOfReplicas: "3" # Data diduplikasi ke 3 node berbeda
  staleReplicaTimeout: "2880"

Anti-Pattern vs Solusi dalam Dynamic Provisioning #

Mari kita pelajari beberapa kesalahan arsitektur (anti-pattern) yang umum ditemui saat menerapkan dynamic provisioning beserta perbandingan kodenya.

Anti-Pattern 1: Menggunakan Binding Mode Immediate di Multi-Zona Cloud #

Kita mendeploy StorageClass SSD di AWS EKS multi-zona (Singapura) dengan binding mode bawaan Immediate. Hal ini memicu ketidaksesuaian lokasi pembuatan disk fisik dengan penempatan penjadwalan Pod.

Kode Manifest Salah (Binding Mode Immediate) #

# JANGAN GUNAKAN INI UNTUK MULTI-ZONE CLUSTER
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: unsafe-immediate-sc
provisioner: ebs.csi.aws.com
volumeBindingMode: Immediate # Volume dibuat sebelum Pod dijadwalkan!
parameters:
  type: gp3

Kode Solusi (Menggunakan WaitForFirstConsumer) #

# SOLUSI: Menunda pembuatan volume hingga node Pod ditentukan
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: safe-wait-sc
provisioner: ebs.csi.aws.com
volumeBindingMode: WaitForFirstConsumer # Volume dibuat tepat di zona Pod berada
parameters:
  type: gp3

Anti-Pattern 2: Menghapus Dukungan Ekspansi Volume (allowVolumeExpansion) #

Kita lupa mengaktifkan fitur ekspansi volume pada StorageClass. Ketika database kita kehabisan ruang disk di tengah malam, kita terpaksa mematikan database, membuat PVC baru, memindahkan data lama ke volume baru secara manual, yang memicu downtime operasional yang panjang.

Kode Manifest Salah (Tanpa Properti Ekspansi) #

# JANGAN GUNAKAN INI: Menyulitkan peningkatan kapasitas disk
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: no-expansion-sc
provisioner: pd.csi.storage.gke.io
# allowVolumeExpansion tidak didefinisikan (default: false)

Kode Solusi (StorageClass dengan Ekspansi Aktif) #

# SOLUSI: Aktifkan ekspansi volume dinamis
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: flexible-expansion-sc
provisioner: pd.csi.storage.gke.io
allowVolumeExpansion: true # Mengizinkan resize volume live!

Jika developer ingin memperbesar disk PVC dari 50Gi menjadi 100Gi, developer cukup mengedit manifest PVC yang sedang berjalan tanpa perlu menghapusnya:

# Cara melakukan resize PVC (Cukup terapkan perubahan ukuran langsung)
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: app-db-pvc
  namespace: production
spec:
  accessModes:
    - ReadWriteOnce
  storageClassName: flexible-expansion-sc
  resources:
    requests:
      storage: 100Gi # Ubah dari 50Gi ke 100Gi, lalu jalankan kubectl apply

Panduan Troubleshooting Masalah Dynamic Provisioning #

Ketika dynamic provisioning gagal bekerja, developer biasanya mendapati PVC mereka tertahan selamanya di status Pending. Berikut adalah panduan sistematis untuk mendiagnosis masalah tersebut:

1. Memeriksa Deskripsi Kejadian PVC #

Titik awal analisis kita adalah memeriksa log event dari objek PVC itu sendiri:

kubectl describe pvc <nama-pvc> -n <namespace>

Mari kita pelajari beberapa pesan error yang sering muncul beserta penjelasannya:

  • "waiting for a volume to be created, either by external provisioner or manually created by system administrator":
    • Artinya: Kubernetes API Server sudah mengirimkan request pembuatan volume ke driver CSI, tetapi driver CSI tidak merespons atau tidak aktif.
    • Solusi: Periksa apakah pod kontroler CSI di namespace system (misalnya kube-system) sedang berjalan atau mengalami crash:
      kubectl get pods -n kube-system -l app.kubernetes.io/name=aws-ebs-csi-driver
      
  • "failed to provision volume: RPC error: code = InvalidParameter desc = KMS key not found":
    • Artinya: Parameter enkripsi KMS key yang ditulis di dalam StorageClass salah atau tidak dapat ditemukan di cloud account kita.
    • Solusi: Periksa kebenaran string ARN KMS key pada parameter StorageClass.
  • "AccessDenied: User: arn:aws:sts::... is not authorized to perform: ec2:CreateVolume":
    • Artinya: Pod CSI driver tidak memiliki izin IAM role/Service Account yang cukup untuk memanggil API cloud provider.
    • Solusi: Tinjau konfigurasi IAM OIDC provider kita dan pastikan Service Account ebs-csi-controller-sa telah memiliki anotasi ARN IAM Role yang memiliki policy AWS EBS permissions yang tepat.

Ringkasan #

  • Dynamic provisioning mengeliminasi bottleneck manual: PV secara otomatis diciptakan oleh Kubernetes berkat kolaborasi antara StorageClass dan driver CSI ketika mendeteksi adanya objek PVC baru.
  • WaitForFirstConsumer adalah kewajiban multi-zona: Hindari binding instan (Immediate) di cloud provider multi-zona guna memastikan volume fisik dibuat di zona yang sama dengan penempatan node Pod kita.
  • Pahami reclaimPolicy untuk perlindungan data: Setel reclaimPolicy: Retain pada penyimpanan database penting kita agar volume fisik di cloud tidak terhapus otomatis saat objek PVC tidak sengaja terhapus.
  • Aktifkan allowVolumeExpansion: Selalu aktifkan ekspansi volume dinamis pada StorageClass produksi kita agar tim operasional dapat memperbesar kapasitas disk secara live tanpa memicu downtime database.
  • Diagnosis PVC stuck melalui event logs: Selalu gunakan kubectl describe pvc untuk mengidentifikasi hambatan otorisasi IAM, kesalahan penamaan StorageClass, atau kegagalan internal komunikasi driver CSI.

← Sebelumnya: Backup & Restore   Berikutnya: Anti-Pattern Storage →

About | Author | Content Scope | Editorial Policy | Privacy Policy | Disclaimer | Contact