يذهب؟ سحق! تعرف على مشغل الصدفة (مراجعة وتقرير فيديو من KubeCon EU'2020)

هذا العام، كان مؤتمر Kubernetes الأوروبي الرئيسي - KubeCon + CloudNativeCon Europe 2020 - افتراضيًا. ومع ذلك، فإن مثل هذا التغيير في الشكل لم يمنعنا من تقديم تقريرنا الذي خططنا له منذ فترة طويلة "انطلق؟" سحق! تعرف على مشغل Shell" المخصص لمشروعنا مفتوح المصدر مشغل القشرة.

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

يذهب؟ سحق! تعرف على مشغل الصدفة (مراجعة وتقرير فيديو من KubeCon EU'2020)

مقدمة فيديو مع التقرير (حوالي 23 دقيقة باللغة الإنجليزية، وهي أكثر إفادة بشكل ملحوظ من المقالة) والمقتطف الرئيسي منها في شكل نص. يذهب!

في Flant نقوم باستمرار بتحسين كل شيء وأتمتته. اليوم سنتحدث عن مفهوم آخر مثير. يقابل: البرمجة النصية لشل السحابية الأصلية!

ومع ذلك، لنبدأ بالسياق الذي يحدث فيه كل هذا: Kubernetes.

واجهة برمجة تطبيقات Kubernetes ووحدات التحكم

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

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

وبالتالي، يعمل Kubernetes كنوع من خادم الملفات (لبيانات YAML) بثلاث طرق أساسية (نعم، في الواقع هناك طرق أخرى، لكننا سنحذفها في الوقت الحالي).

يذهب؟ سحق! تعرف على مشغل الصدفة (مراجعة وتقرير فيديو من KubeCon EU'2020)

المشكلة هي أن الخادم يمكنه تخزين المعلومات فقط. لجعلها تعمل تحتاج مراقب - المفهوم الثاني الأكثر أهمية والأساسية في عالم Kubernetes.

هناك نوعان رئيسيان من وحدات التحكم. الأول يأخذ المعلومات من Kubernetes، ويعالجها وفقًا للمنطق المتداخل، ويعيدها إلى K8s. يأخذ النوع الثاني المعلومات من Kubernetes، ولكن على عكس النوع الأول، فإنه يغير حالة بعض الموارد الخارجية.

دعونا نلقي نظرة فاحصة على عملية إنشاء النشر في Kubernetes:

  • وحدة تحكم النشر (مضمنة في kube-controller-manager) يتلقى معلومات حول النشر ويقوم بإنشاء مجموعة النسخ المتماثلة.
  • تقوم ReplicaSet بإنشاء نسختين متماثلتين (حافظتين) بناءً على هذه المعلومات، ولكن لم تتم جدولة هذه الكبسولات بعد.
  • يقوم المجدول بجدولة القرون وإضافة معلومات العقدة إلى YAMLs الخاصة بهم.
  • تقوم Kubelets بإجراء تغييرات على مورد خارجي (على سبيل المثال Docker).

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

يذهب؟ سحق! تعرف على مشغل الصدفة (مراجعة وتقرير فيديو من KubeCon EU'2020)

مشغل شل

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

يذهب؟ سحق! تعرف على مشغل الصدفة (مراجعة وتقرير فيديو من KubeCon EU'2020)

مثال بسيط: نسخ الأسرار

دعونا نلقي نظرة على مثال بسيط.

لنفترض أن لدينا مجموعة Kubernetes. لديها مساحة الاسم default مع بعض السر mysecret. بالإضافة إلى ذلك، هناك مساحات أسماء أخرى في الكتلة. البعض منهم لديه تسمية محددة المرفقة بهم. هدفنا هو نسخ Secret إلى مساحات الأسماء باستخدام التصنيف.

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

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

كيف يعمل مشغل القشرة

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

يذهب؟ سحق! تعرف على مشغل الصدفة (مراجعة وتقرير فيديو من KubeCon EU'2020)

يشترك مشغل Shell في أحداث Kubernetes ويقوم بتشغيل هذه الخطافات استجابة لتلك الأحداث التي نحتاجها.

يذهب؟ سحق! تعرف على مشغل الصدفة (مراجعة وتقرير فيديو من KubeCon EU'2020)

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

صنع عامل في باش

والآن نحن جاهزون للتنفيذ. للقيام بذلك، نحن بحاجة إلى كتابة وظيفتين (بالمناسبة، نوصي مكتبة shell_lib، مما يبسط إلى حد كبير خطافات الكتابة في Bash):

  • الأول ضروري لمرحلة التكوين - فهو يعرض سياق الربط؛
  • والثاني يحتوي على المنطق الرئيسي للخطاف.

#!/bin/bash

source /shell_lib.sh

function __config__() {
  cat << EOF
    configVersion: v1
    # BINDING CONFIGURATION
EOF
}

function __main__() {
  # THE LOGIC
}

hook::run "$@"

الخطوة التالية هي تحديد الأشياء التي نحتاجها. في حالتنا، نحن بحاجة إلى تتبع:

  • سر المصدر للتغييرات؛
  • جميع مساحات الأسماء الموجودة في المجموعة، حتى تتمكن من معرفة أي منها يحمل تسمية مرفقة بها؛
  • أسرار الهدف للتأكد من أنها كلها متزامنة مع سر المصدر.

اشترك في المصدر السري

التكوين الملزم لذلك بسيط للغاية. نشير إلى أننا مهتمون بالسر بالاسم mysecret في مساحة الاسم default:

يذهب؟ سحق! تعرف على مشغل الصدفة (مراجعة وتقرير فيديو من KubeCon EU'2020)

function __config__() {
  cat << EOF
    configVersion: v1
    kubernetes:
    - name: src_secret
      apiVersion: v1
      kind: Secret
      nameSelector:
        matchNames:
        - mysecret
      namespace:
        nameSelector:
          matchNames: ["default"]
      group: main
EOF

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

يذهب؟ سحق! تعرف على مشغل الصدفة (مراجعة وتقرير فيديو من KubeCon EU'2020)

كما ترون، فإنه يحتوي على الاسم والكائن بأكمله.

تتبع مساحات الأسماء

أنت الآن بحاجة إلى الاشتراك في مساحات الأسماء. للقيام بذلك، نحدد تكوين الربط التالي:

- name: namespaces
  group: main
  apiVersion: v1
  kind: Namespace
  jqFilter: |
    {
      namespace: .metadata.name,
      hasLabel: (
       .metadata.labels // {} |  
         contains({"secret": "yes"})
      )
    }
  group: main
  keepFullObjectsInMemory: false

كما ترون، ظهر حقل جديد في التكوين بالاسم jqFilter. كما يوحي اسمها، jqFilter يقوم بتصفية كافة المعلومات غير الضرورية وإنشاء كائن JSON جديد يحتوي على الحقول التي تهمنا. سوف يتلقى الخطاف ذو التكوين المماثل سياق الربط التالي:

يذهب؟ سحق! تعرف على مشغل الصدفة (مراجعة وتقرير فيديو من KubeCon EU'2020)

أنه يحتوي على مجموعة filterResults لكل مساحة اسم في الكتلة. متغير منطقي hasLabel يشير إلى ما إذا كانت التسمية مرفقة بمساحة اسم معينة. محدد keepFullObjectsInMemory: false يشير إلى أنه ليست هناك حاجة للاحتفاظ بالأشياء الكاملة في الذاكرة.

تتبع أسرار الهدف

نحن نشترك في جميع الأسرار التي تحتوي على تعليق توضيحي محدد managed-secret: "yes" (هؤلاء هم هدفنا dst_secrets):

- name: dst_secrets
  apiVersion: v1
  kind: Secret
  labelSelector:
    matchLabels:
      managed-secret: "yes"
  jqFilter: |
    {
      "namespace":
        .metadata.namespace,
      "resourceVersion":
        .metadata.annotations.resourceVersion
    }
  group: main
  keepFullObjectsInMemory: false

في هذه الحالة، jqFilter يقوم بتصفية جميع المعلومات باستثناء مساحة الاسم والمعلمة resourceVersion. تم تمرير المعلمة الأخيرة إلى التعليق التوضيحي عند إنشاء السر: فهي تسمح لك بمقارنة إصدارات الأسرار وإبقائها محدثة.

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

يذهب؟ سحق! تعرف على مشغل الصدفة (مراجعة وتقرير فيديو من KubeCon EU'2020)

وبناء على كل هذه المعلومات، يمكن تطوير خوارزمية أساسية. يتكرر على جميع مساحات الأسماء و:

  • إذا hasLabel المسائل true لمساحة الاسم الحالية:
    • يقارن السر العالمي بالسر المحلي:
      • إذا كانا نفس الشيء، فإنه لا يفعل شيئا؛
      • إذا اختلفوا - ينفذ kubectl replace أو create;
  • إذا hasLabel المسائل false لمساحة الاسم الحالية:
    • يتأكد من أن Secret ليس في مساحة الاسم المحددة:
      • إذا كان السر المحلي موجودًا، فاحذفه باستخدام kubectl delete;
      • إذا لم يتم الكشف عن السر المحلي، فإنه لا يفعل شيئا.

يذهب؟ سحق! تعرف على مشغل الصدفة (مراجعة وتقرير فيديو من KubeCon EU'2020)

تنفيذ الخوارزمية في باش يمكنك التنزيل في موقعنا المستودعات مع الأمثلة.

هذه هي الطريقة التي تمكنا من إنشاء وحدة تحكم Kubernetes بسيطة باستخدام 35 سطرًا من تكوين YAML ونفس المقدار تقريبًا من كود Bash! ومهمة مشغل الصدفة هي ربطهم ببعضهم البعض.

ومع ذلك، فإن نسخ الأسرار ليس المجال الوحيد لتطبيق الأداة المساعدة. فيما يلي بعض الأمثلة الإضافية لإظهار ما هو قادر عليه.

المثال 1: إجراء تغييرات على ConfigMap

دعونا نلقي نظرة على عملية نشر تتكون من ثلاث حجرات. تستخدم Pods ConfigMap لتخزين بعض التكوينات. عندما تم إطلاق البودات، كانت ConfigMap في حالة معينة (دعنا نسميها v.1). وفقًا لذلك، تستخدم جميع البودات هذا الإصدار المحدد من ConfigMap.

لنفترض الآن أن خريطة ConfigMap قد تغيرت (الإصدار 2). ومع ذلك، ستستخدم البودات الإصدار السابق من ConfigMap (الإصدار 1):

يذهب؟ سحق! تعرف على مشغل الصدفة (مراجعة وتقرير فيديو من KubeCon EU'2020)

كيف يمكنني جعلهم يتحولون إلى ConfigMap (الإصدار 2) الجديد؟ الجواب بسيط: استخدم القالب. دعونا نضيف تعليقًا توضيحيًا للمجموع الاختباري إلى القسم template تكوينات النشر:

يذهب؟ سحق! تعرف على مشغل الصدفة (مراجعة وتقرير فيديو من KubeCon EU'2020)

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

إذا أجرى المستخدم تغييرات على ConfigMap، فسوف يلاحظها مشغل الصدفة ويعيد حساب المجموع الاختباري. وبعد ذلك، سيتم تفعيل سحر Kubernetes: سيقتل المنسق الكبسولة، وينشئ واحدة جديدة، وينتظر حتى تصبح Ready، وينتقل إلى التالي. ونتيجة لذلك، ستتم مزامنة عملية النشر والتبديل إلى الإصدار الجديد من ConfigMap.

يذهب؟ سحق! تعرف على مشغل الصدفة (مراجعة وتقرير فيديو من KubeCon EU'2020)

المثال 2: العمل مع تعريفات الموارد المخصصة

كما تعلم، يتيح لك Kubernetes إنشاء أنواع مخصصة من الكائنات. على سبيل المثال، يمكنك إنشاء نوع MysqlDatabase. لنفترض أن هذا النوع يحتوي على معلمتين للبيانات الوصفية: name и namespace.

apiVersion: example.com/v1alpha1
kind: MysqlDatabase
metadata:
  name: foo
  namespace: bar

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

يذهب؟ سحق! تعرف على مشغل الصدفة (مراجعة وتقرير فيديو من KubeCon EU'2020)

المثال 3: مراقبة الشبكة العنقودية

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

أولا وقبل كل شيء، سوف تحتاج إلى الاشتراك في العقد. يحتاج مشغل Shell إلى الاسم وعنوان IP لكل عقدة. وبمساعدتهم، سيقوم بتنفيذ الأمر ping على هذه العقد.

configVersion: v1
kubernetes:
- name: nodes
  apiVersion: v1
  kind: Node
  jqFilter: |
    {
      name: .metadata.name,
      ip: (
       .status.addresses[] |  
        select(.type == "InternalIP") |
        .address
      )
    }
  group: main
  keepFullObjectsInMemory: false
  executeHookOnEvent: []
schedule:
- name: every_minute
  group: main
  crontab: "* * * * *"

المعلمة executeHookOnEvent: [] يمنع الخطاف من العمل استجابة لأي حدث (أي استجابة لتغيير العقد أو إضافتها أو حذفها). ومع ذلك فهو سيتم تشغيل (وتحديث قائمة العقد) المقرر - كل دقيقة حسب ما يحدده المجال schedule.

والسؤال الذي يطرح نفسه الآن، كيف نعرف بالضبط عن مشاكل مثل فقدان الحزمة؟ دعونا نلقي نظرة على الكود:

function __main__() {
  for i in $(seq 0 "$(context::jq -r '(.snapshots.nodes | length) - 1')"); do
    node_name="$(context::jq -r '.snapshots.nodes['"$i"'].filterResult.name')"
    node_ip="$(context::jq -r '.snapshots.nodes['"$i"'].filterResult.ip')"
    packets_lost=0
    if ! ping -c 1 "$node_ip" -t 1 ; then
      packets_lost=1
    fi
    cat >> "$METRICS_PATH" <<END
      {
        "name": "node_packets_lost",
        "add": $packets_lost,
        "labels": {
          "node": "$node_name"
        }
      }
END
  done
}

نحن نراجع قائمة العقد، ونحصل على أسمائها وعناوين IP الخاصة بها، ونجري اختبار الاتصال بها ونرسل النتائج إلى Prometheus. يمكن لمشغل Shell تصدير المقاييس إلى Prometheusوحفظها في ملف يقع وفقًا للمسار المحدد في متغير البيئة $METRICS_PATH.

مثل يمكنك إنشاء مشغل لمراقبة الشبكة البسيطة في المجموعة.

آلية الانتظار

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

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

ولحسن الحظ، لدى مشغل الصدفة آلية انتظار مدمجة. يتم وضع جميع الأحداث في قائمة الانتظار ومعالجتها بالتسلسل.

دعونا نوضح ذلك بالأمثلة. لنفترض أن لدينا خطافين. الحدث الأول يذهب إلى الخطاف الأول. بمجرد اكتمال المعالجة، تتحرك قائمة الانتظار للأمام. تتم إعادة توجيه الأحداث الثلاثة التالية إلى الخطاف الثاني - تتم إزالتها من قائمة الانتظار وإدخالها "في دفعة واحدة". إنه يتلقى الخطاف مجموعة من الأحداث - أو بتعبير أدق مجموعة من السياقات الملزمة.

هذه أيضا يمكن دمج الأحداث في واحدة كبيرة. المعلمة هي المسؤولة عن هذا group في تكوين الربط.

يذهب؟ سحق! تعرف على مشغل الصدفة (مراجعة وتقرير فيديو من KubeCon EU'2020)

يمكنك إنشاء أي عدد من قوائم الانتظار/الخطافات ومجموعاتها المختلفة. على سبيل المثال، يمكن لقائمة انتظار واحدة أن تعمل بخطافين، أو العكس.

يذهب؟ سحق! تعرف على مشغل الصدفة (مراجعة وتقرير فيديو من KubeCon EU'2020)

كل ما عليك فعله هو تكوين الحقل وفقًا لذلك queue في تكوين الربط. إذا لم يتم تحديد اسم لقائمة الانتظار، فسيتم تشغيل الخطاف في قائمة الانتظار الافتراضية (default). تتيح لك آلية الانتظار هذه حل جميع مشكلات إدارة الموارد بشكل كامل عند العمل باستخدام الخطافات.

اختتام

لقد شرحنا ما هو مشغل الصدفة، وأظهرنا كيف يمكن استخدامه لإنشاء مشغلي Kubernetes بسرعة ودون عناء، وقدمنا ​​عدة أمثلة على استخدامه.

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

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

يذهب؟ سحق! تعرف على مشغل الصدفة (مراجعة وتقرير فيديو من KubeCon EU'2020)

مقاطع الفيديو والشرائح

فيديو من العرض (~23 دقيقة):


عرض التقرير:

PS

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

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

إضافة تعليق