قواعد البيانات في الإنتاج

قواعد البيانات على Kubernetes

18 دقيقة الدرس 9 من 30

قواعد البيانات على Kubernetes

تشغيل قواعد البيانات على Kubernetes من أكثر المواضيع جدلًا في هندسة المنصات. لسنوات كان الرأي السائد: "الأعباء عديمة الحالة فقط — احتفظ بقواعد بياناتك خارج الكتلة." كان هذا المنطق مقبولًا عام 2016 حين كانت بدائيات التخزين في Kubernetes غير ناضجة. في عام 2025، مع وجود عوامل ناضجة ومشغّلات CSI وتجارب إنتاجية موثّقة في شركات كـ Zalando وCloudflare وGitLab، تغيّرت المعادلة. لكن "يمكنك" لا تعني "يجب عليك"، والظروف التي يصحّ فيها كل جواب تختلف اختلافًا جوهريًّا.

لماذا تشغيل قواعد البيانات في Kubernetes أمر صعب

صُمّم Kubernetes حول مبدأ "الماشية" — حاويات عديمة الحالة يمكن قتلها وإعادة جدولتها وتوسيعها أفقيًّا كيفما شئت. قواعد البيانات "حيوانات أليفة": لها هوية وحالة قرصية وتوبولوجيا نسخ متماثل وعضوية في الكتلة يجب أن تنجو من عمليات إعادة التشغيل وأعطال العقد دون فقدان بيانات. عدة بدائيات تردم هذه الفجوة:

  • StatefulSet — يُعيّن هويات منتظمة وثابتة للحاويات (pg-0، pg-1، pg-2) تبقى حتى بعد إعادة تشغيل الحاوية. تحصل كل حاوية على PersistentVolumeClaim خاص بها.
  • PersistentVolumeClaim (PVC) — التخزين الدائم للحاوية، مدعوم بمشغّل CSI (EBS أو GCE PD أو Ceph أو Longhorn وغيرها). يبقى الـ PVC بعد زوال الحاوية.
  • Headless Service — خدمة بـ clusterIP: None تكشف اسم DNS لكل حاوية مباشرةً (pg-0.postgres-headless.default.svc.cluster.local)، مما يتيح للمشغّل توجيه الكتابات إلى الأساسية والقراءات إلى النسخ.
  • PodDisruptionBudget (PDB) — يمنع Kubernetes من إخلاء عدد كبير من حاويات قواعد البيانات في آنٍ واحد أثناء صيانة العقد.

حتى مع هذه البدائيات، لن تكتب مشغّل قاعدة بيانات جاهزًا للإنتاج من الصفر. منطق التنسيق — انتخاب القائد، وترقية النسخة، والتبديل دون فقدان بيانات، وإعادة تحميل الإعدادات عند تغيير المواصفات — معقّد بما يكفي لجعل المجتمع يتقارب حول المشغّلات (operators) كآلية تسليم قياسية.

المشغّلات: التجريد الصحيح

يُشفّر مشغّل Kubernetes كتاب تشغيل المشغّل البشري في صورة حلقة تحكم. يراقب موارد مخصصة (CRs) تُعرّفها — كائن Cluster لـ PostgreSQL مثلًا — ويُوفّق حالة الكتلة الفعلية نحو الحالة المطلوبة. المشغّلات الجيدة تتولى:

  • الإقلاع: تهيئة الأساسية، وبثّ النسخ منها، وتسجيلها في التوبولوجيا
  • الفشل التلقائي: رصد فشل الأساسية، وانتخاب قائد جديد، وتحديث نقاط نهاية الخدمة المخفية، كل ذلك دون فقدان بيانات
  • التبديل: تسليم الأساسية بأمان وبدون توقف للصيانة
  • النسخ الاحتياطي: نسخ قاعدية مجدوَلة إلى مخزن الكائنات (S3، GCS) وأرشفة WAL المستمرة
  • إدارة الإعدادات: ترجمة تغيير في المواصفة إلى إعادة تحميل أو تشغيل منسّقة ومتدرجة
  • ترقيات الإصدار الثانوية والرئيسية: ترقيات منسّقة على مستوى الكتلة بأكملها مع دعم التراجع

CloudNativePG — المعيار الذهبي لمشغّل PostgreSQL

CloudNativePG (CNPG) مشروع حضانة CNCF وأنضج مشغّل PostgreSQL إنتاجيًّا متاح. يشغّل PostgreSQL مباشرةً في الحاويات (بدون sidecar)، ويستخدم نسخ التدفق الأصلية لـ PostgreSQL، ويدمج أرشفة WAL مع مخزن الكائنات جاهزًا للاستخدام. إليك مانيفست كتلة بسيط لكن متوافق مع متطلبات الإنتاج:

# cnpg-cluster.yaml apiVersion: postgresql.cnpg.io/v1 kind: Cluster metadata: name: pg-prod namespace: databases spec: instances: 3 # 1 أساسية + 2 احتياطية متزامنة imageName: ghcr.io/cloudnative-pg/postgresql:16.3 postgresql: parameters: max_connections: "200" shared_buffers: "256MB" wal_level: logical # تفعيل النسخ المنطقي إذا لزم synchronous_commit: "on" bootstrap: initdb: database: app owner: app secret: name: pg-app-credentials # Secret مُنشأ مسبقًا باسم مستخدم وكلمة مرور storage: size: 100Gi storageClass: gp3-encrypted # EBS gp3 مشفّر مدعوم بـ CSI backup: retentionPolicy: "30d" barmanObjectStore: destinationPath: s3://my-cluster-backups/pg-prod s3Credentials: accessKeyId: name: s3-creds key: ACCESS_KEY_ID secretAccessKey: name: s3-creds key: SECRET_ACCESS_KEY wal: compression: gzip maxParallel: 2 monitoring: enablePodMonitor: true # ينشئ PodMonitor لاستخلاص Prometheus resources: requests: memory: "2Gi" cpu: "1" limits: memory: "4Gi" cpu: "2" --- # PodDisruptionBudget: منع إخلاء أكثر من حاوية قاعدة بيانات واحدة في آنٍ واحد apiVersion: policy/v1 kind: PodDisruptionBudget metadata: name: pg-prod-pdb namespace: databases spec: minAvailable: 2 selector: matchLabels: cnpg.io/cluster: pg-prod

طبّق الملف وسيُقلّع CNPG الكتلة، ويُهيّئ نسخ التدفق، ويبدأ أرشفة WAL، وينشئ PodMonitor لكي تستخلص Prometheus مقاييس postgres_exporter المدمجة تلقائيًّا. تحقق من حالة الكتلة بـ:

# تثبيت إضافة kubectl الخاصة بـ CNPG (مرة واحدة) kubectl krew install cnpg # ملخص صحة الكتلة kubectl cnpg status pg-prod -n databases # مثال على المخرجات: # Cluster Summary # Name: pg-prod # Namespace: databases # System ID: 7384… # PostgreSQL Image: ghcr.io/cloudnative-pg/postgresql:16.3 # Primary instance: pg-prod-1 # Status: Cluster in healthy state # Instances: 3 # Ready instances: 3 # # Instances # NAME CURRENT LSN REPLICATION LAG STATUS ROLE # pg-prod-1 0/1A3C5F8 — healthy Primary # pg-prod-2 0/1A3C5F8 0s healthy Standby (sync) # pg-prod-3 0/1A3C5F8 0s healthy Standby (sync) # تشغيل تبديل يدوي (تسليم الأساسية بدون توقف) kubectl cnpg promote pg-prod pg-prod-2 -n databases # بدء نسخة احتياطية فورية إلى مخزن الكائنات kubectl cnpg backup pg-prod -n databases
مشغّلات ناضجة أخرى تستحق المعرفة: Zalando Postgres Operator (يستخدم Patroni داخليًّا، مُختبَر على نطاق Zalando)، PGO (Crunchy Data) (دعم مؤسسي قوي وتجربة نسخ احتياطي واسترداد متقنة)، Percona Operator for MySQL/MongoDB (يغطي XtraDB Cluster وPercona Server for MongoDB)، وKubeDB (متعدد المحركات: PostgreSQL وMySQL وMongoDB وRedis وElasticsearch). للـ Redis، يُعدّ Redis Enterprise Operator وspotahome/redis-operator مفتوح المصدر الخيارَين الرئيسيَّين.

التخزين: القرار الفاصل

المشغّل بلا قيمة إذا كانت طبقة التخزين تحته غير موثوقة. اختيار التخزين له أثر أكبر على أداء قاعدة البيانات وسلامة البيانات من أي قرار آخر في Kubernetes.

Kubernetes database storage stack Application Pod CloudNativePG Operator StatefulSet Pods PVC per Pod CSI Driver (EBS / GCE PD / Ceph / Longhorn) Physical / Network Block Storage
مكدّس تخزين قواعد البيانات في Kubernetes: يدير المشغّل التوبولوجيا؛ ويربط مشغّل CSI الـ PVCs بالتخزين الكتلي الدائم أسفل الكتلة.

مبادئ التخزين الرئيسية لقواعد البيانات الإنتاجية على Kubernetes:

  • استخدم التخزين الكتلي، لا أنظمة الملفات المشتركة. NFS ومعظم تكوينات CephFS غير آمنة لأدلة بيانات PostgreSQL أو MySQL لأنها لا توفّر ضمانات fsync التي تعتمد عليها قواعد البيانات. استخدم وحدات التخزين الكتلية (EBS أو GCE PD أو Ceph RBD في وضع الكتلة).
  • فعّل تشفير الوحدات على مستوى StorageClass، لا على مستوى التطبيق. تضمن الإضافة التوضيحية encrypted: "true" أو مرجع مفتاح KMS في StorageClass تشفير كل PVC تلقائيًّا.
  • اطلب ضمان QoS للتخزين. على العقد التي تضمّ أعباء متعددة، يُعدّ ضجيج جهة I/O القرص من المصادر الرئيسية لارتفاع زمن الاستجابة. استخدم topologySpreadConstraints أو مجموعات عقد مخصصة (عبر node selectors و taints) لعزل حاويات قواعد البيانات.
  • لا تستخدم emptyDir لبيانات قاعدة البيانات أبدًا. emptyDir زائل — يُدمَّر حين تُخلَى الحاوية. هذا أكثر الأخطاء شيوعًا التي تؤدي إلى فقدان البيانات عند تشغيل قواعد البيانات في Kubernetes لأول مرة.
  • اضبط StorageClass بـ reclaimPolicy: Retain لجميع PVCs الخاصة بقواعد البيانات. سياسة Delete الافتراضية ستُدمّر وحدة تخزين البيانات بشكل دائم فور حذف أي PVC — سواء بقصد أم بخطأ بشري.
فخ حذف PVC: إذا شغّلت kubectl delete pvc pg-prod-1 على StorageClass بـ reclaimPolicy: Delete، فإن وحدة تخزين EBS الأساسية ستُدمَّر بشكل دائم في غضون ثوانٍ. استخدم دائمًا reclaimPolicy: Retain لوحدات التخزين الخاصة بقواعد البيانات. بعد التفكيك المقصود، احذف الـ PV ووحدة التخزين الأساسية يدويًّا فقط بعد التأكد من أن البيانات لم تعد مطلوبة أو أن نسخة احتياطية مُتحقَّقة منها موجودة.

متى لا تُشغّل قواعد البيانات على Kubernetes

حتى مع المشغّلات الناضجة، هناك حالات تُضيف فيها قاعدة البيانات داخل Kubernetes تعقيدًا دون فائدة متناسبة:

  • أنت تستخدم خدمة مُدارة ولا تعاني من مشكلة تشغيلية. RDS وCloud SQL وAurora تحلّ مشاكل حقيقية بتكلفة معقولة. الانتقال إلى كتلة CNPG لاكتساب تحكم لا تحتاجه هو تعقيد خالص.
  • فريقك لا يمتلك خبرة Kubernetes. تشغيل كتلة CNPG يتطلب فهم StatefulSets وPVCs وStorageClasses وسياسات الشبكة وCRDs الخاصة بالمشغّل. لا يجب أن تتخذ Kubernetes منصةً لقواعد البيانات كأول خطوة إذا لم يكن فريقك ملمًّا بها.
  • طبقة التخزين لديك غير جاهزة للإنتاج. إذا كانت الكتلة تستخدم أقراصًا محلية زائلة، أو تثبيت Longhorn سيء الضبط، أو NFS، فإن تشغيل قاعدة بيانات إنتاجية عليها سينتهي بكارثة. أصلح البنية التحتية قبل تشغيل الأعباء ذات الحالة.
  • متطلبات الامتثال أو إقامة البيانات تفرض العزل. بعض الأطر التنظيمية تشترط تشغيل قواعد البيانات على أجهزة مخصصة لمستأجر واحد. كتلة Kubernetes مشتركة تنتهك هذه الاشتراطات بغض النظر عن نضج المشغّل.
  • أعباء I/O مرتفعة للغاية. لن تبلغ كتلة تعمل على تخزين شبكي للأغراض العامة مستوى الإنتاجية التي يوفرها مضيف NVMe مادي. لـ OLTP مكثوف الكتابة على نطاق واسع، لا يزال المضيف المخصص أو خادم قواعد البيانات المادي هو الإجابة الصحيحة.
إطار القرار العملي: ابدأ بقواعد البيانات السحابية المُدارة. انتقل إلى مشغّل Kubernetes حين: (1) تشغّل Kubernetes لكل شيء آخر وكسب الاتساق التشغيلي حقيقي، (2) تحتاج ميزات لا تعرضها الخدمة المُدارة، أو (3) تجاوزت تكلفة الخدمة المُدارة تكلفة هندسة تشغيل كتلة CNPG. في شركات كـ Cloudflare وGitLab، نقطة التعادل حقيقية عند حجم كافٍ — لكن الشرط المسبق هو فريق منصة يمتلك طبقة المشغّل باحترافية مساوية لأي خدمة بنية تحتية أخرى.

ممارسات تشغيلية رئيسية

إذا قرّرت تشغيل قواعد البيانات على Kubernetes، فهذه الممارسات هي ما يُميّز النشر الإنتاجي عن التجريب:

  • هيّئ PDB دائمًا. بدون PodDisruptionBudget، يمكن لـ kubectl drain أثناء صيانة العقد إخلاء الأساسية وإحدى النسخ في آنٍ واحد، مما يتسبب في توقف مؤقت أو سلسلة من عمليات الفشل التلقائي.
  • استخدم قواعد anti-affinity لتوزيع حاويات قواعد البيانات عبر العقد المادية ومناطق التوافر. الأساسية وكلا النسختين على نفس العقدة يعني أن فشل عقدة واحدة يُسقط الكتلة بأكملها.
  • اختبر الفشل التلقائي بانتظام باستخدام أمر الترقية الخاص بالمشغّل. اعرف RTO من فشل الأساسية قبل أن تواجهه في الإنتاج.
  • تحقق من أرشفة WAL والاسترداد. تشغيل kubectl cnpg backup pg-prod لا يكفي — استرجع تلك النسخة الاحتياطية بانتظام في namespace منفصل أو كتلة تجريبية للتأكد من صحتها.
  • افصل namespace قواعد البيانات باستخدام NetworkPolicies تسمح فقط لـ namespaces التطبيقات بالوصول إلى منافذ قواعد البيانات. يجب ألّا تكون قواعد البيانات متاحة من الإنترنت المفتوح أو من أعباء غير ذات صلة في الكتلة ذاتها.