Anti-Pattern Storage #

Storage adalah area di mana kesalahan konfigurasi paling sering tidak terdeteksi sampai terjadi insiden. Container crash tidak menyebabkan kehilangan data pada stateless app, tapi pada stateful workload, satu konfigurasi yang salah bisa berarti data hilang permanen. Artikel ini mengkompilasi anti-pattern storage yang paling sering ditemui di cluster Kubernetes — bukan untuk menakut-nakuti, tapi supaya kamu tahu persis apa yang harus dihindari dan mengapa.

Anti-Pattern 1: Menyimpan State di Filesystem Container #

Ini adalah kesalahan paling fundamental dan paling sering dilakukan oleh developer yang baru migrasi ke Kubernetes.

# ANTI-PATTERN: menulis file penting langsung ke container
spec:
  containers:
  - name: app
    image: my-app:v1
    # Aplikasi menulis ke /var/app/uploads/ dan /var/app/cache/
    # TANPA volume — data ada di layer container ephemeral
Konsekuensi:

  App di-update → rolling update → container baru dari image bersih
                → /var/app/uploads/ HILANG
                → /var/app/cache/ HILANG

  Node di-maintain → Pod dipindah ke node lain → container baru
                   → Data HILANG

  Pod crash dan restart → container baru → Data HILANG
# BENAR: mount volume untuk semua data yang perlu persisten
spec:
  volumes:
  - name: uploads
    persistentVolumeClaim:
      claimName: app-uploads-pvc
  - name: cache
    emptyDir: {}           # cache boleh hilang, tapi tetap di volume terpisah
  containers:
  - name: app
    image: my-app:v1
    volumeMounts:
    - name: uploads
      mountPath: /var/app/uploads
    - name: cache
      mountPath: /var/app/cache

Anti-Pattern 2: Reclaim Policy Delete untuk Storage Produksi #

# ANTI-PATTERN: StorageClass dengan reclaimPolicy: Delete untuk database
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: database-storage     # nama menyiratkan untuk database
provisioner: ebs.csi.aws.com
reclaimPolicy: Delete         # ← BERBAHAYA untuk database
Konsekuensi:

  Developer menghapus StatefulSet karena "mau redeploy"
    → PVC masih ada (StatefulSet delete tidak hapus PVC)
    → Developer hapus PVC secara manual
    → PV dengan policy Delete langsung menghapus EBS volume
    → Data database hilang permanen
    → Tidak ada yang bisa dilakukan
# BENAR: Retain untuk storage yang berisi data kritikal
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: database-storage
provisioner: ebs.csi.aws.com
reclaimPolicy: Retain         # ← data aman, admin yang memutuskan nasibnya

Anti-Pattern 3: Tidak Ada Backup #

ANTI-PATTERN: menganggap PVC adalah backup yang cukup

Pola pikir yang salah:
  "Data ada di PVC, PVC ada di cloud disk, cloud disk redundant
   → pasti aman, tidak perlu backup"

Realita yang sering terjadi:
  ✗ Developer tidak sengaja hapus data di aplikasi
     → Data terhapus dari PVC, tidak ada cara restore

  ✗ Bug aplikasi menulis data korup ke database
     → Semua replica mengandung data korup, tidak ada titik restore

  ✗ StatefulSet di-delete, PVC ikut terhapus karena misconfigurasi
     → Data hilang permanen

  ✗ Ransomware atau insider threat menghapus semua data
     → Tidak ada backup = tidak ada recovery
BENAR: backup berlapis

  Level 1: Volume Snapshot setiap hari (cepat, untuk rollback storage)
  Level 2: Database dump setiap jam ke S3 (untuk recovery data aplikasi)
  Level 3: Backup ke region lain setiap minggu (untuk disaster recovery)

Anti-Pattern 4: hostPath di Workload Produksi #

# ANTI-PATTERN: hostPath untuk data persisten aplikasi
spec:
  volumes:
  - name: data
    hostPath:
      path: /data/myapp     # data disimpan di node tertentu
  containers:
  - name: app
    volumeMounts:
    - name: data
      mountPath: /var/data
Konsekuensi:

  Pod harus selalu berjalan di node yang sama
    → Scheduling terkunci ke satu node (node affinity implicit)
    → Node itu maintenance? Pod tidak bisa berjalan di tempat lain
    → Node itu failure? Data hilang karena tidak ada replikasi

  Berbeda antar node
    → Data di Node A tidak sama dengan di Node B
    → Tidak ada konsistensi
# BENAR: gunakan PVC dengan StorageClass yang tepat
spec:
  volumes:
  - name: data
    persistentVolumeClaim:
      claimName: app-data-pvc    # volume yang bisa follow Pod ke node manapun

Anti-Pattern 5: Satu PVC untuk Banyak Database Instance #

# ANTI-PATTERN: semua instance database share satu PVC
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: postgres
spec:
  replicas: 3
  template:
    spec:
      volumes:
      - name: data
        persistentVolumeClaim:
          claimName: postgres-shared-data    # ← SALAH: satu PVC untuk 3 Pod
Konsekuensi:

  RWO access mode: hanya satu node yang bisa mount
    → Pod di node berbeda tidak bisa mount volume
    → 2 dari 3 Pod stuck di Pending

  RWX access mode: semua Pod menulis ke direktori yang sama
    → Konflik antara instance PostgreSQL
    → Data korup karena multiple writers tanpa koordinasi
# BENAR: volumeClaimTemplates untuk PVC terpisah per Pod
spec:
  volumeClaimTemplates:
  - metadata:
      name: data
    spec:
      accessModes: ["ReadWriteOnce"]
      storageClassName: db-storage
      resources:
        requests:
          storage: 50Gi
# Kubernetes membuat: data-postgres-0, data-postgres-1, data-postgres-2

Anti-Pattern 6: Tidak Menetapkan storageClassName #

# ANTI-PATTERN: PVC tanpa storageClassName
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: app-data
spec:
  accessModes: [ReadWriteOnce]
  resources:
    requests:
      storage: 10Gi
  # tidak ada storageClassName
Konsekuensi:

  Jika ada default StorageClass: PVC menggunakan default
    → Mungkin default-nya adalah storage murah tapi lambat
    → Database yang butuh IOPS tinggi akan lambat

  Jika tidak ada default StorageClass: PVC Pending selamanya
    → Developer bingung kenapa PVC tidak bound
    → Tidak ada error message yang jelas

  Jika default StorageClass berubah: behavior PVC yang sama berubah
    → Cluster yang di-upgrade bisa tiba-tiba punya behavior storage berbeda
# BENAR: selalu eksplisit tentukan storageClassName
spec:
  storageClassName: db-storage   # eksplisit dan terdokumentasi

Anti-Pattern 7: Resource Tanpa Limit di Storage-Intensive Workload #

# ANTI-PATTERN: batch job menulis ke storage tanpa batas
spec:
  containers:
  - name: data-processor
    image: processor:v1
    # tidak ada resource limits
    # tidak ada ephemeral-storage limits
Konsekuensi:

  Batch job membuat file temporary dalam jumlah besar
    → Disk node penuh
    → kubelet mendeteksi DiskPressure
    → kubelet mulai evict Pod lain di node yang sama
    → Workload produksi yang tidak bersalah terkena dampak
# BENAR: batasi ephemeral storage untuk workload yang menulis banyak
spec:
  containers:
  - name: data-processor
    image: processor:v1
    resources:
      requests:
        ephemeral-storage: "1Gi"
      limits:
        ephemeral-storage: "5Gi"   # batas penggunaan disk ephemeral container

Ringkasan #

  • Jangan simpan state di filesystem container — data yang tidak di-mount ke volume hilang saat container restart; ini anti-pattern paling umum di aplikasi yang baru dikontainerisasi.
  • Retain policy untuk storage produksi — Delete policy menghapus data permanen saat PVC dihapus; gunakan Retain dan biarkan admin yang memutuskan nasib data.
  • Backup bukan opsional — replikasi storage dan cloud redundancy tidak melindungi dari penghapusan data yang disengaja atau korupsi; backup berlapis adalah keharusan.
  • Hindari hostPath untuk data persisten — terikat ke satu node, tidak ada failover, tidak ada replikasi; gunakan PVC yang bisa follow Pod ke node manapun.
  • volumeClaimTemplates, bukan shared PVC di StatefulSet — setiap instance database harus punya PVC sendiri; berbagi satu PVC antar instance database menyebabkan konflik atau Pod stuck.
  • Selalu eksplisit tentukan storageClassName — jangan bergantung pada default yang bisa berubah; eksplisit lebih baik dari implisit untuk konfigurasi yang kritikal.

← Sebelumnya: Dynamic Provisioning   Berikutnya: Storage Performance →

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