PersistentVolume #

Di dalam kluster Kubernetes, kita membedakan dengan tegas antara peran Administrator Kluster (Platform Engineer) dengan Pengembang Aplikasi (Application Developer). Administrator bertanggung jawab untuk mengelola infrastruktur fisik—termasuk server, jaringan, dan kapasitas penyimpanan (storage). Sementara itu, pengembang fokus pada fungsionalitas kode dan kebutuhan beban kerja mereka. Untuk mendukung pemisahan tanggung jawab ini pada aspek penyimpanan data persisten, Kubernetes menyediakan objek PersistentVolume (PV).

PersistentVolume adalah representasi fisik dari media penyimpanan yang telah disiapkan di tingkat kluster. Sama seperti Node yang merepresentasikan kapasitas komputasi (CPU/RAM) global kluster, PV merepresentasikan kapasitas penyimpanan global yang tidak terikat pada namespace mana pun (non-namespaced resource). Artikel ini akan membahas secara mendalam anatomi manifes PV, parameter penentu performa, daur hidup status PV, mekanisme static provisioning, hingga cara memulihkan data yang terkunci pada status Released.


Posisi PersistentVolume dalam Ekosistem Storage #

Untuk memahami bagaimana PersistentVolume bekerja, kita harus melihat bagaimana PV berinteraksi dengan PersistentVolumeClaim (PVC) dan StorageClass. PVC bertindak sebagai permintaan (“klaim”) dari developer, sedangkan PV bertindak sebagai penyedia kapasitas yang siap diikat (bound) ke PVC tersebut.

Berikut adalah diagram alur siklus hidup (lifecycle phases) status PersistentVolume sejak awal dibuat hingga proses pembersihan:

flowchart TD
    Created["PV Dibuat (Available)"] --> BindAction["PVC Baru Meminta Bind"]
    BindAction --> Bound["PV Diikat ke PVC (Bound)"]
    
    Bound --> PVC_Delete["User Menghapus Objek PVC"]
    PVC_Delete --> CheckPolicy{"Apa Kebijakan\nReclaim Policy?"}
    
    CheckPolicy -- "Retain" --> Released["Released (Data Fisik Aman, PV Terkunci)"]
    CheckPolicy -- "Delete" --> Deleted["Disk Cloud Dihapus & PV Dihapus"]
    CheckPolicy -- "Recycle" --> Clean["rm -rf Pada Direktori"]
    
    Clean --> Created
    
    subgraph AdminAction ["Intervensi Manual Admin"]
        Released --> AdminDecide{"Apa Tindakan?"}
        AdminDecide -- "Hapus ClaimRef" --> Created
        AdminDecide -- "Hapus PV & Data" --> Finish["Selesai Hapus"]
    end

Anatomi Manifes PersistentVolume #

Untuk memahami parameter konfigurasi tingkat tinggi yang disediakan oleh PV, mari kita perhatikan manifest berikut yang menunjukkan PV berbasis NFS server yang dikonfigurasi secara manual:

apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv-production-postgres
  labels:
    storage-tier: premium
    encrypted: "true"
spec:
  capacity:
    storage: 100Gi                   # Kapasitas fisik disk
  volumeMode: Filesystem             # Filesystem (Default) | Block
  accessModes:
    - ReadWriteOnce                  # RWO | ROX | RWX | RWOP
  persistentVolumeReclaimPolicy: Retain # Retain | Delete | Recycle
  storageClassName: premium-manual   # Dicocokkan dengan storageClassName PVC
  nfs:                               # Tipe backend storage (NFS)
    path: /var/exports/postgres-data
    server: nfs-server.production.internal

Penjelasan Parameter Kunci: #

1. capacity.storage #

Mendefinisikan kapasitas penyimpanan fisik yang dialokasikan untuk volume ini (misalnya 100Gi atau 100 Gibibytes). Kubernetes menggunakan satuan biner standar IEC untuk ukuran penyimpanan.

2. volumeMode #

Menentukan bagaimana volume akan disajikan ke dalam kontainer:

  • Filesystem (Default): Volume akan diformat dengan sistem berkas (seperti ext4 atau xfs) sebelum dipasang ke kontainer. Ini adalah opsi standar untuk sebagian besar aplikasi.
  • Block: Volume disajikan sebagai raw block device tanpa filesystem apa pun. Opsi ini sangat berguna untuk aplikasi database berkinerja tinggi (seperti Oracle, Apache Cassandra, atau PostgreSQL tingkat lanjut) yang ingin melakukan manajemen blok I/O sendiri tanpa overhead dari filesystem Linux.

3. persistentVolumeReclaimPolicy #

Kebijakan yang menentukan apa yang harus dilakukan Kubernetes terhadap media penyimpanan fisik setelah objek PVC yang mengikatnya dihapus:

  • Retain (Direkomendasikan untuk Produksi): Ketika PVC dihapus, PV akan berubah status menjadi Released. Data fisik di dalam storage tetap aman dan tidak dihapus. Administrator kluster harus melakukan verifikasi manual sebelum membersihkan data tersebut.
  • Delete: Ketika PVC dihapus, objek PV beserta media penyimpanan fisik di cloud provider (seperti AWS EBS volume) akan dihapus secara otomatis. Ini adalah default untuk volume yang dibuat secara otomatis oleh StorageClass (dynamic provisioning).
  • Recycle (Sudah Deprecated): Menjalankan operasi pembersihan dasar (rm -rf /volume/*) pada volume NFS untuk membersihkan data lama, lalu membuat status PV kembali menjadi Available agar dapat diklaim ulang. Fitur ini sudah digantikan sepenuhnya oleh mekanisme dynamic provisioning yang lebih aman.

Memahami Daur Hidup Status PV (Lifecycle Phases) #

Sebuah objek PersistentVolume akan berpindah status secara dinamis di dalam database etcd kluster mengikuti interaksi yang dilakukan oleh user:

1. Available #

PV telah berhasil dibuat oleh Administrator atau Storage Controller dan sedang dalam kondisi siap untuk digunakan. Belum ada objek PVC mana pun yang mengikatnya.

2. Bound #

PV telah berhasil dicocokkan dan diikat (bound) secara eksklusif ke sebuah objek PVC. Selama dalam status ini, tidak boleh ada PVC lain yang dapat mengklaim PV ini. PV akan tetap berstatus Bound hingga objek PVC tersebut dihapus oleh user.

3. Released #

User telah menghapus objek PVC pendamping. Karena reclaim policy PV diatur sebagai Retain, Kubernetes memutus hubungan binding namun tidak menghapus data fisik. PV berstatus Released tetap terkunci secara administratif.

  • Penting: PV berstatus Released tidak dapat langsung diklaim kembali oleh PVC baru, karena di dalam metadata PV masih tersimpan referensi ke PVC lama (spec.claimRef).

4. Failed #

Terjadi kegagalan ketika Kubernetes mencoba melakukan penghapusan otomatis (pada policy Delete) atau pembersihan (pada policy Recycle). Status ini membutuhkan intervensi manual dari tim Platform Engineer untuk mendiagnosis masalah pada driver storage CSI.


Panduan Taktis: Menggunakan Kembali PV Berstatus Released #

Di lingkungan produksi, kita sering kali dihadapkan pada situasi di mana developer menghapus PVC secara tidak sengaja. Karena reclaim policy diset ke Retain, data kita masih aman di disk fisik, namun status PV tertahan di status Released. Bagaimana cara mengembalikan PV tersebut agar bisa digunakan kembali oleh PVC baru tanpa kehilangan data?

Berikut adalah langkah-langkah memulihkan PV berstatus Released kembali menjadi Available:

Langkah 1: Periksa Status PV #

Kita melihat PV tertahan di status Released dengan sisa referensi ke PVC lama:

kubectl get pv pv-production-postgres

Output:

NAME                     CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS     CLAIM
pv-production-postgres   100Gi      RWO            Retain           Released   production/postgres-pvc-old

Langkah 2: Hapus Blok claimRef Secara Manual #

Kunci yang membuat PV tersebut terkunci adalah properti spec.claimRef di dalam manifest PV. Kita dapat menghapus properti ini dengan menjalankan perintah edit:

kubectl edit pv pv-production-postgres

Di dalam editor teks yang muncul, cari blok claimRef di bawah spec dan hapus blok tersebut secara keseluruhan:

# SEBELUMNYA:
spec:
  claimRef:
    apiVersion: v1
    kind: PersistentVolumeClaim
    name: postgres-pvc-old
    namespace: production
    resourceVersion: "123456"
    uid: "abc-123-def"

# SETELAH DIEDIT (Hapus seluruh blok claimRef di atas):
spec:
  # Properti claimRef telah dihilangkan

Langkah 3: Verifikasi Status PV #

Setelah kita menyimpan perubahan tersebut, Kube-controller-manager akan mendeteksi hilangnya claimRef dan langsung mengubah status PV kembali menjadi Available:

kubectl get pv pv-production-postgres

Output:

NAME                     CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM
pv-production-postgres   100Gi      RWO            Retain           Available

Kini, pengembang aplikasi dapat membuat PVC baru yang menunjuk ke storageClassName atau label PV ini untuk menyambungkan kembali aplikasi ke data lama dengan aman.


Static Provisioning vs Dynamic Provisioning #

Ada dua cara untuk menyediakan volume PersistentVolume di Kubernetes:

1. Static Provisioning (Penyediaan Manual) #

Administrator kluster harus memprediksi kebutuhan storage di masa depan. Mereka membuat disk fisik di cloud console, mencatat ID volume, lalu menulis manifest YAML PV secara manual satu per satu.

  • Masalah: Menimbulkan hambatan operasional (operational bottleneck). Jika developer butuh database baru di tengah malam, mereka harus menunggu Administrator masuk kerja untuk membuatkan PV terlebih dahulu. Jika tidak ada PV yang cocok, PVC akan tertahan di status Pending selamanya.

2. Dynamic Provisioning (Penyediaan Otomatis) #

Mekanisme modern di mana kluster Kubernetes membuatkan disk fisik dan objek PV secara otomatis secara real-time begitu ada PVC baru yang dideklarasikan oleh developer. Hal ini dimungkinkan dengan adanya objek StorageClass.

  • Keuntungan: Efisiensi self-service penuh. Developer cukup membuat PVC, dan StorageClass akan memerintahkan driver CSI untuk memanggil cloud API untuk menyiapkan storage fisik secara otomatis dalam hitungan detik.

Node Affinity pada Local PersistentVolume #

Dalam beberapa skenario khusus (seperti kluster database berkinerja ekstrem), kita ingin menggunakan disk fisik SSD NVMe yang terpasang langsung secara fisik di dalam mesin node worker (local storage), bukan disk cloud yang diakses lewat jaringan virtual.

Karena data disimpan di disk fisik mesin tertentu, kita wajib memberi tahu Kubernetes agar tidak memindahkan Pod yang menggunakan storage ini ke mesin lain. Kita melakukan ini dengan menuliskan konfigurasi Node Affinity di manifest PV lokal:

apiVersion: v1
kind: PersistentVolume
metadata:
  name: local-ssd-pv-01
spec:
  capacity:
    storage: 500Gi
  volumeMode: Filesystem
  accessModes:
  - ReadWriteOnce
  persistentVolumeReclaimPolicy: Retain
  storageClassName: local-fast-ssd
  local:
    path: /mnt/disks/nvme-ssd-1       # Path mount di host node worker
  nodeAffinity:                       # Wajib didefinisikan!
    required:
      nodeSelectorTerms:
      - matchExpressions:
        - key: kubernetes.io/hostname
          operator: In
          values:
          - worker-node-3             # Disk lokal ini HANYA ada di worker-node-3

[!IMPORTANT] Saat menggunakan Local PV dengan Node Affinity, kita harus menyetel properti volumeBindingMode: WaitForFirstConsumer pada StorageClass yang bersangkutan. Jika kita menggunakan mode default Immediate, Kubernetes akan langsung melakukan binding PVC ke PV lokal sebelum Pod dijadwalkan, yang sering kali berujung pada kegagalan jika Pod tersebut ternyata tidak dapat dijadwalkan di worker-node-3 akibat keterbatasan CPU atau memori node.


Anti-Pattern Terkait PersistentVolume & Solusinya #

Berikut adalah tiga kesalahan fatal yang sering menimbulkan kekacauan data pada tingkat administratif:

Anti-Pattern 1: Menggunakan Reclaim Policy Delete untuk Database Produksi yang Diprovision secara Manual #

Menyetel persistentVolumeReclaimPolicy: Delete pada manifest PV manual database penting.

ANTI-PATTERN: persistentVolumeReclaimPolicy: Delete untuk Postgres DB Manual
// KITA MELAKUKAN:
- Kita membuat PV manual untuk server database menggunakan policy Delete.
- Developer secara tidak sengaja menjalankan perintah hapus namespace (kubectl delete namespace production) 
  atau menghapus PVC untuk uji coba.

// KONSEKUENSI DI PRODUKSI:
- Kehilangan Data Instan: Kubernetes akan langsung mendeteksi terhapusnya objek PVC.
- Karena policy diatur sebagai `Delete`, controller akan mengirim instruksi ke cloud provider 
  untuk menghapus volume fisik (EBS/GCP PD) dari console cloud.
- Seluruh data transaksi produksi musnah seketika dan tidak dapat dipulihkan kembali dari kluster.
✓ SOLUSI YANG BENAR:
- Selalu gunakan `persistentVolumeReclaimPolicy: Retain` pada semua manifest PV yang dibuat secara manual.
- Jika volume dibuat secara dinamis oleh StorageClass, pastikan kita mengaktifkan fitur perlindungan penghapusan 
  (*deletion protection*) pada tingkat database atau di sisi cloud provider.

Anti-Pattern 2: Menaruh Data Stateful pada PV Bertipe hostPath Tanpa Node Affinity #

Membuat PV manual menggunakan tipe driver hostPath tanpa menyertakan aturan nodeAffinity yang mengunci lokasi node worker.

ANTI-PATTERN: PersistentVolume hostPath Tanpa nodeAffinity
// KITA MELAKUKAN:
- Kita membuat PV bernama `data-pv` dengan driver `hostPath` menunjuk ke `/mnt/data` di host.
- Kita tidak menuliskan blok `nodeAffinity` di manifest PV tersebut.

// KONSEKUENSI DI PRODUKSI:
- Inkonsistensi Data: Scheduler akan menganggap PV ini dapat digunakan oleh Pod di node mana saja.
- Saat Pod dijadwalkan di `worker-node-1`, ia membaca data di `/mnt/data` milik `worker-node-1`.
- Esok harinya, Pod di-restart dan dijadwalkan di `worker-node-2`. Ia akan me-mount folder `/mnt/data` 
  di `worker-node-2` yang isinya bisa saja kosong atau berisi berkas sampah milik aplikasi lain, 
  mengakibatkan aplikasi crash atau salah membaca data status.
✓ SOLUSI YANG BENAR:
- Jangan gunakan `hostPath` untuk PV stateful umum.
- Jika terpaksa menggunakan penyimpanan lokal node worker, gunakan tipe volume **`local`** 
  dan wajib sertakan deklarasi `nodeAffinity` yang mengunci hostname node worker secara spesifik.

Anti-Pattern 3: Membiarkan PV Released Menumpuk di Kluster Tanpa Pembersihan #

Mengabaikan pemantauan kapasitas kluster sehingga banyak PV berstatus Released terbengkalai di database etcd.

ANTI-PATTERN: Membiarkan PV Released Terbengkalai Selamanya
// KITA MELAKUKAN:
- Tim developer sering melakukan deploy dan hapus aplikasi uji coba (CI/CD pipelines).
- Karena policy PV menggunakan `Retain`, setiap proses hapus menyisakan satu objek PV berstatus `Released`.
- Kita tidak memiliki prosedur pembersihan otomatis atau manual.

// KONSEKUENSI DI PRODUKSI:
- Pemborosan Anggaran Cloud: Disk cloud fisik di backend tetap aktif berjalan dan memotong tagihan cloud bulanan kita.
- Starvation PVC: Developer baru mencoba mendeploy aplikasi, namun PVC mereka stuck di status `Pending` 
  karena semua PV yang tersisa berstatus `Released` (terkunci), tidak ada PV berstatus `Available` yang siap diklaim.
✓ SOLUSI YANG BENAR:
- Lakukan audit berkala pada objek PV kluster menggunakan perintah: `kubectl get pv | grep Released`.
- Buat cron job pembersih otomatis di luar kluster yang mendeteksi PV `Released` berumur lebih dari 3 hari, 
  kemudian mengirimkan instruksi hapus ke cloud API dan API Server Kubernetes secara bersih.

Ringkasan #

  • Abstraksi Global Non-Namespaced — PersistentVolume adalah representasi storage fisik kluster di tingkat administratif yang bersifat global dan tidak terikat namespace.
  • Perlindungan Data via Retain — Selalu gunakan persistentVolumeReclaimPolicy: Retain untuk data produksi agar data fisik di disk tidak ikut terhapus saat objek PVC didelete.
  • volumeMode Block untuk DB — Gunakan setelan volumeMode: Block untuk database intensif performa tinggi guna melewati overhead formatting filesystem Linux.
  • Resolusi Status Released — Kembalikan PV berstatus Released menjadi Available dengan menghapus blok referensi spec.claimRef di dalam manifest PV.
  • Lokal PV Wajib Node Affinity — Saat menggunakan local storage NVMe, sertakan Node Affinity pada PV untuk menjamin Pod selalu dijadwalkan pada mesin fisik yang tepat.
  • Dynamic Provisioning untuk Skala — Gunakan StorageClass (dynamic provisioning) untuk menghindari bottleneck administratif dari proses pembuatan PV manual (static provisioning).
  • Hindari hostPath Liar — Jangan mendeploy PV hostPath tanpa menyertakan nodeAffinity guna menghindari tabrakan pembacaan data di node worker yang berbeda.

← Sebelumnya: Storage Problem di Distributed Systems   Berikutnya: PersistentVolumeClaim →

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