StatefulSets & Penyimpanan Persisten dalam Kubernetes
Buat aplikasi stateful dengan skalasi terurut dan data yang bertahan lama
Kubernetes StatefulSets adalah solusi utama untuk mengelola aplikasi berstatus yang memerlukan identitas stabil, penyimpanan permanen, dan pola penyebaran terurut—penting untuk database, sistem terdistribusi, dan lapisan caching.
Jika Anda baru dengan Kubernetes atau sedang mengatur klaster, pertimbangkan untuk menjelajahi distribusi Kubernetes seperti k3s atau MicroK8s untuk pengembangan, atau instalasi Kubernetes dengan Kubespray untuk klaster berbasis produksi.
Gambar yang menarik ini dihasilkan oleh model AI Flux 1 dev.
Apa itu StatefulSets?
StatefulSets adalah objek API beban kerja Kubernetes yang dirancang khusus untuk mengelola aplikasi berstatus. Berbeda dengan Deployments yang memperlakukan semua pod sebagai saling menggantikan, StatefulSets mempertahankan identitas unik untuk setiap pod dengan jaminan tentang urutan dan keunikan.
Fitur Utama:
- Identitas Jaringan Stabil: Setiap pod mendapatkan nama host yang dapat diprediksi yang bertahan selama restart
- Penyimpanan Permanen: Klaim Volume Persisten yang ditujukan untuk mengikuti pod selama reschedule
- Penyebaran Terurut: Pod dibuat secara berurutan (0, 1, 2…) dan dihentikan dalam urutan terbalik
- Pembaruan Terurut: Pembaruan berjalan dalam urutan, memastikan stabilitas aplikasi
StatefulSets sangat penting untuk aplikasi seperti PostgreSQL, MySQL, MongoDB, Cassandra, Elasticsearch, Kafka, ZooKeeper, Redis, dan etcd—setiap beban kerja di mana identitas pod dan keberlanjutan data penting.
Memahami Penyimpanan Permanen dalam Kubernetes
Kubernetes menyediakan lapisan abstraksi penyimpanan yang canggih yang memisahkan manajemen penyimpanan dari siklus hidup pod:
Komponen Penyimpanan
PersistentVolume (PV): Sebuah bagian penyimpanan dalam klaster yang disediakan oleh administrator atau dibuat secara dinamis melalui StorageClass. PVs ada secara independen dari pod.
PersistentVolumeClaim (PVC): Permintaan penyimpanan oleh pod. PVCs mengikat ke PVs yang tersedia yang cocok dengan kebutuhan mereka (ukuran, mode akses, kelas penyimpanan).
StorageClass: Mendefinisikan berbagai “kelas” penyimpanan dengan berbagai penyedia (AWS EBS, GCE PD, Azure Disk, NFS, dll.) dan parameter seperti replikasi, tingkat kinerja, dan kebijakan cadangan.
Mode Akses
- ReadWriteOnce (RWO): Volume dipasang sebagai baca-tulis oleh satu node
- ReadOnlyMany (ROX): Volume dipasang sebagai baca-hanya oleh banyak node
- ReadWriteMany (RWX): Volume dipasang sebagai baca-tulis oleh banyak node (memerlukan backend penyimpanan khusus)
Arsitektur Penyimpanan StatefulSet
StatefulSets menggunakan volumeClaimTemplates untuk secara otomatis menciptakan PersistentVolumeClaims untuk setiap replika pod. Ini secara fundamental berbeda dari Deployments:
Cara volumeClaimTemplates Bekerja
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: mysql
spec:
serviceName: mysql-service
replicas: 3
selector:
matchLabels:
app: mysql
template:
metadata:
labels:
app: mysql
spec:
containers:
- name: mysql
image: mysql:8.0
ports:
- containerPort: 3306
name: mysql
volumeMounts:
- name: data
mountPath: /var/lib/mysql
env:
- name: MYSQL_ROOT_PASSWORD
valueFrom:
secretKeyRef:
name: mysql-secret
key: password
volumeClaimTemplates:
- metadata:
name: data
spec:
accessModes: [ "ReadWriteOnce" ]
storageClassName: "fast-ssd"
resources:
requests:
storage: 10Gi
Ketika Anda membuat StatefulSet ini:
- Kubernetes membuat pod
mysql-0dan PVCdata-mysql-0 - Lalu membuat pod
mysql-1dan PVCdata-mysql-1 - Akhirnya membuat pod
mysql-2dan PVCdata-mysql-2
Setiap pod mendapatkan volume permanen 10GB sendiri. Jika mysql-1 dihapus atau dijadwalkan ulang, Kubernetes membuatnya kembali dan menghubungkan PVC data-mysql-1 yang sama, mempertahankan semua data.
Membuat Service Headless untuk StatefulSets
StatefulSets memerlukan Service Headless untuk menyediakan identitas jaringan stabil:
apiVersion: v1
kind: Service
metadata:
name: mysql-service
spec:
clusterIP: None # Ini membuatnya menjadi service headless
selector:
app: mysql
ports:
- port: 3306
name: mysql
Ini menciptakan entri DNS untuk setiap pod:
mysql-0.mysql-service.default.svc.cluster.localmysql-1.mysql-service.default.svc.cluster.localmysql-2.mysql-service.default.svc.cluster.local
Aplikasi dapat terhubung langsung ke instance pod tertentu menggunakan nama DNS stabil ini.
Pola Penyebaran StatefulSet
Untuk tim yang mengelola penyebaran Kubernetes yang kompleks, Helm Charts menyediakan cara yang kuat untuk mengemas dan mendeploy StatefulSets dengan templating, versioning, dan manajemen dependensi. Helm menyederhanakan pengelolaan konfigurasi StatefulSet di berbagai lingkungan.
Penyebaran Terurut
Ketika menyebar dari 3 ke 5 replika:
kubectl scale statefulset mysql --replicas=5
Kubernetes menciptakan pod dalam urutan: mysql-3 → menunggu siap → mysql-4
Ketika menyebar dari 5 ke 3:
kubectl scale statefulset mysql --replicas=3
Kubernetes menghentikan dalam urutan terbalik: mysql-4 → menunggu penghentian → mysql-3
Pembaruan Berjalan
StatefulSets mendukung dua strategi pembaruan:
OnDelete: Pembaruan manual—pod hanya diperbarui ketika Anda menghapusnya RollingUpdate: Pembaruan otomatis berurutan dalam urutan ordinal terbalik
spec:
updateStrategy:
type: RollingUpdate
rollingUpdate:
partition: 2 # Hanya perbarui pod dengan ordinal >= 2
Parameter partition memungkinkan pengujian canary—Anda dapat memperbarui pod dengan nomor tinggi terlebih dahulu sebelum menyebar ke semua replika.
Praktik Terbaik Penyimpanan
Pemrosesan Dinamis
Selalu gunakan StorageClasses untuk pemrosesan volume dinamis:
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: fast-ssd
provisioner: kubernetes.io/aws-ebs
parameters:
type: gp3
iops: "3000"
throughput: "125"
allowVolumeExpansion: true
reclaimPolicy: Retain
allowVolumeExpansion: Memungkinkan memperbesar PVC tanpa membuat ulang
reclaimPolicy: Retain mempertahankan data PV setelah penghapusan PVC, Delete menghapusnya secara otomatis
Kebijakan Retensi PVC
Kubernetes 1.23+ mendukung persistentVolumeClaimRetentionPolicy:
spec:
persistentVolumeClaimRetentionPolicy:
whenDeleted: Retain # Pertahankan PVC ketika StatefulSet dihapus
whenScaled: Delete # Hapus PVC ketika menyebar ke bawah
Opsi:
- Retain: Pertahankan PVC (perilaku default, paling aman)
- Delete: Hapus PVC secara otomatis (berguna untuk lingkungan pengembangan)
Strategi Cadangan
Snapshots Volume: Gunakan sumber daya VolumeSnapshot untuk membuat cadangan titik dalam waktu
apiVersion: snapshot.storage.k8s.io/v1
kind: VolumeSnapshot
metadata:
name: mysql-snapshot-20251113
spec:
volumeSnapshotClassName: csi-snapclass
source:
persistentVolumeClaimName: data-mysql-0
Cadangan Tingkat Aplikasi: Gunakan alat seperti mysqldump, pg_dump, atau Velero untuk cadangan database khusus
Replikasi Terdistribusi: Konfigurasikan replikasi tingkat aplikasi (replikasi MySQL, replikasi streaming PostgreSQL) sebagai pertahanan pertama
Kasus Penggunaan Nyata
Klaster Database (PostgreSQL)
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: postgres
spec:
serviceName: postgres
replicas: 3
selector:
matchLabels:
app: postgres
template:
metadata:
labels:
app: postgres
spec:
containers:
- name: postgres
image: postgres:16
ports:
- containerPort: 5432
env:
- name: POSTGRES_PASSWORD
valueFrom:
secretKeyRef:
name: postgres-secret
key: password
- name: PGDATA
value: /var/lib/postgresql/data/pgdata
volumeMounts:
- name: data
mountPath: /var/lib/postgresql/data
volumeClaimTemplates:
- metadata:
name: data
spec:
accessModes: ["ReadWriteOnce"]
storageClassName: "standard"
resources:
requests:
storage: 20Gi
Cache Terdistribusi (Redis)
Untuk klaster Redis, Anda memerlukan StatefulSet dan konfigurasi yang hati-hati:
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: redis
spec:
serviceName: redis-service
replicas: 6
selector:
matchLabels:
app: redis
template:
metadata:
labels:
app: redis
spec:
containers:
- name: redis
image: redis:7-alpine
command:
- redis-server
- "--appendonly"
- "yes"
- "--appendfsync"
- "everysec"
ports:
- containerPort: 6379
name: redis
volumeMounts:
- name: data
mountPath: /data
volumeClaimTemplates:
- metadata:
name: data
spec:
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 5Gi
Antrian Pesan (Kafka)
Kafka memerlukan penyimpanan permanen untuk log dan identitas jaringan stabil untuk koordinasi broker:
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: kafka
spec:
serviceName: kafka-service
replicas: 3
selector:
matchLabels:
app: kafka
template:
metadata:
labels:
app: kafka
spec:
containers:
- name: kafka
image: confluentinc/cp-kafka:7.5.0
ports:
- containerPort: 9092
name: kafka
env:
- name: KAFKA_BROKER_ID
valueFrom:
fieldRef:
fieldPath: metadata.name
volumeMounts:
- name: data
mountPath: /var/lib/kafka/data
volumeClaimTemplates:
- metadata:
name: data
spec:
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 100Gi
Pemantauan dan Penyelesaian Masalah
Untuk referensi menyeluruh tentang perintah Kubernetes yang digunakan dalam bagian ini, lihat Kubernetes Cheatsheet.
Periksa Status StatefulSet
# Lihat detail StatefulSet
kubectl get statefulset mysql
kubectl describe statefulset mysql
# Periksa urutan pembuatan pod dan status
kubectl get pods -l app=mysql -w
# Lihat status PVC
kubectl get pvc
kubectl describe pvc data-mysql-0
Masalah Umum
Pod Tertahan dalam Pending: Periksa status PVC dan ketersediaan penyimpanan
kubectl describe pod mysql-0
kubectl get events --sort-by='.lastTimestamp'
Penyimpanan Penuh: Perluas PVC jika StorageClass memungkinkan
kubectl patch pvc data-mysql-0 -p '{"spec":{"resources":{"requests":{"storage":"20Gi"}}}}'
Pod Tidak Dapat Dihentikan: Periksa kunci aplikasi atau masalah pemutusan volume
kubectl delete pod mysql-0 --grace-period=0 --force
Metrik yang Perlu Dipantau
- Penggunaan Penyimpanan: Pantau kapasitas PVC dan persentase penggunaan
- Kinerja I/O: Lacak IOPS, throughput, dan latensi
- Restart Pod: Restart yang sering mungkin menunjukkan masalah penyimpanan
- Waktu Pengikatan PVC: Waktu pengikatan yang lambat menunjukkan masalah pemrosesan
Strategi Migrasi
Ketika bermigrasi ke StatefulSets, pastikan klaster Kubernetes Anda dikonfigurasi dengan benar. Untuk pengaturan homelab atau klaster kecil, tinjau perbandingan menyeluruh dari distribusi Kubernetes untuk memilih platform yang tepat untuk kebutuhan beban kerja Anda.
Dari Deployment ke StatefulSet
- Buat StatefulSet dengan volumeClaimTemplates
- Skalakan turun Deployment secara halus
- Pulihkan data dari cadangan ke pod StatefulSet
- Perbarui referensi DNS/Service
- Hapus Deployment lama dan PVCs
Cadangkan Sebelum Migrasi
# Snapshot PVC yang ada
kubectl get pvc -o yaml > pvc-backup.yaml
# Buat snapshot volume
kubectl apply -f volume-snapshot.yaml
Pertimbangan Keamanan
Enkripsi Penyimpanan
Aktifkan enkripsi di tempat menggunakan parameter StorageClass:
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: encrypted-storage
provisioner: kubernetes.io/aws-ebs
parameters:
type: gp3
encrypted: "true"
kmsKeyId: arn:aws:kms:us-east-1:123456789012:key/abcd-1234
Kontrol Akses
Gunakan RBAC untuk membatasi siapa yang dapat menciptakan/merubah StatefulSets dan PVCs:
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: statefulset-manager
rules:
- apiGroups: ["apps"]
resources: ["statefulsets"]
verbs: ["get", "list", "create", "update", "delete"]
- apiGroups: [""]
resources: ["persistentvolumeclaims"]
verbs: ["get", "list", "create", "delete"]
Kebijakan Jaringan
Batasi komunikasi pod ke pod:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: mysql-network-policy
spec:
podSelector:
matchLabels:
app: mysql
policyTypes:
- Ingress
ingress:
- from:
- podSelector:
matchLabels:
app: backend
ports:
- protocol: TCP
port: 3306
Optimisasi Kinerja
Tingkat Kinerja Penyimpanan
Pilih StorageClass yang sesuai berdasarkan beban kerja:
- IOPS Tinggi: Database dengan baca/tulis acak berat (gp3, io2)
- Throughput Tinggi: Agregasi log, analitik (st1, sc1)
- Seimbang: Aplikasi umum (gp3)
Penyebaran Pod
Gunakan anti-affinity pod untuk menyebarkan pod StatefulSet di zona ketersediaan:
spec:
template:
spec:
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchLabels:
app: mysql
topologyKey: topology.kubernetes.io/zone
Permintaan dan Batas Sumber Daya
Atur sumber daya yang sesuai untuk kinerja konsisten:
resources:
requests:
cpu: "2"
memory: "4Gi"
ephemeral-storage: "10Gi"
limits:
cpu: "4"
memory: "8Gi"
ephemeral-storage: "20Gi"
Pola Lanjutan
Aplikasi Berstatus dengan Init Containers
Gunakan init containers untuk inisialisasi database:
spec:
template:
spec:
initContainers:
- name: init-mysql
image: mysql:8.0
command:
- bash
- "-c"
- |
if [[ ! -d /var/lib/mysql/mysql ]]; then
mysqld --initialize-insecure --datadir=/var/lib/mysql
fi
volumeMounts:
- name: data
mountPath: /var/lib/mysql
Pod Multi-Container untuk Sidecars
Tambahkan sidecars cadangan atau agen pemantauan:
spec:
template:
spec:
containers:
- name: mysql
image: mysql:8.0
# ... konfigurasi mysql ...
- name: backup-sidecar
image: mysql-backup:latest
volumeMounts:
- name: data
mountPath: /var/lib/mysql
readOnly: true
ConfigMaps untuk Konfigurasi Dinamis
Pisahkan konfigurasi dari definisi StatefulSet:
apiVersion: v1
kind: ConfigMap
metadata:
name: mysql-config
data:
my.cnf: |
[mysqld]
max_connections=200
innodb_buffer_pool_size=2G
---
spec:
template:
spec:
containers:
- name: mysql
volumeMounts:
- name: config
mountPath: /etc/mysql/conf.d
volumes:
- name: config
configMap:
name: mysql-config
Tautan Berguna
- Dokumentasi Kubernetes StatefulSets
- Volume Persisten
- Kelas Penyimpanan
- Snapshot Volume
- Praktik Terbaik StatefulSet
- Driver CSI
- Solusi Cadangan Velero
- Penyimpanan Rook Ceph
- Kubernetes Cheatsheet
- Instalasi Kubernetes dengan Kubespray
- Perbandingan Distribusi Kubernetes untuk Klaster Homelab 3 Node
- Distribusi Kubernetes - overview dari kubeadm, k3s, MicroK8s, Minikube, Talos Linux dan RKE2
- Menguasai Helm Charts: Panduan Manajemen Paket Kubernetes