تقدم هذه المقالة بشكل أساسي المراحل في عملية الجدولة حيث تلعب استراتيجيات الجدولة الخاصة بـ Predicates و Priorities دورًا رئيسيًا.
Predicates
دعنا نلقي نظرة أولاً على Predicates. يمكن فهم دور Predicates في عملية الجدولة على أنه مرشح (Filter)، أي: يقوم “بتصفية” مجموعة من العقد التي تستوفي الشروط من جميع العقد في المجموعة الحالية وفقًا لسياسة الجدولة. هذه العقد هي جميع المضيفين المحتملين للـ Pod الذي ينتظر الجدولة. في Kubernetes، هناك أربع سياسات جدولة افتراضية.
النوع الأول يسمى GeneralPredicates.
كما يوحي الاسم، هذه المجموعة من قواعد التصفية مسؤولة عن سياسات الجدولة الأساسية. على سبيل المثال، PodFitsResources يحسب ما إذا كانت موارد CPU والذاكرة للمضيف كافية. بالطبع، كما ذكرت سابقًا، PodFitsResources يتحقق فقط من حقل requests للـ Pod. تجدر الإشارة إلى أن جدولة Kubernetes لا تحدد أنواع موارد محددة لموارد الأجهزة مثل GPU، بل تستخدم تنسيق Key-Value يسمى Extended Resource لوصفها. على سبيل المثال:
apiVersion: v1
kind: Pod
metadata:
name: extended-resource-demo
spec:
containers:
- name: extended-resource-demo-ctr
image: nginx
resources:
requests:
alpha.kubernetes.io/nvidia-gpu: "2"
limits:
alpha.kubernetes.io/nvidia-gpu: "2"
يمكن ملاحظة أن Pod الخاص بنا يعلن عن استخدام وحدتي GPU من نوع NVIDIA باستخدام تعريف alpha.kubernetes.io/nvidia-gpu=2. في PodFitsResources، لا يعرف المجدول في الواقع أن معنى حقل Key هذا هو GPU، بل يستخدم Value التالية مباشرة للحساب. بالطبع، في حقل Capacity للعقدة، تحتاج أيضًا إلى إضافة العدد الإجمالي لوحدات GPU على هذا المضيف، مثل: alpha.kubernetes.io/nvidia-gpu=4. سأقدم هذه العمليات بالتفصيل لاحقًا عند شرح Device Plugin. PodFitsHost يتحقق مما إذا كان اسم المضيف يطابق spec.nodeName للـ Pod. PodFitsHostPorts يتحقق مما إذا كانت منافذ المضيف (spec.nodePort) التي يطلبها Pod تتعارض مع المنافذ المستخدمة بالفعل. PodMatchNodeSelector يتحقق مما إذا كانت العقد المحددة بواسطة nodeSelector أو nodeAffinity للـ Pod تطابق العقدة قيد الفحص، وهكذا. يمكن ملاحظة أن هذه المجموعة من GeneralPredicates هي شرط التصفية الأساسي لـ Kubernetes لفحص ما إذا كان Pod يمكن أن يعمل على Node. لذلك، يتم استدعاء GeneralPredicates أيضًا مباشرة من قبل مكونات أخرى (مثل kubelet).
النوع الثاني هو قواعد التصفية المتعلقة بـ Volume.
هذه المجموعة من قواعد التصفية مسؤولة عن سياسة الجدولة المتعلقة بالـ Volume المستمر للحاوية. من بينها، NoDiskConflict يتحقق مما إذا كان هناك تعارض بين الـ Volumes المستمرة المعلنة من قبل عدة Pods. على سبيل المثال، Volumes من نوع AWS EBS لا يُسمح باستخدامها من قبل Pods في نفس الوقت. لذلك، عندما يتم تحميل Volume EBS باسم A بالفعل على عقدة معينة، لا يمكن جدولة Pod آخر يعلن أيضًا عن استخدام هذا Volume A إلى هذه العقدة. MaxPDVolumeCountPredicate يتحقق مما إذا كان نوع معين من الـ Volume المستمر على عقدة قد تجاوز عددًا معينًا. إذا كان الأمر كذلك، فلن يتمكن Pod الذي يعلن عن استخدام هذا النوع من الـ Volume المستمر من الجدولة إلى هذه العقدة. VolumeZonePredicate يتحقق مما إذا كانت علامة Zone (مجال التوفر العالي) للـ Volume المستمر تتطابق مع علامة Zone للعقدة قيد الفحص. بالإضافة إلى ذلك، هناك قاعدة تسمى VolumeBindingPredicate. وهي مسؤولة عن التحقق مما إذا كان حقل nodeAffinity الخاص بـ PV المقابل لـ Pod يطابق تسمية عقدة معينة. يجب على الـ Local Persistent Volume استخدام nodeAffinity لربطه بعقدة محددة. هذا يعني في الواقع أنه خلال مرحلة Predicates، يجب أن يكون Kubernetes قادرًا على الجدولة بناءً على خصائص Volume الخاصة بـ Pod. بالإضافة إلى ذلك، إذا لم يتم ربط PVC الخاص بـ Pod بعد بـ PV معين، فإن المجدول مسؤول أيضًا عن فحص جميع PVs التي سيتم ربطها. عندما يكون هناك PV متوفر وكان nodeAffinity لهذا PV متسقًا مع العقدة قيد الفحص، ستعيد هذه القاعدة “نجاح”. على سبيل المثال:
apiVersion: v1
kind: PersistentVolume
metadata:
name: example-local-pv
spec:
capacity:
storage: 500Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Retain
storageClassName: local-storage
local:
path: /mnt/disks/vol1
nodeAffinity:
required:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/hostname
operator: In
values:
- my-node
يمكن ملاحظة أن الدليل المستمر المقابل لهذا PV سيظهر فقط على المضيف المسمى my-node. لذلك، يجب جدولة أي Pod يستخدم هذا PV عبر PVC إلى my-node ليعمل بشكل صحيح. VolumeBindingPredicate هو بالضبط المكان الذي يتخذ فيه المجدول هذا القرار.
النوع الثالث هو قواعد التصفية المتعلقة بالمضيف.
تفحص هذه المجموعة من القواعد بشكل أساسي ما إذا كان Pod المراد جدولته يستوفي شروطًا معينة للعقدة نفسها. على سبيل المثال، PodToleratesNodeTaints يتحقق من آلية “الtaint” للعقدة التي نستخدمها غالبًا من قبل. فقط عندما يتطابق حقل Toleration للـ Pod مع حقل Taint للعقدة يمكن جدولة هذا Pod إلى العقدة. NodeMemoryPressurePredicate يتحقق مما إذا كانت ذاكرة العقدة الحالية غير كافية. إذا كان الأمر كذلك، لا يمكن جدولة Pod المنتظر إلى هذه العقدة.
النوع الرابع هو قواعد التصفية المتعلقة بـ Pod.
تتداخل هذه المجموعة من القواعد مع معظم GeneralPredicates. ما هو مميز هو PodAffinityPredicate. دور هذه القاعدة هو فحص علاقات التقارب والتباعد بين Pod المراد جدولته و Pods الموجودة على العقدة. على سبيل المثال:
apiVersion: v1
kind: Pod
metadata:
name: with-pod-antiaffinity
spec:
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchExpressions:
- key: security
operator: In
values:
- S2
topologyKey: kubernetes.io/hostname
containers:
- name: with-pod-affinity
image: docker.io/ocpqe/hello-pod
في هذا المثال، تحدد قاعدة podAntiAffinity أن هذا Pod لا يريد التواجد على نفس العقدة مع أي Pod يحمل تسمية security=S2. تجدر الإشارة إلى أن PodAffinityPredicate له نطاق، مثل القاعدة أعلاه، فهي صالحة فقط للعقد التي تحمل تسمية Key kubernetes.io/hostname. هذا هو دور الكلمة المفتاحية topologyKey.
تشكل هذه الأنواع الأربعة من Predicates الاستراتيجية الأساسية للمجدول لتحديد ما إذا كانت العقدة يمكنها تشغيل Pod المراد جدولته. عند التنفيذ، عندما يتم جدولة Pod، سيقوم جدولة Kubernetes ببدء 16 Goroutine بشكل متزامن لحساب Predicates لجميع العقد في المجموعة، وأخيرًا إرجاع قائمة المضيفين التي يمكنها تشغيل هذا Pod. تجدر الإشارة إلى أنه عند تنفيذ Predicates لكل عقدة، سيقوم المجدول بالفحص بترتيب ثابت. يتم تحديد هذا الترتيب وفقًا لمعنى Predicates نفسها. على سبيل المثال، سيتم فحص Predicates المتعلقة بالمضيف في وقت مبكر. وإلا، فإن حساب PodAffinityPredicate على مضيف يعاني من نقص حاد في الموارد لا معنى له.
Priorities
بعد “التصفية” للعقد في مرحلة Predicates، فإن عمل مرحلة Priorities هو تسجيل نقاط لهذه العقد. نطاق التسجيل هنا هو 0-10 نقاط، والعقدة ذات النقاط الأعلى هي أفضل عقدة سيتم ربط Pod بها أخيرًا. قاعدة التسجيل الأكثر استخدامًا في Priorities هي LeastRequestedPriority. هذا الخوارزمية تختار في الواقع المضيف الذي يحتوي على معظم الموارد الخاملة (CPU و Memory). بالإضافة إلى ذلك، هناك ثلاث أولويات أخرى: NodeAffinityPriority و TaintTolerationPriority و InterPodAffinityPriority. كما تشير الأسماء، فهي متشابهة في المعنى وطريقة الحساب مع Predicates الثلاثة السابقة: PodMatchNodeSelector و PodToleratesNodeTaints و PodAffinityPredicate. ومع ذلك، كـ Priority، كلما زادت الحقول التي تستوفيها العقدة للقواعد المذكورة أعلاه، زادت نتيجتها. في Priorities الافتراضية، هناك أيضًا استراتيجية تسمى ImageLocalityPriority. وهي قاعدة جدولة جديدة تم تفعيلها في Kubernetes v1.12، وهي: إذا كانت الصورة التي يحتاجها Pod المراد جدولته كبيرة وموجودة بالفعل على بعض العقد، فإن هذه العقد ستحصل على نقاط أعلى. بالطبع، لتجنب تسبب الخوارزمية في تراكم الجدولة، سيقوم المجدول أيضًا بالتحسين وفقًا لتوزيع الصورة عند حساب النقاط، أي: إذا كان عدد العقد التي تتوزع عليها الصورة الكبيرة قليلًا جدًا، فسيتم تقليل وزن هذه العقد، وبالتالي “تعويض” خطر التسبب في تراكم الجدولة.
باختصار، هذا هو مبدأ العمل الرئيسي لقواعد الجدولة الافتراضية في جدولة Kubernetes. في عملية التنفيذ الفعلية، تم تخزين معلومات المجموعة و Pods في المجدول مؤقتًا، لذا فإن عملية تنفيذ هذه الخوارزميات سريعة نسبيًا. بالإضافة إلى ذلك، بالنسبة لخوارزميات الجدولة الأكثر تعقيدًا، مثل PodAffinityPredicate، فهي لا تهتم فقط بـ Pod المراد جدولته والعقدة قيد الفحص عند الحساب، بل تحتاج أيضًا إلى الاهتمام بمعلومات المجموعة بأكملها، مثل المرور عبر جميع العقد وقراءة Labels الخاصة بها. في هذه المرحلة، سيقوم جدولة Kubernetes أولاً بحساب معلومات المجموعة اللازمة للخوارزمية مسبقًا قبل تنفيذ خوارزمية الجدولة لكل Pod يتم جدولته، ثم تخزينها مؤقتًا. بهذه الطريقة، عند تنفيذ الخوارزمية فعليًا، يحتاج المجدول فقط إلى قراءة المعلومات المخزنة مؤقتًا للحساب، وبالتالي تجنب الحاجة إلى استرداد وحساب معلومات المجموعة بأكملها بشكل متكرر لكل عقدة عند حساب Predicates.
الخلاصة
باختصار، ناقشت هذه المقالة خوارزميات الجدولة الرئيسية داخل جدولة Kubernetes الافتراضية. من المهم ملاحظة أنه بالإضافة إلى القواعد التي تم تناولها في هذه المقالة، هناك في الواقع بعض الاستراتيجيات داخل جدولة Kubernetes غير مفعلة افتراضيًا. يمكنك تحديد ملف تكوين لـ kube-scheduler أو إنشاء ConfigMap لتكوين القواعد التي تريد تفعيلها أو تعطيلها. علاوة على ذلك، يمكنك التحكم في سلوك المجدول عن طريق تعيين أوزان لـ Priorities. بهذا نختتم شرح آليات الجدولة الافتراضية في جدولة Kubernetes. تجدر الإشارة إلى أنه على الرغم من أن المجدول يعمل بسرعة بسبب تخزين معلومات المجموعة و Pods مؤقتًا، إلا أنه بالنسبة للخوارزميات الأكثر تعقيدًا، يجب على المجدول أن يأخذ في الاعتبار حالة المجموعة بأكملها، وليس فقط Pod والعقدة المعنية. ويشمل ذلك الحسابات الأولية والتخزين المؤقت لمعلومات المجموعة الضرورية قبل التنفيذ الفعلي لخوارزمية الجدولة، مما يضمن الكفاءة والدقة في عملية الجدولة.
Novita AI هي المنصة السحابية الشاملة التي تمكن طموحاتك في مجال الذكاء الاصطناعي. مع واجهات برمجة تطبيقات متكاملة بسلاسة، وحوسبة بدون خادم، وتسريع GPU، نقدم الأدوات الفعالة من حيث التكلفة التي تحتاجها لبناء وتوسيع نطاق أعمالك القائمة على الذكاء الاصطناعي بسرعة. تخلص من متاعب البنية التحتية وابدأ مجانًا - Novita AI تجعل أحلامك في الذكاء الاصطناعي حقيقة واقعة.
قراءة موصى بها:
