ProHoster > بلوق > إدارة > Kubernetes: ما سبب أهمية إعداد إدارة موارد النظام؟
Kubernetes: ما سبب أهمية إعداد إدارة موارد النظام؟
كقاعدة عامة، هناك دائمًا حاجة إلى توفير مجموعة مخصصة من الموارد للتطبيق لتشغيله بشكل صحيح ومستقر. ولكن ماذا لو كانت هناك عدة تطبيقات تعمل بنفس الطاقة؟ كيفية تزويد كل واحد منهم بالحد الأدنى من الموارد اللازمة؟ كيف يمكنك الحد من استهلاك الموارد؟ كيفية توزيع الحمل بشكل صحيح بين العقد؟ كيف يمكن التأكد من أن آلية القياس الأفقي تعمل في حالة زيادة حمل التطبيق؟
عليك أن تبدأ بالأنواع الرئيسية للموارد الموجودة في النظام - وهذا بالطبع هو وقت المعالج وذاكرة الوصول العشوائي. في بيانات k8s يتم قياس أنواع الموارد هذه بالوحدات التالية:
وحدة المعالجة المركزية - في النوى
ذاكرة الوصول العشوائي - بالبايت
علاوة على ذلك، يمكن تعيين نوعين من المتطلبات لكل مورد - طلبات и حدود. الطلبات - تصف الحد الأدنى من متطلبات الموارد المجانية للعقدة لتشغيل الحاوية (والجراب ككل)، بينما تحدد الحدود حدًا صارمًا للموارد المتاحة للحاوية.
من المهم أن نفهم أن البيان ليس من الضروري أن يحدد كلا النوعين بشكل صريح، ولكن السلوك سيكون كما يلي:
إذا تم تحديد حدود المورد بشكل صريح فقط، فإن طلبات هذا المورد تأخذ تلقائيًا قيمة مساوية للحدود (يمكنك التحقق من ذلك عن طريق استدعاء كيانات الوصف). أولئك. في الواقع، ستقتصر الحاوية على نفس مقدار الموارد التي تحتاجها للتشغيل.
إذا تم تحديد الطلبات بشكل صريح لمورد ما فقط، فلن يتم تعيين أي قيود عليا على هذا المورد - أي. الحاوية محدودة فقط بموارد العقدة نفسها.
من الممكن أيضًا تكوين إدارة الموارد ليس فقط على مستوى حاوية معينة، ولكن أيضًا على مستوى مساحة الاسم باستخدام الكيانات التالية:
نطاق الحد - يصف سياسة التقييد على مستوى الحاوية/الكبسولة في ns وهو ضروري لوصف الحدود الافتراضية على الحاوية/الكبسولة، وكذلك منع إنشاء حاويات/قرون من الواضح أنها دهنية (أو العكس)، والحد من عددها وتحديد الاختلاف المحتمل في القيم في الحدود والطلبات
حصص الموارد - وصف سياسة التقييد بشكل عام لجميع الحاويات في ns ويتم استخدامها، كقاعدة عامة، لتحديد الموارد بين البيئات (مفيدة عندما لا يتم ترسيم البيئات بشكل صارم على مستوى العقدة)
فيما يلي أمثلة على البيانات التي تحدد حدود الموارد:
أولئك. في هذه الحالة، لتشغيل حاوية باستخدام nginx، ستحتاج على الأقل إلى 1 غيغابايت من ذاكرة الوصول العشوائي المجانية و0.2 وحدة معالجة مركزية على العقدة، بينما يمكن للحاوية على الأكثر أن تستهلك 0.2 وحدة معالجة مركزية وكل ذاكرة الوصول العشوائي المتوفرة على العقدة.
أولئك. لا يمكن أن يتجاوز مجموع جميع حاويات الطلب في ns الافتراضية 300 متر لوحدة المعالجة المركزية و1 جيجا لـ OP، ومجموع كل الحد هو 700 متر لوحدة المعالجة المركزية و2 جيجا لـ OP.
أولئك. في مساحة الاسم الافتراضية لجميع الحاويات، سيتم تعيين الطلب على 100 متر لوحدة المعالجة المركزية و1 جيجا لـ OP، والحد هو 1 وحدة المعالجة المركزية و2 جيجا. في الوقت نفسه، يتم أيضًا تعيين حد للقيم المحتملة في الطلب/الحد لوحدة المعالجة المركزية (50m < x < 2) وذاكرة الوصول العشوائي (500M < x < 4G).
أولئك. لكل جراب في ns الافتراضي سيكون هناك حد 4 vCPU و1G.
الآن أود أن أخبركم بالمزايا التي يمكن أن يوفرها لنا وضع هذه القيود.
آلية موازنة التحميل بين العقد
كما تعلم، فإن مكون k8s هو المسؤول عن توزيع القرون بين العقد، مثل جدولةوالذي يعمل وفق خوارزمية محددة. تمر هذه الخوارزمية بمرحلتين عند اختيار العقدة المثالية للإطلاق:
تصفية
المدى
أولئك. وفقًا للسياسة الموصوفة، يتم تحديد العقد في البداية حيث يمكن تشغيل الكبسولة بناءً على المجموعة المسندات (بما في ذلك التحقق مما إذا كانت العقدة لديها موارد كافية لتشغيل الجراب - PodFitsResources)، ثم لكل من هذه العقد، وفقًا لـ أولويات يتم منح النقاط (بما في ذلك، كلما زادت الموارد المجانية التي تمتلكها العقدة، زاد عدد النقاط المخصصة لها - LeastResourceAllocation/LeastRequestedPriority/BalancedResourceAllocation) ويتم تشغيل الكبسولة على العقدة التي تحتوي على أكبر عدد من النقاط (إذا استوفت عدة عقد هذا الشرط في وقت واحد، إذن يتم اختيار واحد عشوائي).
في الوقت نفسه، عليك أن تفهم أن المجدول، عند تقييم الموارد المتاحة للعقدة، يسترشد بالبيانات المخزنة في إلخ - أي. لمقدار المورد المطلوب/الحد لكل جراب يعمل على هذه العقدة، ولكن ليس لاستهلاك المورد الفعلي. يمكن الحصول على هذه المعلومات من إخراج الأمر kubectl describe node $NODEعلى سبيل المثال:
نرى هنا جميع البودات تعمل على عقدة معينة، بالإضافة إلى الموارد التي تطلبها كل كبسولة. وإليك ما تبدو عليه سجلات المجدول عند تشغيل جراب cronjob-cron-events-1573793820-xt6q9 (ستظهر هذه المعلومات في سجل المجدول عند تعيين مستوى التسجيل العاشر في وسيطات أمر التشغيل -v=10 ):
سجل
I1115 07:57:21.637791 1 scheduling_queue.go:908] About to try and schedule pod nxs-stage/cronjob-cron-events-1573793820-xt6q9
I1115 07:57:21.637804 1 scheduler.go:453] Attempting to schedule pod: nxs-stage/cronjob-cron-events-1573793820-xt6q9
I1115 07:57:21.638285 1 predicates.go:829] Schedule Pod nxs-stage/cronjob-cron-events-1573793820-xt6q9 on Node nxs-k8s-s5 is allowed, Node is running only 16 out of 110 Pods.
I1115 07:57:21.638300 1 predicates.go:829] Schedule Pod nxs-stage/cronjob-cron-events-1573793820-xt6q9 on Node nxs-k8s-s6 is allowed, Node is running only 20 out of 110 Pods.
I1115 07:57:21.638322 1 predicates.go:829] Schedule Pod nxs-stage/cronjob-cron-events-1573793820-xt6q9 on Node nxs-k8s-s3 is allowed, Node is running only 20 out of 110 Pods.
I1115 07:57:21.638322 1 predicates.go:829] Schedule Pod nxs-stage/cronjob-cron-events-1573793820-xt6q9 on Node nxs-k8s-s4 is allowed, Node is running only 17 out of 110 Pods.
I1115 07:57:21.638334 1 predicates.go:829] Schedule Pod nxs-stage/cronjob-cron-events-1573793820-xt6q9 on Node nxs-k8s-s10 is allowed, Node is running only 16 out of 110 Pods.
I1115 07:57:21.638365 1 predicates.go:829] Schedule Pod nxs-stage/cronjob-cron-events-1573793820-xt6q9 on Node nxs-k8s-s12 is allowed, Node is running only 9 out of 110 Pods.
I1115 07:57:21.638334 1 predicates.go:829] Schedule Pod nxs-stage/cronjob-cron-events-1573793820-xt6q9 on Node nxs-k8s-s11 is allowed, Node is running only 11 out of 110 Pods.
I1115 07:57:21.638385 1 predicates.go:829] Schedule Pod nxs-stage/cronjob-cron-events-1573793820-xt6q9 on Node nxs-k8s-s1 is allowed, Node is running only 19 out of 110 Pods.
I1115 07:57:21.638402 1 predicates.go:829] Schedule Pod nxs-stage/cronjob-cron-events-1573793820-xt6q9 on Node nxs-k8s-s2 is allowed, Node is running only 21 out of 110 Pods.
I1115 07:57:21.638383 1 predicates.go:829] Schedule Pod nxs-stage/cronjob-cron-events-1573793820-xt6q9 on Node nxs-k8s-s9 is allowed, Node is running only 16 out of 110 Pods.
I1115 07:57:21.638335 1 predicates.go:829] Schedule Pod nxs-stage/cronjob-cron-events-1573793820-xt6q9 on Node nxs-k8s-s8 is allowed, Node is running only 18 out of 110 Pods.
I1115 07:57:21.638408 1 predicates.go:829] Schedule Pod nxs-stage/cronjob-cron-events-1573793820-xt6q9 on Node nxs-k8s-s13 is allowed, Node is running only 8 out of 110 Pods.
I1115 07:57:21.638478 1 predicates.go:1369] Schedule Pod nxs-stage/cronjob-cron-events-1573793820-xt6q9 on Node nxs-k8s-s10 is allowed, existing pods anti-affinity terms satisfied.
I1115 07:57:21.638505 1 predicates.go:1369] Schedule Pod nxs-stage/cronjob-cron-events-1573793820-xt6q9 on Node nxs-k8s-s8 is allowed, existing pods anti-affinity terms satisfied.
I1115 07:57:21.638577 1 predicates.go:1369] Schedule Pod nxs-stage/cronjob-cron-events-1573793820-xt6q9 on Node nxs-k8s-s9 is allowed, existing pods anti-affinity terms satisfied.
I1115 07:57:21.638583 1 predicates.go:829] Schedule Pod nxs-stage/cronjob-cron-events-1573793820-xt6q9 on Node nxs-k8s-s7 is allowed, Node is running only 25 out of 110 Pods.
I1115 07:57:21.638932 1 resource_allocation.go:78] cronjob-cron-events-1573793820-xt6q9 -> nxs-k8s-s10: BalancedResourceAllocation, capacity 39900 millicores 66620178432 memory bytes, total request 2343 millicores 9640186880 memory bytes, score 9
I1115 07:57:21.638946 1 resource_allocation.go:78] cronjob-cron-events-1573793820-xt6q9 -> nxs-k8s-s10: LeastResourceAllocation, capacity 39900 millicores 66620178432 memory bytes, total request 2343 millicores 9640186880 memory bytes, score 8
I1115 07:57:21.638961 1 resource_allocation.go:78] cronjob-cron-events-1573793820-xt6q9 -> nxs-k8s-s9: BalancedResourceAllocation, capacity 39900 millicores 66620170240 memory bytes, total request 4107 millicores 11307422720 memory bytes, score 9
I1115 07:57:21.638971 1 resource_allocation.go:78] cronjob-cron-events-1573793820-xt6q9 -> nxs-k8s-s8: BalancedResourceAllocation, capacity 39900 millicores 66620178432 memory bytes, total request 5847 millicores 24333637120 memory bytes, score 7
I1115 07:57:21.638975 1 resource_allocation.go:78] cronjob-cron-events-1573793820-xt6q9 -> nxs-k8s-s9: LeastResourceAllocation, capacity 39900 millicores 66620170240 memory bytes, total request 4107 millicores 11307422720 memory bytes, score 8
I1115 07:57:21.638990 1 resource_allocation.go:78] cronjob-cron-events-1573793820-xt6q9 -> nxs-k8s-s8: LeastResourceAllocation, capacity 39900 millicores 66620178432 memory bytes, total request 5847 millicores 24333637120 memory bytes, score 7
I1115 07:57:21.639022 1 generic_scheduler.go:726] cronjob-cron-events-1573793820-xt6q9_nxs-stage -> nxs-k8s-s10: TaintTolerationPriority, Score: (10)
I1115 07:57:21.639030 1 generic_scheduler.go:726] cronjob-cron-events-1573793820-xt6q9_nxs-stage -> nxs-k8s-s8: TaintTolerationPriority, Score: (10)
I1115 07:57:21.639034 1 generic_scheduler.go:726] cronjob-cron-events-1573793820-xt6q9_nxs-stage -> nxs-k8s-s9: TaintTolerationPriority, Score: (10)
I1115 07:57:21.639041 1 generic_scheduler.go:726] cronjob-cron-events-1573793820-xt6q9_nxs-stage -> nxs-k8s-s10: NodeAffinityPriority, Score: (0)
I1115 07:57:21.639053 1 generic_scheduler.go:726] cronjob-cron-events-1573793820-xt6q9_nxs-stage -> nxs-k8s-s8: NodeAffinityPriority, Score: (0)
I1115 07:57:21.639059 1 generic_scheduler.go:726] cronjob-cron-events-1573793820-xt6q9_nxs-stage -> nxs-k8s-s9: NodeAffinityPriority, Score: (0)
I1115 07:57:21.639061 1 interpod_affinity.go:237] cronjob-cron-events-1573793820-xt6q9 -> nxs-k8s-s10: InterPodAffinityPriority, Score: (0)
I1115 07:57:21.639063 1 selector_spreading.go:146] cronjob-cron-events-1573793820-xt6q9 -> nxs-k8s-s10: SelectorSpreadPriority, Score: (10)
I1115 07:57:21.639073 1 interpod_affinity.go:237] cronjob-cron-events-1573793820-xt6q9 -> nxs-k8s-s8: InterPodAffinityPriority, Score: (0)
I1115 07:57:21.639077 1 selector_spreading.go:146] cronjob-cron-events-1573793820-xt6q9 -> nxs-k8s-s8: SelectorSpreadPriority, Score: (10)
I1115 07:57:21.639085 1 interpod_affinity.go:237] cronjob-cron-events-1573793820-xt6q9 -> nxs-k8s-s9: InterPodAffinityPriority, Score: (0)
I1115 07:57:21.639088 1 selector_spreading.go:146] cronjob-cron-events-1573793820-xt6q9 -> nxs-k8s-s9: SelectorSpreadPriority, Score: (10)
I1115 07:57:21.639103 1 generic_scheduler.go:726] cronjob-cron-events-1573793820-xt6q9_nxs-stage -> nxs-k8s-s10: SelectorSpreadPriority, Score: (10)
I1115 07:57:21.639109 1 generic_scheduler.go:726] cronjob-cron-events-1573793820-xt6q9_nxs-stage -> nxs-k8s-s8: SelectorSpreadPriority, Score: (10)
I1115 07:57:21.639114 1 generic_scheduler.go:726] cronjob-cron-events-1573793820-xt6q9_nxs-stage -> nxs-k8s-s9: SelectorSpreadPriority, Score: (10)
I1115 07:57:21.639127 1 generic_scheduler.go:781] Host nxs-k8s-s10 => Score 100037
I1115 07:57:21.639150 1 generic_scheduler.go:781] Host nxs-k8s-s8 => Score 100034
I1115 07:57:21.639154 1 generic_scheduler.go:781] Host nxs-k8s-s9 => Score 100037
I1115 07:57:21.639267 1 scheduler_binder.go:269] AssumePodVolumes for pod "nxs-stage/cronjob-cron-events-1573793820-xt6q9", node "nxs-k8s-s10"
I1115 07:57:21.639286 1 scheduler_binder.go:279] AssumePodVolumes for pod "nxs-stage/cronjob-cron-events-1573793820-xt6q9", node "nxs-k8s-s10": all PVCs bound and nothing to do
I1115 07:57:21.639333 1 factory.go:733] Attempting to bind cronjob-cron-events-1573793820-xt6q9 to nxs-k8s-s10
هنا نرى أنه في البداية يقوم المجدول بتصفية وإنشاء قائمة من 3 عقد يمكن تشغيله عليها (nxs-k8s-s8، nxs-k8s-s9، nxs-k8s-s10). ثم يقوم بحساب الدرجات بناءً على عدة معلمات (بما في ذلك BalancedResourceAlllocation وLeastResourceAlllocation) لكل من هذه العقد من أجل تحديد العقدة الأكثر ملاءمة. في النهاية، تتم جدولة الكبسولة على العقدة التي تحتوي على أكبر عدد من النقاط (هنا عقدتان لهما نفس عدد النقاط 100037 في وقت واحد، لذلك يتم تحديد نقطة عشوائية - nxs-k8s-s10).
إنتاج: إذا كانت العقدة تقوم بتشغيل كبسولات لم يتم تعيين أي قيود عليها، فبالنسبة لـ k8s (من وجهة نظر استهلاك الموارد) سيكون هذا معادلاً كما لو لم تكن هناك مثل هذه البودات على هذه العقدة على الإطلاق. لذلك، إذا كان لديك، بشكل مشروط، جراب مع عملية شره (على سبيل المثال، wowza) ولم يتم تعيين أي قيود عليه، فقد ينشأ موقف عندما تأكل هذه الكبسولة بالفعل جميع موارد العقدة، ولكن بالنسبة لـ k8s، هذه العقدة تعتبر غير محملة وسيتم منحها نفس عدد النقاط عند التصنيف (على وجه التحديد في النقاط التي تقيم الموارد المتاحة) كعقدة لا تحتوي على وحدات عمل، مما قد يؤدي في النهاية إلى توزيع غير متساوٍ للحمل بين العقد.
إخلاء البود
كما تعلم، يتم تخصيص واحدة من ثلاث فئات لجودة الخدمة لكل حجرة:
مضمون - يتم تعيينه عندما يتم تحديد طلب وحدود لكل حاوية في الكبسولة للذاكرة ووحدة المعالجة المركزية، ويجب أن تتطابق هذه القيم
قابل للانفجار - تحتوي حاوية واحدة على الأقل في الكبسولة على طلب وحد، مع طلب < حد
أفضل جهد - عندما لا تكون هناك حاوية واحدة في الكبسولة محدودة الموارد
في الوقت نفسه، عندما تواجه العقدة نقصًا في الموارد (القرص والذاكرة)، يبدأ kubelet في ترتيب وطرد الكبسولات وفقًا لخوارزمية محددة تأخذ في الاعتبار أولوية الكبسولة وفئة جودة الخدمة الخاصة بها. على سبيل المثال، إذا كنا نتحدث عن ذاكرة الوصول العشوائي (RAM)، بناءً على فئة جودة الخدمة، يتم منح النقاط وفقًا للمبدأ التالي:
مضمون:-998
أفضل مجهود: 1000
قابل للانفجار: الحد الأدنى (الحد الأقصى (2، 1000 - (1000 * MemoryRequestBytes) / MachineMemoryCapacityBytes)، 999)
أولئك. بنفس الأولوية، سيقوم kubelet أولاً بطرد الكبسولات ذات فئة جودة الخدمة (QoS) ذات أفضل جهد من العقدة.
إنتاج: إذا كنت ترغب في تقليل احتمالية طرد الكبسولة المطلوبة من العقدة في حالة نقص الموارد عليها، فإلى جانب الأولوية، تحتاج أيضًا إلى الاهتمام بتعيين الطلب/الحد الخاص بها.
آلية للقياس التلقائي الأفقي لقرون التطبيق (HPA)
عندما تكون المهمة هي زيادة عدد القرون وتقليله تلقائيًا اعتمادًا على استخدام الموارد (النظام - وحدة المعالجة المركزية/ذاكرة الوصول العشوائي أو المستخدم - rps)، مثل كيان k8s مثل HPA (مقياس تلقائي للجراب الأفقي). الخوارزمية هي كما يلي:
يتم تحديد القراءات الحالية للمورد المرصود (currentMetricValue)
يتم تحديد القيم المطلوبة للمورد (desiredMetricValue)، والتي يتم تعيينها لموارد النظام باستخدام الطلب
يتم تحديد العدد الحالي للنسخ المتماثلة (currentReplicas)
تقوم الصيغة التالية بحساب العدد المطلوب من النسخ المتماثلة (النسخ المتماثلة المطلوبة)
المطلوبالنسخ المتماثلة = [النسخ المتماثلة الحالية * (القيمة الحالية للقياس / القيمة المطلوبة للقياس)]
في هذه الحالة، لن يحدث القياس عندما يكون المعامل (currentMetricValue / DesireMetricValue) قريبًا من 1 (في هذه الحالة، يمكننا ضبط الخطأ المسموح به بأنفسنا؛ بشكل افتراضي هو 0.1).
دعونا نلقي نظرة على كيفية عمل hpa باستخدام مثال تطبيق اختبار التطبيق (الموصوف بالنشر)، حيث يكون من الضروري تغيير عدد النسخ المتماثلة اعتمادًا على استهلاك وحدة المعالجة المركزية:
أولئك. نرى أن حجرة التطبيق تم تشغيلها مبدئيًا في حالتين، تحتوي كل واحدة منهما على حاويتين nginx وnginx-exporter، لكل منهما محدد طلبات لوحدة المعالجة المركزية.
أولئك. لقد أنشأنا HPA الذي سيراقب اختبار تطبيق النشر ويضبط عدد الكبسولات مع التطبيق بناءً على مؤشر وحدة المعالجة المركزية (نتوقع أن تستهلك الكبسولة 30% من وحدة المعالجة المركزية التي تطلبها)، مع وجود عدد النسخ المتماثلة نطاق 2-10.
الآن دعونا نلقي نظرة على آلية عمل HPA إذا قمنا بتحميل أحد المواقد:
# kubectl top pod
NAME CPU(cores) MEMORY(bytes)
app-test-78559f8f44-pgs58 101m 243Mi
app-test-78559f8f44-cj4jz 4m 240Mi
في المجموع لدينا ما يلي:
القيمة المطلوبة (desiredMetricValue) - وفقًا لإعدادات hpa، لدينا 30%
القيمة الحالية (currentMetricValue) - للحساب، يحسب مدير وحدة التحكم متوسط قيمة استهلاك الموارد بنسبة٪، أي. يقوم بما يلي بشكل مشروط:
يتلقى القيم المطلقة لمقاييس الكبسولة من الخادم المتري، أي. 101 م و 4 م
من أجل تحييد التأثير السلبي على النظام أثناء زيادة الأحمال، فإن تكوين HPA ليس كافيًا. على سبيل المثال، وفقًا للإعدادات الموجودة في مدير وحدة التحكم hpa، فإنه يقرر أن عدد النسخ المتماثلة يحتاج إلى زيادة بمقدار مرتين، لكن العقد لا تحتوي على موارد مجانية لتشغيل مثل هذا العدد من القرون (أي لا يمكن للعقدة توفير الموارد المطلوبة إلى حجرة الطلبات) وتتحول هذه القرون إلى الحالة المعلقة.
في هذه الحالة، إذا كان لدى الموفر IaaS/PaaS مطابق (على سبيل المثال، GKE/GCE، AKS، EKS، وما إلى ذلك)، فإن أداة مثل المقياس التلقائي للعقدة. يسمح لك بتعيين الحد الأقصى والحد الأدنى لعدد العقد في المجموعة وضبط العدد الحالي للعقد تلقائيًا (عن طريق استدعاء واجهة برمجة تطبيقات موفر السحابة لطلب/إزالة عقدة) عندما يكون هناك نقص في الموارد في المجموعة والقرون لا يمكن جدولتها (في حالة انتظار).
الخلاصة: لتتمكن من قياس العقد تلقائيًا، من الضروري تعيين الطلبات في حاويات الكبسولة حتى يتمكن k8s من تقييم الحمل على العقد بشكل صحيح وبالتالي الإبلاغ عن عدم وجود موارد في المجموعة لبدء تشغيل الكبسولة التالية.
اختتام
تجدر الإشارة إلى أن تعيين حدود موارد الحاوية ليس شرطًا لتشغيل التطبيق بنجاح، ولكن لا يزال من الأفضل القيام بذلك للأسباب التالية:
لتشغيل أكثر دقة للمجدول من حيث موازنة التحميل بين عقد k8s
لتقليل احتمالية حدوث حدث "إخلاء الكبسولة".
لكي يعمل القياس التلقائي الأفقي لقرون التطبيق (HPA).