Database di Kubernetes #

Menjalankan database di Kubernetes adalah topik yang sering memicu perdebatan di komunitas engineering. Sebagian berpendapat Kubernetes tidak cocok untuk workload stateful. Sebagian lagi berhasil menjalankan database di Kubernetes dalam skala besar di produksi. Keduanya tidak salah — konteksnya yang berbeda. Artikel ini membantu kamu memutuskan dengan data, bukan dengan opini.

Apa yang Membuat Database Berbeda #

Database bukan sekadar aplikasi biasa yang perlu storage. Ada beberapa karakteristik yang membuatnya lebih kompleks:

Perbedaan database vs aplikasi stateless:

Aplikasi stateless:
  ✓ Semua instance identik — bisa kill dan replace mana saja
  ✓ Scale-out dengan menambah replica lebih mudah
  ✓ Tidak ada state yang perlu dijaga konsisten antar instance
  ✓ Restart = fresh start tanpa konsekuensi

Database:
  ✗ Setiap instance punya identitas (primary, secondary, replica-1, dst)
  ✗ Scale-out butuh proses khusus (join cluster, sync data dulu)
  ✗ State harus konsisten dan terjaga saat ada kegagalan
  ✗ Restart bisa memerlukan recovery procedure
  ✗ Upgrade versi butuh koordinasi antar node cluster

Kapan Database di Kubernetes Masuk Akal #

Pertimbangkan database di Kubernetes jika:
  ✓ Tim punya keahlian operasional database di Kubernetes
  ✓ Butuh portabilitas (berjalan sama di cloud manapun atau on-premise)
  ✓ Strategi multi-cloud atau menghindari vendor lock-in
  ✓ Database development/staging yang boleh lebih sederhana
  ✓ Database untuk microservice kecil dengan traffic rendah
  ✓ Sudah menggunakan operator (Zalando Postgres Operator, Vitess, dll)

Pertimbangkan managed service (RDS, Cloud SQL, Atlas) jika:
  ✓ Database adalah core business dan downtime sangat mahal
  ✓ Tim tidak punya bandwidth untuk mengelola operasional database
  ✓ SLA tinggi (99.99%) lebih mudah dicapai dengan managed service
  ✓ Backup, failover, patching diinginkan "by default" tanpa setup
  ✓ Cost operasional yang diperhitungkan

Pola Dasar: StatefulSet untuk Database Tunggal #

Untuk database sederhana (single instance, bukan cluster), StatefulSet dengan PVC sudah cukup:

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: postgres
  namespace: production
spec:
  serviceName: postgres
  replicas: 1              # single instance — tidak ada replication
  selector:
    matchLabels:
      app: postgres
  template:
    metadata:
      labels:
        app: postgres
    spec:
      containers:
      - name: postgres
        image: postgres:15.4
        env:
        - name: POSTGRES_DB
          value: "appdb"
        - name: POSTGRES_USER
          value: "appuser"
        - name: POSTGRES_PASSWORD
          valueFrom:
            secretKeyRef:
              name: postgres-secret
              key: password
        - name: PGDATA
          value: /var/lib/postgresql/data/pgdata
        ports:
        - containerPort: 5432
        resources:
          requests:
            cpu: "500m"
            memory: "1Gi"
          limits:
            cpu: "2000m"
            memory: "4Gi"
        volumeMounts:
        - name: data
          mountPath: /var/lib/postgresql/data
        livenessProbe:
          exec:
            command:
            - pg_isready
            - -U
            - appuser
          initialDelaySeconds: 30
          periodSeconds: 10
        readinessProbe:
          exec:
            command:
            - pg_isready
            - -U
            - appuser
          initialDelaySeconds: 5
          periodSeconds: 5
  volumeClaimTemplates:
  - metadata:
      name: data
    spec:
      accessModes: ["ReadWriteOnce"]
      storageClassName: db-storage      # StorageClass dengan IOPS tinggi
      resources:
        requests:
          storage: 50Gi

Service untuk Akses Database #

# Service untuk koneksi internal cluster
apiVersion: v1
kind: Service
metadata:
  name: postgres
  namespace: production
spec:
  selector:
    app: postgres
  ports:
  - port: 5432
    targetPort: 5432
  clusterIP: None           # Headless Service untuk StatefulSet
                            # DNS: postgres.production.svc.cluster.local

---
# Jika butuh koneksi dari luar cluster (untuk debugging)
apiVersion: v1
kind: Service
metadata:
  name: postgres-external
  namespace: production
spec:
  selector:
    app: postgres
  ports:
  - port: 5432
    targetPort: 5432
  type: ClusterIP           # Jangan ekspos database ke internet!
                            # Gunakan kubectl port-forward untuk debugging

Operator Pattern untuk Database Kompleks #

Untuk database dengan replication, high availability, dan automated failover, pendekatan manual tidak scalable. Operator adalah solusinya — program yang mengotomasi semua operasional kompleks menggunakan Kubernetes API.

Operator Pattern:

Custom Resource Definition (CRD):
  apiVersion: acid.zalan.do/v1
  kind: postgresql             ← resource kustom yang didefinisikan operator
  metadata:
    name: production-db
  spec:
    teamId: "platform"
    volume:
      size: 100Gi
    numberOfInstances: 3       ← 1 primary + 2 secondary
    postgresql:
      version: "15"
    backup:
      retentionDays: 14

Operator Controller:
  → Baca spec postgresql "production-db"
  → Buat StatefulSet dengan 3 instance PostgreSQL
  → Konfigurasi Patroni untuk HA dan automatic failover
  → Setup backup terjadwal ke S3
  → Handle failover otomatis saat primary mati
  → Manage rolling upgrade saat versi PostgreSQL diperbarui

Operator populer untuk database di Kubernetes:

PostgreSQL:
  → Zalando Postgres Operator (paling mature, production-proven)
  → CloudNativePG (CNCF project, modern design)
  → Crunchy Data PGO

MySQL / MariaDB:
  → Percona Operator for MySQL
  → Oracle MySQL Operator

MongoDB:
  → MongoDB Community Operator
  → Percona Operator for MongoDB

Redis:
  → Redis Operator (Spotahome)
  → Redis Enterprise Operator

Kafka:
  → Strimzi (CNCF project, paling mature)

Checklist Sebelum Database ke Kubernetes Production #

STORAGE:
  □ StorageClass dengan IOPS yang tepat untuk workload
  □ volumeBindingMode: WaitForFirstConsumer (untuk multi-AZ)
  □ reclaimPolicy: Retain agar data tidak terhapus saat PVC dihapus
  □ Storage yang cukup dengan buffer minimal 30%

BACKUP:
  □ Backup otomatis terjadwal (minimal sekali sehari)
  □ Backup disimpan di tempat terpisah dari cluster
  □ Proses restore sudah diuji dan terdokumentasi
  □ Point-in-time recovery dikonfigurasi jika butuh

HIGH AVAILABILITY:
  □ Minimal 2 node untuk replicated database
  □ Anti-affinity rules agar replica tidak di node yang sama
  □ Automatic failover dikonfigurasi dan diuji
  □ Connection pooling untuk mengelola koneksi

MONITORING:
  □ Database metrics di-export ke Prometheus
  □ Alert untuk: disk usage > 80%, replication lag, connection saturation
  □ Slow query logging aktif

SECURITY:
  □ Kredensial database disimpan di Secret (bukan ConfigMap)
  □ Akses network dibatasi dengan NetworkPolicy
  □ Database tidak di-expose keluar cluster

Ringkasan #

  • Database di Kubernetes bisa dilakukan, tapi lebih kompleks — stateful lifecycle, replication, failover, dan backup butuh lebih dari sekadar membuat StatefulSet.
  • Managed service untuk database kritikal — jika downtime sangat mahal dan tim tidak punya bandwidth operasional, RDS/Cloud SQL/Atlas lebih pragmatis.
  • StatefulSet untuk database sederhana — single-instance database untuk microservice kecil atau non-kritikal sudah cukup dengan StatefulSet + PVC.
  • Operator untuk database kompleks — Zalando Postgres Operator, CloudNativePG, Strimzi untuk Kafka; operator mengotomasi semua yang tidak bisa dilakukan StatefulSet biasa.
  • StorageClass dengan IOPS tinggi untuk database — jangan gunakan default StorageClass yang dioptimalkan untuk cost; database butuh throughput dan latensi yang konsisten.
  • Backup adalah keharusan absolut — backup yang tidak diuji sama dengan tidak punya backup; test restore procedure secara regular.

← Sebelumnya: StorageClass   Berikutnya: StatefulSet + PVC →

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