StatefulSets وتخزين البيانات المستمرة في Kubernetes
نشر تطبيقات مُحَفَّظة مع التوسع المُرَتَّب والبيانات المستمرة
Kubernetes StatefulSets هي الحل المثالي لإدارة تطبيقات تتطلب هويات مستقرة، تخزين دائم، ونمط توزيع منظم—وهي ضرورية للقواعد البيانات، الأنظمة الموزعة، وطبقات التخزين المؤقت.
إذا كنت جديدًا في Kubernetes أو تقوم بإعداد مجموعة خوادم، ففكر في استكشاف توزيعات Kubernetes مثل k3s أو MicroK8s للاستخدام في التطوير، أو تثبيت Kubernetes باستخدام Kubespray لمستوى إنتاجي من المجموعات.
هذا الصورة الرائعة تم إنشاؤها بواسطة نموذج AI Flux 1 dev.
ما هي StatefulSets؟
StatefulSets هي كائن واجهة برمجة تطبيقات (API) في Kubernetes تم تصميمه خصيصًا لإدارة التطبيقات ذات الحالة. على عكس Deployments التي تتعامل مع جميع Pods كأنها قابلة للتبديل، فإن StatefulSets تحافظ على هوية فريدة لكل Pod مع ضمانات حول الترتيب والاختلاف.
الميزات الرئيسية:
- مُعرِّفات الشبكة المستقرة: يحصل كل Pod على اسم مضيف متوقع يظل ثابتًا عبر إعادة التشغيل
- تخزين دائم: طلبات PersistentVolumeClaims المخصصة التي ترافق Pods عبر إعادة التعيين
- توزيع منظم: يتم إنشاء Pods تسلسليًا (0، 1، 2…) وتُنهى في ترتيب معاكس
- تحديثات منظمة: تتم التحديثات التدريجية في ترتيب، مما يضمن استقرار التطبيق
StatefulSets ضرورية للتطبيقات مثل PostgreSQL، MySQL، MongoDB، Cassandra، Elasticsearch، Kafka، ZooKeeper، Redis، و etcd—أي مهمة حيث تهم هوية Pod والاحتفاظ بالبيانات.
فهم التخزين المستمر في Kubernetes
يوفر Kubernetes طبقة تجريد متقدمة للتخزين تفصل إدارة التخزين عن دورة حياة Pod:
مكونات التخزين
PersistentVolume (PV): قطعة تخزين في المجموعة تُنشَأ من قبل المشرف أو تُنشَأ ديناميكيًا عبر StorageClass. توجد PV بشكل مستقل عن Pods.
PersistentVolumeClaim (PVC): طلب للتخزين من قبل Pod. ترتبط PVCs بـ PVs المتاحة التي تتطابق مع متطلباتها (الحجم، وضع الوصول، فئة التخزين).
StorageClass: تحدد “فئات” مختلفة من التخزين مع مزودين مختلفين (AWS EBS، GCE PD، Azure Disk، NFS، إلخ) ومواصفات مثل التكرار، مستويات الأداء، وسياسات النسخ الاحتياطي.
وضعيات الوصول
- ReadWriteOnce (RWO): يتم تثبيت الحجم كقراءة/كتابة بواسطة عقدة واحدة
- ReadOnlyMany (ROX): يتم تثبيت الحجم كقراءة فقط بواسطة عدة عقد
- ReadWriteMany (RWX): يتم تثبيت الحجم كقراءة/كتابة بواسطة عدة عقد (يتطلب مكونات تخزين خاصة)
بنية تخزين StatefulSet
تستخدم StatefulSets volumeClaimTemplates لإنشاء PersistentVolumeClaims تلقائيًا لكل نسخة من Pod. هذا يختلف جذريًا عن Deployments:
كيف تعمل volumeClaimTemplates
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
عند إنشاء هذا StatefulSet:
- ينشئ Kubernetes Pod
mysql-0و PVCdata-mysql-0 - ثم ينشئ Pod
mysql-1و PVCdata-mysql-1 - أخيرًا ينشئ Pod
mysql-2و PVCdata-mysql-2
يحصل كل Pod على حجم تخزين مستقل بسعة 10 جيجابايت. إذا تم حذف mysql-1 أو إعادة تعيينه، يعيد Kubernetes إنشاءه ويربطه بنفس PVC data-mysql-1، مما يحافظ على جميع البيانات.
إنشاء خدمة بدون عنوان (Headless Service) لـ StatefulSets
تتطلب StatefulSets خدمة بدون عنوان (Headless Service) لتقديم هويات شبكة مستقرة:
apiVersion: v1
kind: Service
metadata:
name: mysql-service
spec:
clusterIP: None # هذا يجعلها خدمة بدون عنوان
selector:
app: mysql
ports:
- port: 3306
name: mysql
هذا ينشئ دخول DNS لكل Pod:
mysql-0.mysql-service.default.svc.cluster.localmysql-1.mysql-service.default.svc.cluster.localmysql-2.mysql-service.default.svc.cluster.local
يمكن للتطبيقات الاتصال مباشرة بنسخ Pod المحددة باستخدام هذه الأسماء المستقرة.
أنماط توزيع StatefulSet
للفرق التي تدير توزيعات Kubernetes المعقدة، توفر Helm Charts طريقة قوية لتعبئة ونشر StatefulSets مع التمكين، إدارة الإصدارات، وإدارة الاعتماديات. يبسط Helm إدارة إعدادات StatefulSet عبر بيئات مختلفة.
التوسع التسلسلي
عند التوسع من 3 إلى 5 نسخ:
kubectl scale statefulset mysql --replicas=5
ينشئ Kubernetes Pods تسلسليًا: mysql-3 → ينتظر الجاهزية → mysql-4
عند التوسع من 5 إلى 3:
kubectl scale statefulset mysql --replicas=3
ينهي Kubernetes في ترتيب معاكس: mysql-4 → ينتظر إنهاء → mysql-3
التحديثات التدريجية
تدعم StatefulSets استراتيجيتين لتحديثات:
OnDelete: تحديثات يدوية—Pods تُحدث فقط عند حذفها RollingUpdate: تحديثات تلقائية تسلسلية في ترتيب معاكس
spec:
updateStrategy:
type: RollingUpdate
rollingUpdate:
partition: 2 # تحديث Pods فقط ذات الترتيب >= 2
يتيح معلمة partition تنفيذ عمليات تجريبية—يمكنك تحديث Pods ذات الأرقام العالية أولاً ثم اختبارها قبل نشرها على جميع النسخ.
أفضل الممارسات في التخزين
التخصيص الديناميكي
استخدم دائمًا StorageClasses لتحديد الحجم التخزيني بشكل ديناميكي:
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: يسمح بتوسيع PVC دون إعادة إنشائه
reclaimPolicy: Retain يحتفظ ببيانات PV بعد حذف PVC، Delete يحذفها تلقائيًا
سياسات الاحتفاظ بـ PVC
يدعم Kubernetes 1.23+ persistentVolumeClaimRetentionPolicy:
spec:
persistentVolumeClaimRetentionPolicy:
whenDeleted: Retain # احتفظ بـ PVCs عند حذف StatefulSet
whenScaled: Delete # حذف PVCs عند التوسع
الخيارات:
- Retain: احتفظ بـ PVCs (السلوك الافتراضي، الأ安全)
- Delete: حذف PVCs تلقائيًا (مفيد للبيئات التطويرية)
استراتيجيات النسخ الاحتياطي
ال快照ات: استخدم موارد VolumeSnapshot لإنشاء نسخ احتياطية في وقت معين
apiVersion: snapshot.storage.k8s.io/v1
kind: VolumeSnapshot
metadata:
name: mysql-snapshot-20251113
spec:
volumeSnapshotClassName: csi-snapclass
source:
persistentVolumeClaimName: data-mysql-0
النسخ الاحتياطية على مستوى التطبيق: استخدم أدوات مثل mysqldump، pg_dump، أو Velero للنسخ الاحتياطي المخصص للقواعد البيانات
التكرار الموزع: أعد تكوين تكرار التطبيق (تكرار MySQL، تكرار البث في PostgreSQL) كخط دفاع أول
حالات استخدام واقعية
مجموعة قواعد بيانات (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
ذاكرة تخزين مؤقتة موزعة (Redis)
للمجموعات Redis، تحتاج إلى StatefulSet وتكوين دقيق:
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
قافلة الرسائل (Kafka)
تتطلب Kafka تخزينًا دائمًا للسجلات وهويات شبكة مستقرة لتنسيق المُنسق:
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
المراقبة والتحقيق في الأخطاء
للحصول على مرجع شامل لتعليمات Kubernetes المستخدمة في هذا القسم، راجع قائمة الأوامر المختصرة لـ Kubernetes.
فحص حالة StatefulSet
# عرض تفاصيل StatefulSet
kubectl get statefulset mysql
kubectl describe statefulset mysql
# فحص ترتيب إنشاء Pod وحالة
kubectl get pods -l app=mysql -w
# عرض حالة PVC
kubectl get pvc
kubectl describe pvc data-mysql-0
المشكلات الشائعة
Pod عالق في الانتظار: تحقق من حالة PVC وتوافر التخزين
kubectl describe pod mysql-0
kubectl get events --sort-by='.lastTimestamp'
التخزين ممتلئ: توسع PVC إذا سمح StorageClass بذلك
kubectl patch pvc data-mysql-0 -p '{"spec":{"resources":{"requests":{"storage":"20Gi"}}}}'
Pod لا يمكنه إنهاء التشغيل: تحقق من قفلات على مستوى التطبيق أو مشاكل في إلغاء تثبيت الحجم
kubectl delete pod mysql-0 --grace-period=0 --force
المقاييس التي يجب مراقبتها
- استخدام التخزين: مراقبة سعة PVC ونسبة الاستخدام
- أداء I/O: تتبع IOPS، معدل النقل، والتأخير
- إعادة تشغيل Pod: إعادة التشغيل المتكررة قد تشير إلى مشاكل في التخزين
- وقت ربط PVC: التأخير في الربط يشير إلى مشاكل في التخصيص
استراتيجيات الهجرة
عند الهجرة إلى StatefulSets، تأكد من أن مجموعة خوادم Kubernetes مُعدة بشكل صحيح. للاستخدام في المختبرات المنزلية أو المجموعات الصغيرة، راجع مقارنتنا الشاملة لـ توزيعات Kubernetes لاختيار المنصة المناسبة لاحتياجاتك.
من Deployment إلى StatefulSet
- إنشاء StatefulSet مع volumeClaimTemplates
- تقليل Deployment بشكل لطيف
- استعادة البيانات من النسخ الاحتياطية إلى Pods في StatefulSet
- تحديث مراجع DNS/Service
- حذف Deployment القديم و PVCs
النسخ الاحتياطية قبل الهجرة
# إنشاء نسخ احتياطية لـ PVCs الحالية
kubectl get pvc -o yaml > pvc-backup.yaml
# إنشاء نسخ احتياطية للحجم
kubectl apply -f volume-snapshot.yaml
اعتبارات الأمان
تشفير التخزين
تفعيل التشفير عند الراحة باستخدام معلمات 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
التحكم في الوصول
استخدم RBAC لتحديد من يمكنه إنشاء/تعديل StatefulSets و 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"]
سياسات الشبكة
تقييد الاتصال بين Pods:
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
تحسين الأداء
فئات الأداء في التخزين
اختر فئات StorageClass المناسبة بناءً على المهمة:
- IOPS مرتفع: قواعد بيانات ذات قراءة/كتابة عشوائية (gp3، io2)
- معدل نقل مرتفع: تجميع السجلات، التحليلات (st1، sc1)
- متوازن: تطبيقات عامة (gp3)
توزيع Pods
استخدم تجنب توزيع Pods لتفريق StatefulSet Pods عبر مناطق توفر:
spec:
template:
spec:
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchLabels:
app: mysql
topologyKey: topology.kubernetes.io/zone
طلبات وحدود الموارد
حدد موارد مناسبة لضمان الأداء المستقر:
resources:
requests:
cpu: "2"
memory: "4Gi"
ephemeral-storage: "10Gi"
limits:
cpu: "4"
memory: "8Gi"
ephemeral-storage: "20Gi"
الأنماط المتقدمة
تطبيق حالة مع حاويات بدائية
استخدم حاويات بدائية لتهيئة قاعدة البيانات:
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
Pods متعددة الحاويات لـ Sidecars
أضف Sidecars للنسخ الاحتياطية أو وكلاء المراقبة:
spec:
template:
spec:
containers:
- name: mysql
image: mysql:8.0
# ... إعدادات mysql ...
- name: backup-sidecar
image: mysql-backup:latest
volumeMounts:
- name: data
mountPath: /var/lib/mysql
readOnly: true
ConfigMaps للاعدادات الديناميكية
فصل الاعدادات عن تعريف 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
روابط مفيدة
- مستندات Kubernetes StatefulSets
- الوحدات المستمرة
- فئات التخزين
- 快照ات الحجم
- أفضل الممارسات لـ StatefulSet
- مُزودي CSI
- حلول النسخ الاحتياطية من Velero
- تخزين Rook Ceph
- قائمة الأوامر المختصرة لـ Kubernetes
- تثبيت Kubernetes باستخدام Kubespray
- مقارنة توزيعات Kubernetes لـ 3 عقد مختبرية منزلية
- توزيعات Kubernetes - ملخص سريع لـ kubeadm، k3s، MicroK8s، Minikube، Talos Linux و RKE2
- استيعاب Helm Charts: دليل إدارة حزم Kubernetes