تقديم مشغل shell: مما يجعل مشغلي Kubernetes أسهل

كانت هناك بالفعل مقالات في مدونتنا حول قدرات المشغلين في Kubernetes وكيفية كتابة مشغل بسيط بنفسك . هذه المرة نريد أن نلفت انتباهكم إلى حل Open Source-Solution ، الذي يأخذ عملية إنشاء المشغلين إلى مستوى سهل للغاية - تعرف على مشغل shell !

لماذا؟


فكرة المشغل البسيط بسيطة للغاية: الاشتراك في الأحداث من كائنات Kubernetes ، وعند تلقي هذه الأحداث ، ابدأ تشغيل برنامج خارجي ، مع تزويده بمعلومات حول الحدث:



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

المشغل في 15 دقيقة


دعونا نلقي نظرة على مثال لما يمكن أن يكون آليا في مجموعة Kubernetes وكيف سيساعد مشغل shell. مثال على ذلك ما يلي: تكرار سر الوصول إلى سجل عامل ميناء.

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

الأتمتة سهلة


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

أتمتة مع مشغل شل


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

أولاً ، دعنا نعيد تحليل النص. تسمى البرامج النصية من حيث مشغل shell الخطافات. يخبر كل خطاف عند بدء التشغيل بعلامة --config المشغل shell عن روابطه ، أي ما الأحداث التي تحتاج إلى إطلاق. في حالتنا ، سوف نستخدم onKubernetesEvent :

 #!/bin/bash if [[ $1 == "--config" ]] ; then cat <<EOF { "onKubernetesEvent": [ { "kind": "namespace", "event":["add"] } ]} EOF fi 

يوصف هنا أننا مهتمون بأحداث لإضافة ( add ) كائنات من namespace النوع.

تحتاج الآن إلى إضافة الرمز الذي سيتم تنفيذه عند حدوث الحدث:

 #!/bin/bash if [[ $1 == "--config" ]] ; then #  cat <<EOF { "onKubernetesEvent": [ { "kind": "namespace", "event":["add"] } ]} EOF else # : # ,  namespace  createdNamespace=$(jq -r '.[0].resourceName' $BINDING_CONTEXT_PATH) #      kubectl create -n ${createdNamespace} -f - <<EOF apiVersion: v1 kind: Secret metadata: ... data: ... EOF fi 

! ممتاز والنتيجة هي نص صغير جميل. "لإعادة إحيائها" ، تبقى خطوتان: إعداد الصورة وتشغيلها في الكتلة.

تحضير صورة مع خطاف


إذا نظرت إلى البرنامج النصي ، يمكنك أن ترى أنه jq kubectl و kubectl . هذا يعني أن الصورة يجب أن تحتوي على الأشياء التالية: الخطاف الخاص بنا ، مشغل المشغل الذي سيقوم بمراقبة الأحداث وإطلاق الخطاف ، وكذلك الأوامر المستخدمة بواسطة الخطاف (kubectl و jq). يحتوي Hub.docker.com بالفعل على صورة جاهزة يتم فيها تغليف shell-operator و kubectl و jq. يبقى لإضافة الخطاف مع Dockerfile بسيط:

 $ cat Dockerfile FROM flant/shell-operator:v1.0.0-beta.1-alpine3.9 ADD namespace-hook.sh /hooks $ docker build -t registry.example.com/my-operator:v1 . $ docker push registry.example.com/my-operator:v1 

إطلاق الكتلة


مرة أخرى ، دعنا ننظر إلى الخطاف وهذه المرة أكتب الإجراءات وما الأشياء التي يؤديها في الكتلة:

  1. يشترك في أحداث مساحة الاسم
  2. ينشئ سرًا في مساحات الأسماء غير المكان الذي يتم تشغيله فيه.

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

الوصف النهائي في YAML هو شيء مثل هذا:

 --- apiVersion: v1 kind: ServiceAccount metadata: name: monitor-namespaces-acc --- apiVersion: rbac.authorization.k8s.io/v1beta1 kind: ClusterRole metadata: name: monitor-namespaces rules: - apiGroups: [""] resources: ["namespaces"] verbs: ["get", "watch", "list"] - apiGroups: [""] resources: ["secrets"] verbs: ["get", "list", "create", "patch"] --- apiVersion: rbac.authorization.k8s.io/v1beta1 kind: ClusterRoleBinding metadata: name: monitor-namespaces roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: monitor-namespaces subjects: - kind: ServiceAccount name: monitor-namespaces-acc namespace: example-monitor-namespaces 

يمكنك تشغيل الصورة المجمعة في شكل نشر بسيط:

 apiVersion: extensions/v1beta1 kind: Deployment metadata: name: my-operator spec: template: spec: containers: - name: my-operator image: registry.example.com/my-operator:v1 serviceAccountName: monitor-namespaces-acc 


للراحة ، يتم إنشاء مساحة اسم منفصلة حيث سيتم تشغيل مشغل shell وتطبيق البيانات التي تم إنشاؤها:

 $ kubectl create ns example-monitor-namespaces $ kubectl -n example-monitor-namespaces apply -f rbac.yaml $ kubectl -n example-monitor-namespaces apply -f deployment.yaml 


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



وبالتالي ، تحول البرنامج النصي shell بسيط إلى مشغل حقيقي لـ Kubernetes ويعمل كجزء لا يتجزأ من الكتلة. وكل هذا - بدون العملية المعقدة لتطوير المشغلين في Golang:



هناك توضيح آخر حول هذا الموضوع ...


سنكشف عن معناها بمزيد من التفصيل في أحد المنشورات التالية. محدث (1 مايو 2019): راجع " توسيع Kubernetes وتوسيعه (مراجعة وتقرير فيديو) ".

تصفية


يعد تتبع الكائنات جيدًا ، لكن غالبًا ما يكون من الضروري الاستجابة للتغيرات في بعض خصائص كائن ، على سبيل المثال ، إلى تغيير في عدد النسخ المتماثلة في نشر ، أو لتغيير في تسميات كائن.

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

على سبيل المثال ، للرد على تغييرات التصنيف على كائنات النشر ، تحتاج إلى تصفية حقل labels من حقل metadata . سيكون التكوين مثل هذا:

 cat <<EOF { "onKubernetesEvent": [ { "kind": "deployment", "event":["update"], "jqFilter": ".metadata.labels" } ]} EOF 

يعمل هذا التعبير في jqFilter على تحويل بيان JSON الطويل الخاص بـ Deployment إلى JSON قصيرة مع تسميات:



سوف يقوم مشغل shell بتشغيل خطاف فقط عندما يتم تغيير JSON هذه التغييرات القصيرة ويتم تجاهل التغييرات في الخصائص الأخرى.

ربط إطلاق السياق


يتيح لك تكوين الخطاف تحديد عدة خيارات للأحداث - على سبيل المثال ، خياران للأحداث من Kubernetes وجدولين:

 {"onKubernetesEvent":[ {"name":"OnCreatePod", "kind": "pod", "event":["add"] }, {"name":"OnModifiedNamespace", "kind": "namespace", "event":["update"], "jqFilter": ".metadata.labels" } ], "schedule": [ { "name":"every 10 min", "crontab":"0 */10 * * * *" }, {"name":"on Mondays at 12:10", "crontab": "0 10 12 * * 1" ]} 

انحدار صغير: نعم ، يدعم مشغل shell تشغيل البرامج النصية على طراز crontab . يمكنك قراءة المزيد في الوثائق .

لتمييز سبب إطلاق الخطاف ، يقوم مشغل shell بإنشاء ملف مؤقت ويمرر المسار إلى BINDING_CONTEXT_TYPE في المتغير BINDING_CONTEXT_TYPE . يحتوي الملف على وصف JSON لسبب بدء الربط. على سبيل المثال ، سيبدأ الخطاف كل 10 دقائق بالمحتويات التالية:

 [{ "binding": "every 10 min"}] 

... وفي يوم الاثنين سيبدأ بهذا:

 [{ "binding": "every 10 min"}, { "binding": "on Mondays at 12:10"}] 

ل onKubernetesEvent سيكون onKubernetesEvent المزيد من إطلاق JSON منذ ذلك الحين أنه يحتوي على وصف للكائن:

 [ { "binding": "onCreatePod", "resourceEvent": "add", "resourceKind": "pod", "resourceName": "foo", "resourceNamespace": "bar" } ] 

يمكن فهم محتويات الحقول من أسمائهم ، وبمزيد من التفصيل - اقرأ في الوثائق . تم عرض مثال على الحصول على اسم المورد من حقل resourceName باستخدام jq بالفعل في خطاف يقوم بتكرار الأسرار:

 jq -r '.[0].resourceName' $BINDING_CONTEXT_PATH 

وبالمثل ، يمكنك الحصول على الحقول المتبقية.

ما التالي؟


في مستودع المشروع ، في الدليل / أمثلة ، هناك أمثلة عن السنانير الجاهزة للتشغيل في الكتلة. عند كتابة السنانير الخاصة بك ، يمكنك أن تأخذها كأساس.

هناك دعم لجمع المقاييس باستخدام Prometheus - تتم كتابة المقاييس المتوفرة في قسم METRICS .

كما قد تظن ، فإن مشغل shell مكتوب بلغة Go ويوزع تحت رخصة مفتوحة المصدر (Apache 2.0). سنكون ممتنين لأي مساعدة في تطوير المشروع على جيثب : العلامات النجمية والمشاكل وسحب الطلبات.

عند فتح حجاب السرية ، نعلم أيضًا أن المشغل الصدفي جزء صغير من نظامنا يمكنه تحديث الإضافات المثبتة في نظام Kubernetes وتنفيذ العديد من الإجراءات التلقائية. تحدثنا عن هذا النظام بمزيد من التفاصيل يوم الاثنين في HighLoad ++ 2019 في سان بطرسبرغ - سيتم نشر الفيديو ونص هذا التقرير قريبًا.

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

ترقبوا!

PS


اقرأ أيضًا في مدونتنا:

Source: https://habr.com/ru/post/ar447442/


All Articles