10 أخطاء Kubernetes الشائعة

ملحوظة. ترجمة.: مؤلفو هذا المقال هم مهندسون من شركة تشيكية صغيرة، Pipetail. لقد تمكنوا من تجميع قائمة رائعة من المشاكل والمفاهيم الخاطئة [المبتذلة في بعض الأحيان، ولكنها لا تزال] ملحة للغاية فيما يتعلق بتشغيل مجموعات Kubernetes.

10 أخطاء Kubernetes الشائعة

على مدار سنوات استخدام Kubernetes، عملنا مع عدد كبير من المجموعات (سواء المُدارة أو غير المُدارة - على GCP وAWS وAzure). وبمرور الوقت، بدأنا نلاحظ أن بعض الأخطاء تتكرر باستمرار. ومع ذلك، ليس هناك عيب في هذا: لقد قمنا بمعظمها بأنفسنا!

تحتوي المقالة على الأخطاء الأكثر شيوعًا وتذكر أيضًا كيفية تصحيحها.

1. الموارد: الطلبات والحدود

يستحق هذا العنصر بالتأكيد الاهتمام الأقرب والمركز الأول في القائمة.

طلب وحدة المعالجة المركزية عادة إما غير محدد على الإطلاق أو له قيمة منخفضة جدًا (لوضع أكبر عدد ممكن من القرون على كل عقدة قدر الإمكان). وبالتالي، تصبح العقد مثقلة. خلال أوقات التحميل العالي، يتم استخدام قوة المعالجة الخاصة بالعقدة بالكامل ولا يتلقى حمل عمل معين سوى ما "طلبه" من قبل وحدة المعالجة المركزية اختناق. يؤدي هذا إلى زيادة زمن وصول التطبيق، والمهلات، وغيرها من العواقب غير السارة. (اقرأ المزيد عن هذا في ترجمتنا الأخيرة الأخرى: "حدود وحدة المعالجة المركزية والاختناق الشديد في Kubernetes"- تقريبًا. ترجمة.)

أفضل مجهود (لأقصى حد لا مُستَحسَن):

resources: {}

طلب وحدة المعالجة المركزية منخفض للغاية (للغاية لا مُستَحسَن):

   resources:
      Requests:
        cpu: "1m"

من ناحية أخرى، يمكن أن يؤدي وجود حد لوحدة المعالجة المركزية إلى تخطي غير معقول لدورات الساعة بواسطة الكبسولات، حتى لو لم يتم تحميل معالج العقدة بالكامل. ومرة أخرى، يمكن أن يؤدي هذا إلى زيادة التأخير. يستمر الجدل حول المعلمة حصة وحدة المعالجة المركزية CFS في نواة Linux واختناق وحدة المعالجة المركزية اعتمادًا على الحدود المحددة، بالإضافة إلى تعطيل حصة CFS... للأسف، يمكن أن تسبب حدود وحدة المعالجة المركزية مشكلات أكثر مما يمكنها حلها. يمكن العثور على مزيد من المعلومات حول هذا على الرابط أدناه.

الاختيار المفرط (الإفراط في الالتزام) مشاكل الذاكرة يمكن أن تؤدي إلى مشاكل أكبر. يتطلب الوصول إلى الحد الأقصى لوحدة المعالجة المركزية تخطي دورات الساعة، بينما يستلزم الوصول إلى الحد الأقصى للذاكرة قتل الكبسولة. هل سبق لك أن لاحظت OOMkill؟ نعم، هذا بالضبط ما نتحدث عنه.

هل تريد تقليل احتمالية حدوث ذلك؟ لا تفرط في تخصيص الذاكرة واستخدم ضمان جودة الخدمة (جودة الخدمة) عن طريق ضبط طلب الذاكرة على الحد الأقصى (كما في المثال أدناه). اقرأ المزيد عن هذا في عروض هينينج جاكوبس (المهندس الرئيسي في زالاندو).

قابل للانفجار (فرصة أكبر للحصول على OOMkilled):

   resources:
      requests:
        memory: "128Mi"
        cpu: "500m"
      limits:
        memory: "256Mi"
        cpu: 2

مضمون:

   resources:
      requests:
        memory: "128Mi"
        cpu: 2
      limits:
        memory: "128Mi"
        cpu: 2

ما الذي يمكن أن يساعد عند إعداد الموارد؟

استخدام خادم المقاييس يمكنك رؤية استهلاك موارد وحدة المعالجة المركزية الحالية واستخدام الذاكرة من خلال القرون (والحاويات الموجودة بداخلها). على الأرجح، أنت تستخدمه بالفعل. فقط قم بتشغيل الأوامر التالية:

kubectl top pods
kubectl top pods --containers
kubectl top nodes

ومع ذلك، فإنها تظهر الاستخدام الحالي فقط. يمكن أن يعطيك فكرة تقريبية عن حجمها، لكنك ستحتاج إليها في النهاية تاريخ التغيرات في المقاييس مع مرور الوقت (للإجابة على أسئلة مثل: "ما هو الحمل الأقصى لوحدة المعالجة المركزية؟"، "ما هو الحمل صباح أمس؟"، وما إلى ذلك). لهذا يمكنك استخدام محب العمل, DataDog وأدوات أخرى. إنهم ببساطة يحصلون على المقاييس من خادم المقاييس ويخزنونها، ويمكن للمستخدم الاستعلام عنها ورسمها وفقًا لذلك.

VerticalPodAutoscaler يسمح أتمتة هذه العملية. فهو يتتبع سجل استخدام وحدة المعالجة المركزية والذاكرة ويقوم بإعداد طلبات وحدود جديدة بناءً على هذه المعلومات.

إن استخدام قوة الحوسبة بكفاءة ليس بالمهمة السهلة. إنها مثل لعب تتريس طوال الوقت. إذا كنت تدفع الكثير مقابل قوة الحوسبة مع متوسط ​​استهلاك منخفض (على سبيل المثال ~ 10%)، فإننا نوصي بالنظر إلى المنتجات المستندة إلى AWS Fargate أو Virtual Kubelet. وهي مبنية على نموذج فواتير بدون خادم/الدفع لكل استخدام، والذي قد يتبين أنه أرخص في مثل هذه الظروف.

2. تحقيقات الحيوية والاستعداد

افتراضيًا، لا يتم تمكين عمليات التحقق من الحيوية والجاهزية في Kubernetes. وأحيانا ينسون تشغيلها..

ولكن كيف يمكنك بدء إعادة تشغيل الخدمة في حالة حدوث خطأ فادح؟ وكيف يعرف موازن التحميل أن الكبسولة جاهزة لقبول حركة المرور؟ أو أنه يمكن التعامل مع المزيد من حركة المرور؟

غالبًا ما يتم الخلط بين هذه الاختبارات مع بعضها البعض:

  • الحياة - فحص "قابلية البقاء"، والذي يقوم بإعادة تشغيل الكبسولة في حالة فشلها؛
  • استعداد — التحقق من الجاهزية، إذا فشل، فسيتم فصل البود عن خدمة Kubernetes (يمكن التحقق من ذلك باستخدام kubectl get endpoints) ولا تصل حركة المرور إليه إلا بعد إتمام الفحص التالي بنجاح.

كل من هذه الشيكات يتم تنفيذه خلال دورة الحياة الكاملة للكبسولة. انها مهمة جدا.

من المفاهيم الخاطئة الشائعة أن مجسات الاستعداد يتم تشغيلها فقط عند بدء التشغيل حتى يتمكن الموازن من معرفة أن الكبسولة جاهزة (Ready) ويمكن أن يبدأ في معالجة حركة المرور. ومع ذلك، هذا ليس سوى واحد من الخيارات لاستخدامها.

والشيء الآخر هو إمكانية اكتشاف أن حركة المرور على الكبسولة مفرطة و الزائد عليه (أو تقوم الحجرة بإجراء عمليات حسابية كثيفة الاستخدام للموارد). في هذه الحالة، يساعد التحقق من الاستعداد تقليل الحمل على الجراب و "تبريده".. يسمح الانتهاء بنجاح من فحص الاستعداد في المستقبل قم بزيادة الحمل على الكبسولة مرة أخرى. وفي هذه الحالة (إذا فشل اختبار الاستعداد)، فإن فشل اختبار الحيوية سيؤدي إلى نتائج عكسية للغاية. لماذا إعادة تشغيل جراب صحي ويعمل بجد؟

ولذلك، في بعض الحالات، لا يكون عدم إجراء عمليات فحص على الإطلاق أفضل من تمكينها باستخدام معلمات تم تكوينها بشكل غير صحيح. كما ذكر أعلاه، إذا التحقق من حيوية النسخ والتحقق من جاهزيتها، فأنت في ورطة كبيرة. الخيار المحتمل هو التكوين اختبار الاستعداد فقطو حيوية خطيرة اترك جانبا.

يجب ألا يفشل كلا النوعين من عمليات التحقق عندما تفشل التبعيات المشتركة، وإلا فسيؤدي ذلك إلى فشل متتالي (يشبه الانهيار الجليدي) لجميع القرون. بعبارة أخرى، لا تؤذي نفسك.

3. LoadBalancer لكل خدمة HTTP

على الأرجح، لديك خدمات HTTP في مجموعتك وترغب في إعادة توجيهها إلى العالم الخارجي.

إذا قمت بفتح الخدمة باسم type: LoadBalancer، ستوفر وحدة التحكم الخاصة به (اعتمادًا على مزود الخدمة) برنامج LoadBalancer خارجيًا وتتفاوض بشأنه (ليس بالضرورة أن يعمل على L7، بل حتى على L4)، وقد يؤثر هذا على التكلفة (عنوان IPv4 الثابت الخارجي، وقوة الحوسبة، والفوترة في كل ثانية ) بسبب الحاجة إلى إنشاء عدد كبير من هذه الموارد.

في هذه الحالة، يكون من المنطقي أكثر استخدام موازن تحميل خارجي واحد، وفتح الخدمات كـ type: NodePort. أو الأفضل من ذلك، قم بتوسيع شيء من هذا القبيل nginx-ingress-controller (أو ترافيك) ، والذي سيكون الوحيد منفذ العقدة نقطة النهاية المرتبطة بموازن التحميل الخارجي وستقوم بتوجيه حركة المرور في المجموعة باستخدام دخول-موارد Kubernetes.

يمكن للخدمات (الصغرى) الأخرى التي تتفاعل مع بعضها البعض أن "تتواصل" باستخدام خدمات مثل ClusterIP وآلية اكتشاف الخدمة المضمنة عبر DNS. لا تستخدم DNS/IP العام الخاص بهم، حيث قد يؤثر ذلك على زمن الوصول ويزيد من تكلفة الخدمات السحابية.

4. التحجيم التلقائي للمجموعة دون مراعاة ميزاتها

عند إضافة عقد إلى مجموعة وإزالتها منها، يجب ألا تعتمد على بعض المقاييس الأساسية مثل استخدام وحدة المعالجة المركزية (CPU) على تلك العقد. يجب أن يأخذ تخطيط الكبسولة في الاعتبار الكثير قيود، مثل تقارب pod/node، والعيوب والتسامح، وطلبات الموارد، وجودة الخدمة، وما إلى ذلك. قد يؤدي استخدام مقياس تلقائي خارجي لا يأخذ هذه الفروق الدقيقة في الاعتبار إلى حدوث مشكلات.

تخيل أنه يجب جدولة حجرة معينة، ولكن يتم طلب/تفكيك كل طاقة وحدة المعالجة المركزية المتاحة والكبسولة يعلق في الدولة Pending. يرى المقياس التلقائي الخارجي متوسط ​​حمل وحدة المعالجة المركزية الحالي (وليس الحمل المطلوب) ولا يبدأ التوسيع (تدرج) - لا يضيف عقدة أخرى. ونتيجة لذلك، لن تتم جدولة هذه الكبسولة.

في هذه الحالة، عكس القياس (تدرج في) — دائمًا ما يكون تنفيذ إزالة العقدة من المجموعة أكثر صعوبة. تخيل أن لديك حجرة ذات حالة (مع تخزين مستمر متصل). الكميات المستمرة تنتمي عادة إلى منطقة توافر محددة ولا تتكرر في المنطقة. وبالتالي، إذا قام أداة قياس تلقائي خارجية بحذف عقدة بهذه الحافظة، فلن يتمكن المجدول من جدولة هذه الحافظة على عقدة أخرى، حيث لا يمكن القيام بذلك إلا في منطقة التوفر حيث يوجد التخزين الدائم. سوف تكون عالقة الكبسولة في الدولة Pending.

تحظى بشعبية كبيرة في مجتمع Kubernetes الكتلة التلقائية. يتم تشغيله على مجموعة، ويدعم واجهات برمجة التطبيقات (APIs) من موفري الخدمات السحابية الرئيسيين، ويأخذ في الاعتبار جميع القيود ويمكن التوسع في الحالات المذكورة أعلاه. كما أنها قادرة على التوسع مع الحفاظ على جميع الحدود المحددة، وبالتالي توفير المال (الذي كان سيتم إنفاقه على السعة غير المستخدمة).

5. إهمال قدرات IAM/RBAC

احذر من استخدام مستخدمي IAM الذين لديهم أسرار ثابتة لـ الآلات والتطبيقات. تنظيم الوصول المؤقت باستخدام الأدوار وحسابات الخدمة (حسابات الخدمة).

غالبًا ما نواجه حقيقة أن مفاتيح الوصول (والأسرار) يتم تشفيرها بشكل ثابت في تكوين التطبيق، بالإضافة إلى إهمال تدوير الأسرار على الرغم من إمكانية الوصول إلى Cloud IAM. استخدم أدوار IAM وحسابات الخدمة بدلاً من المستخدمين حيثما كان ذلك مناسبًا.

10 أخطاء Kubernetes الشائعة

انسَ أمر kube2iam وانتقل مباشرة إلى أدوار IAM لحسابات الخدمة (كما هو موضح في مذكرة بنفس الاسم ستيبان فراني):

apiVersion: v1
kind: ServiceAccount
metadata:
  annotations:
    eks.amazonaws.com/role-arn: arn:aws:iam::123456789012:role/my-app-role
  name: my-serviceaccount
  namespace: default

تعليق توضيحي واحد. ليس بهذه الصعوبة، أليس كذلك؟

ولا تمنح أيضًا حسابات الخدمة وامتيازات ملفات تعريف المثيل admin и cluster-adminإذا لم يكونوا في حاجة إليها. يعد تنفيذ هذا الأمر أكثر صعوبة، خاصة في RBAC K8s، ولكنه بالتأكيد يستحق الجهد المبذول.

6. لا تعتمد على مضاد التقارب التلقائي للقرون

تخيل أن لديك ثلاث نسخ متماثلة لبعض عمليات النشر على عقدة. تقع العقدة، ومعها جميع النسخ المتماثلة. الوضع غير سارة، أليس كذلك؟ ولكن لماذا كانت جميع النسخ المتماثلة على نفس العقدة؟ أليس من المفترض أن يوفر Kubernetes توفرًا عاليًا (HA)؟!

لسوء الحظ، لا يتوافق برنامج جدولة Kubernetes بمبادرة منه مع قواعد الوجود المنفصل (مضاد للتقارب) للقرون. ويجب ذكرها صراحة:

// опущено для краткости
      labels:
        app: zk
// опущено для краткости
      affinity:
        podAntiAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            - labelSelector:
                matchExpressions:
                  - key: "app"
                    operator: In
                    values:
                    - zk
              topologyKey: "kubernetes.io/hostname"

هذا كل شئ. الآن سيتم جدولة البودات على عقد مختلفة (يتم التحقق من هذا الشرط فقط أثناء الجدولة، ولكن ليس أثناء تشغيلها - وبالتالي requiredDuringSchedulingIgnoredDuringExecution).

نحن هنا نتحدث عن podAntiAffinity على العقد المختلفة: topologyKey: "kubernetes.io/hostname"، - وليس حول مناطق توافر مختلفة. لتنفيذ HA كامل، سيتعين عليك التعمق في هذا الموضوع.

7. تجاهل PodDisruptionBudgets

تخيل أن لديك حمل إنتاج على مجموعة Kubernetes. بشكل دوري، يجب تحديث العقد والمجموعة نفسها (أو إيقاف تشغيلها). يعد PodDisruptionBudget (PDB) بمثابة اتفاقية ضمان الخدمة بين مسؤولي المجموعة والمستخدمين.

يسمح لك PDB بتجنب انقطاع الخدمة الناتج عن نقص العقد:

apiVersion: policy/v1beta1
kind: PodDisruptionBudget
metadata:
  name: zk-pdb
spec:
  minAvailable: 2
  selector:
    matchLabels:
      app: zookeeper

في هذا المثال، أنت، كمستخدم للمجموعة، تقول للمسؤولين: "مرحبًا، لدي خدمة Zookeeper، وبغض النظر عما تفعله، أود أن تكون هناك نسختان متماثلتان على الأقل من هذه الخدمة متاحة دائمًا."

يمكنك قراءة المزيد عن هذا هنا.

8. تعدد المستخدمين أو البيئات في مجموعة مشتركة

مساحات الأسماء Kubernetes (مساحات الأسماء) لا توفر عزل قوي.

من المفاهيم الخاطئة الشائعة أنه إذا قمت بنشر تحميل غير منتج في مساحة اسم واحدة وتحميل منتج في مساحة اسم أخرى، فسيتم ذلك لن يؤثر كل منهما على الآخر بأي شكل من الأشكال... ومع ذلك، يمكن تحقيق مستوى معين من العزلة باستخدام طلبات/قيود الموارد، وتحديد الحصص، وتعيين فئات الأولوية. يتم توفير بعض العزلة "المادية" في مستوى البيانات عن طريق أوجه التشابه، أو التسامح، أو الشوائب (أو منتقيات العقد)، ولكن هذا الفصل ليس جيدًا تمامًا. صعب ينفذ.

سيتعين على أولئك الذين يحتاجون إلى الجمع بين كلا النوعين من أعباء العمل في نفس المجموعة التعامل مع التعقيد. إذا لم تكن هناك حاجة لمثل هذه الحاجة، ويمكنك تحمل تكلفة الحصول عليها مجموعة أخرى (على سبيل المثال، في سحابة عامة)، فمن الأفضل القيام بذلك. سيؤدي ذلك إلى تحقيق مستوى أعلى من العزل.

9. ExternalTrafficPolicy: الكتلة

في كثير من الأحيان نرى أن كل حركة المرور داخل المجموعة تأتي من خلال خدمة مثل NodePort، والتي تم تعيين السياسة الافتراضية لها externalTrafficPolicy: Cluster... هذا يعني انه منفذ العقدة مفتوح على كل عقدة في المجموعة، ويمكنك استخدام أي منها للتفاعل مع الخدمة المطلوبة (مجموعة القرون).

10 أخطاء Kubernetes الشائعة

في الوقت نفسه، عادةً ما تكون البودات الحقيقية المرتبطة بخدمة NodePort المذكورة أعلاه متاحة فقط على جهاز معين مجموعة فرعية من هذه العقد. بمعنى آخر، إذا قمت بالاتصال بعقدة لا تحتوي على الكبسولة المطلوبة، فسوف تقوم بإعادة توجيه حركة المرور إلى عقدة أخرى، إضافة قفزة وزيادة زمن الاستجابة (إذا كانت العقد موجودة في مناطق توافر/مراكز بيانات مختلفة، فقد يكون زمن الاستجابة مرتفعًا جدًا؛ بالإضافة إلى ذلك، ستزيد تكاليف حركة الخروج).

من ناحية أخرى، إذا كانت خدمة Kubernetes معينة لديها مجموعة سياسات externalTrafficPolicy: Local، فسيتم فتح NodePort فقط على تلك العقد حيث يتم تشغيل القرون المطلوبة بالفعل. عند استخدام موازن تحميل خارجي يتحقق من الحالة (الفحص الصحي) نقاط النهاية (كيف تفعل ذلك أوس إلب)، هو سيرسل حركة المرور فقط إلى العقد الضرورية، والذي سيكون له تأثير مفيد على التأخير، واحتياجات الحوسبة، وفواتير الخروج (والحس السليم يملي نفس الشيء).

هناك احتمال كبير أنك تستخدم بالفعل شيئًا مثل ترافيك أو nginx-ingress-controller كنقطة نهاية NodePort (أو LoadBalancer، الذي يستخدم NodePort أيضًا) لتوجيه حركة مرور دخول HTTP، ويمكن أن يؤدي تعيين هذا الخيار إلى تقليل زمن الوصول لمثل هذه الطلبات بشكل كبير.

В هذا المنشور يمكنك معرفة المزيد حول ExternalTrafficPolicy ومزاياه وعيوبه.

10. عدم الارتباط بالتجمعات وعدم إساءة استخدام طائرة التحكم

في السابق، كان من المعتاد استدعاء الخوادم بأسماء العلم: أنتونوHAL9000 وColossus... اليوم تم استبدالهم بمعرفات تم إنشاؤها عشوائيًا. ومع ذلك، ظلت هذه العادة، والآن تذهب الأسماء الصحيحة إلى المجموعات.

قصة نموذجية (مبنية على أحداث حقيقية): بدأ كل شيء بإثبات المفهوم، لذلك كان للمجموعة اسم فخور تجريب… مرت سنوات وما زال يستخدم في الإنتاج، والجميع يخاف من لمسه.

لا يوجد شيء ممتع في تحول المجموعات إلى حيوانات أليفة، لذا ننصح بإزالتها بشكل دوري أثناء التدريب التعافي من الكوارث (هذا سيساعد هندسة الفوضى - تقريبا. ترجمة.). بالإضافة إلى ذلك، لن يضر العمل على طبقة التحكم (طائرة مراقبة). الخوف من لمسه ليس علامة جيدة. إلخ. ميت؟ يا رفاق، أنتم حقا في ورطة!

ومن ناحية أخرى، لا ينبغي أن تبالغ في التلاعب بها. مع الوقت قد تصبح طبقة التحكم بطيئة. على الأرجح، يرجع ذلك إلى إنشاء عدد كبير من الكائنات دون تدويرها (وهو موقف شائع عند استخدام Helm مع الإعدادات الافتراضية، ولهذا السبب لا يتم تحديث حالته في configmaps/secrets - ونتيجة لذلك، تتراكم آلاف الكائنات في طبقة التحكم) أو مع التحرير المستمر لكائنات kube-api (للقياس التلقائي، لـ CI/CD، للمراقبة، وسجلات الأحداث، ووحدات التحكم، وما إلى ذلك).

بالإضافة إلى ذلك، نوصي بالتحقق من اتفاقيات SLA/SLO مع موفر Kubernetes المُدار والاهتمام بالضمانات. يمكن للبائع أن يضمن توافر طبقة التحكم (أو مكوناته الفرعية)، ولكن ليس تأخير p99 للطلبات التي ترسلها إليه. وبعبارة أخرى، يمكنك الدخول kubectl get nodes، ولن تتلقى إجابة إلا بعد 10 دقائق، ولن يعد ذلك انتهاكًا لشروط اتفاقية الخدمة.

11. المكافأة: استخدام أحدث علامة

ولكن هذا بالفعل كلاسيكي. في الآونة الأخيرة، واجهنا هذه التقنية في كثير من الأحيان، لأن الكثيرين، بعد أن تعلموا من تجربة مريرة، توقفوا عن استخدام العلامة :latest وبدأت في تثبيت الإصدارات. مرحا!

ECR يحافظ على ثبات علامات الصور; ننصحك بالتعرف على هذه الميزة الرائعة.

ملخص

لا تتوقع أن كل شيء سيعمل بين عشية وضحاها: Kubernetes ليس حلا سحريا. تطبيق سيء سيبقى على هذا النحو حتى في Kubernetes (وربما سيزداد الأمر سوءًا). سيؤدي الإهمال إلى التعقيد المفرط والعمل البطيء والمجهد لطبقة التحكم. بالإضافة إلى ذلك، فإنك تخاطر بالبقاء بدون استراتيجية التعافي من الكوارث. لا تتوقع أن يوفر Kubernetes العزلة والتوافر العالي خارج الصندوق. اقض بعض الوقت في جعل تطبيقك أصليًا على السحابة حقًا.

يمكنك التعرف على التجارب غير الناجحة لمختلف الفرق فيها هذه المجموعة من القصص بواسطة هينينج جاكوبس.

للراغبين في الإضافة إلى قائمة الأخطاء الواردة في هذه المقالة يمكنهم التواصل معنا على تويتر (@ماريك بارتيك, @MstrsObserver).

PS من المترجم

اقرأ أيضًا على مدونتنا:

المصدر: www.habr.com

إضافة تعليق