Volume #
Volume adalah mekanisme di Kubernetes yang memungkinkan container mengakses storage di luar filesystem ephemeral mereka sendiri. Berbeda dari konsep volume di Docker yang lebih sederhana, volume Kubernetes punya lifecycle yang terikat ke Pod dan mendukung puluhan jenis backend — dari direktori di node hingga disk cloud, dari NFS hingga secret yang di-inject sebagai file. Memahami jenis-jenis volume dan cara kerjanya adalah fondasi sebelum masuk ke PersistentVolume dan StorageClass.
Cara Volume Bekerja di Pod #
Volume didefinisikan di level Pod (bukan di level container), lalu di-mount ke dalam container yang membutuhkannya. Ini memungkinkan beberapa container dalam Pod yang sama mengakses volume yang sama.
spec:
volumes: # ← definisi volume di level Pod
- name: data
emptyDir: {}
- name: config
configMap:
name: app-config
containers:
- name: app
volumeMounts: # ← mount ke dalam container
- name: data
mountPath: /var/data
- name: config
mountPath: /etc/config
readOnly: true
- name: sidecar
volumeMounts:
- name: data # ← container lain bisa mount volume yang sama
mountPath: /shared-data
Setiap volume punya name yang unik dalam Pod. Container me-mount volume berdasarkan nama tersebut ke path yang dikehendaki di dalam filesystem container.
emptyDir #
Volume paling dasar — direktori kosong yang dibuat saat Pod mulai dan dihapus saat Pod mati. Datanya hanya ada selama Pod hidup.
volumes:
- name: cache
emptyDir: {} # di filesystem node (disk)
- name: shared-mem
emptyDir:
medium: Memory # di memory (tmpfs) — lebih cepat, tapi pakai RAM
sizeLimit: "256Mi" # batas agar tidak makan terlalu banyak RAM
emptyDir dengan medium: Memory berguna untuk:
- High-speed cache yang butuh latensi sangat rendah
- Berbagi data antar container dalam volume yang tidak perlu persisten
- Menghindari disk I/O untuk data sementara
hostPath #
Mount direktori atau file dari filesystem node langsung ke dalam container. Berbahaya jika dipakai sembarangan, tapi ada kasus valid.
volumes:
- name: docker-sock
hostPath:
path: /var/run/docker.sock
type: Socket # pastikan yang di-mount adalah socket
- name: node-logs
hostPath:
path: /var/log
type: Directory
Tipe yang tersedia untuk hostPath:
DirectoryOrCreate → buat direktori jika belum ada
Directory → harus sudah ada, gagal jika tidak
FileOrCreate → buat file jika belum ada
File → harus sudah ada
Socket → Unix socket yang sudah ada
CharDevice → character device yang sudah ada
BlockDevice → block device yang sudah ada
hostPath memberi container akses langsung ke filesystem host — ini risiko keamanan yang signifikan. Gunakan hanya untuk kasus yang benar-benar membutuhkannya seperti DaemonSet yang perlu akses ke log node atau socket Docker, dan selalu gunakan readOnly: true jika memungkinkan.configMap dan secret #
ConfigMap dan Secret bisa di-mount sebagai volume, memungkinkan konfigurasi dan kredensial diakses sebagai file di dalam container. Ini lebih fleksibel dari environment variable untuk konfigurasi yang panjang atau struktural (seperti file YAML atau JSON).
volumes:
- name: app-config
configMap:
name: my-configmap
items: # pilih key mana yang di-mount
- key: nginx.conf
path: nginx.conf # nama file di dalam container
- key: app.yaml
path: config/app.yaml # bisa di subdirektori
- name: tls-certs
secret:
secretName: tls-secret
defaultMode: 0400 # permission file (read-only untuk owner)
# Di dalam container, file tersedia di mountPath:
# /etc/nginx/nginx.conf
# /etc/config/app.yaml
# /etc/tls/tls.crt
# /etc/tls/tls.key
Keuntungan mount sebagai file dibanding environment variable: file bisa di-update tanpa restart Pod. Kubernetes memperbarui isi file saat ConfigMap berubah (ada delay sekitar 1-2 menit). Namun aplikasi tetap perlu membaca ulang file tersebut — tidak semua framework melakukannya secara otomatis.
downwardAPI #
Mount informasi tentang Pod itu sendiri sebagai file ke dalam container. Berguna untuk aplikasi yang perlu tahu nama Pod-nya, namespace, atau label-nya sendiri.
volumes:
- name: pod-info
downwardAPI:
items:
- path: "pod-name"
fieldRef:
fieldPath: metadata.name
- path: "pod-namespace"
fieldRef:
fieldPath: metadata.namespace
- path: "cpu-limit"
resourceFieldRef:
containerName: app
resource: limits.cpu
projected #
projected menggabungkan beberapa sumber volume (serviceAccountToken, configMap, secret, downwardAPI) ke dalam satu direktori:
volumes:
- name: all-in-one
projected:
sources:
- configMap:
name: app-config
- secret:
name: app-secret
- downwardAPI:
items:
- path: "pod-name"
fieldRef:
fieldPath: metadata.name
Semua sumber akan tersedia dalam satu mountPath — mengurangi jumlah volumeMounts di container.
Volume untuk Cloud Provider #
Setiap cloud provider menyediakan tipe volume khusus untuk storage mereka. Meskipun sekarang penggunaan langsung tipe ini sudah digantikan oleh CSI driver, penting untuk mengenalinya:
# AWS EBS (cara lama, sekarang pakai CSI)
volumes:
- name: data
awsElasticBlockStore:
volumeID: vol-0a1b2c3d4e5f
fsType: ext4
# GCE Persistent Disk (cara lama)
volumes:
- name: data
gcePersistentDisk:
pdName: my-data-disk
fsType: ext4
# Azure Disk (cara lama)
volumes:
- name: data
azureDisk:
diskName: myDisk
diskURI: /subscriptions/.../disks/myDisk
Cara modern: semua ini digantikan oleh CSI (Container Storage Interface) driver yang lebih generik dan tidak terikat ke in-tree code Kubernetes.
CSI Volume #
Container Storage Interface adalah standar yang memungkinkan vendor storage mengembangkan driver mereka sendiri tanpa harus memodifikasi kode Kubernetes itu sendiri.
# Volume menggunakan CSI driver
volumes:
- name: data
csi:
driver: disk.csi.azure.com # nama CSI driver yang ter-install
volumeAttributes:
skuName: Premium_LRS
nodeStageSecretRef:
name: azure-disk-secret
namespace: default
Dalam praktik produksi modern, hampir semua penggunaan persistent storage dilakukan melalui PersistentVolumeClaim yang di-belakangnya menggunakan CSI driver — bukan mendefinisikan CSI volume secara langsung di Pod spec.
subPath: Mount Sebagian Volume #
Terkadang kamu ingin me-mount hanya sebagian dari volume, atau me-mount beberapa bagian ke path yang berbeda:
volumeMounts:
- name: data
mountPath: /var/lib/postgresql/data
subPath: postgres # hanya subdirektori "postgres" di dalam volume
- name: data
mountPath: /var/lib/redis/data
subPath: redis # subdirektori "redis" di volume yang sama
Pola ini berguna ketika satu PVC digunakan untuk menyimpan data dari beberapa komponen, masing-masing di subdirektori yang berbeda.
Ringkasan #
- Volume didefinisikan di level Pod, di-mount di level container — satu volume bisa di-mount oleh beberapa container dalam Pod yang sama.
- emptyDir untuk data sementara dalam Pod —
medium: Memoryuntuk performa tinggi, tapi ingat ini mengonsumsi RAM node.- hostPath hanya untuk kasus khusus — DaemonSet yang perlu akses log node atau socket; selalu batasi dengan
readOnly: truedan type yang tepat.- configMap dan secret sebagai file — lebih fleksibel dari env var untuk konfigurasi panjang; file otomatis diperbarui saat ConfigMap/Secret berubah (dengan delay kecil).
- CSI adalah standar modern — semua cloud provider dan storage vendor sekarang menggunakan CSI driver; hindari tipe volume in-tree yang sudah deprecated.
- subPath untuk berbagi satu volume — me-mount subdirektori tertentu dari volume; berguna agar beberapa komponen bisa berbagi satu PVC dengan namespace direktori yang terpisah.
← Sebelumnya: Ephemeral vs Persistent Storage Berikutnya: Storage Problem di Distributed Systems →