تشغيل فرق في عملية تسليم إصدار تطبيق جديد إلى Kubernetes



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

الأوامر التعسفية مع هيلم ورف


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

ماذا تقدم Kubernetes لحل هذه المشاكل؟ Kubernetes جيد في تشغيل الحاويات كقرون ، وبالتالي فإن الحل القياسي هو تشغيل أمر من صورة ما. للقيام بذلك ، يوجد بدائل Job في Kubernetes يسمح لك بتشغيل pod مع حاويات التطبيقات ومراقبة اكتمال هذا الحافظة.

يذهب هيلم إلى أبعد من ذلك ويقترح إطلاق Job's في مراحل مختلفة من عملية النشر. نحن نتحدث عن خطافات Helm التي يمكنك من خلالها تشغيل Job قبل أو بعد تحديث بيانات المورد. في تجربتنا ، هذه ميزة هيلم رائعة يمكن استخدامها لحل مهام النشر.

ومع ذلك ، فإنه من المستحيل الحصول على معلومات محدثة عن حالة الكائنات أثناء بدء التشغيل في Helm ، وبالتالي فإننا نستخدم الأداة المساعدة werf ، التي تجعل من الممكن مراقبة حالة الموارد أثناء بدء التشغيل مباشرة من نظام CI ، وإذا نجحنا في ذلك ، نقوم بتشخيص انهيار سريع.

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

تشغيل الهجرات قبل الإصدار


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

  1. تحديث قاعدة الكود ؛
  2. بداية الهجرة ؛
  3. تحويل حركة المرور إلى الإصدار الجديد من التطبيق.

داخل Kubernetes ، يجب أن تكون العملية هي نفسها ، ولكن مع تعديلها حسب ما نحتاج إليه:

  1. إطلاق حاوية برمز جديد ، والتي قد تحتوي على مجموعة جديدة من عمليات الترحيل ؛
  2. ابدأ عملية تطبيق الترحيل فيه ، بعد القيام بذلك قبل تحديث إصدار التطبيق.

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

  • pre-install - يعمل على إصدار Helm الأول للتطبيق بعد معالجة جميع القوالب ، ولكن قبل إنشاء الموارد في Kubernetes ؛
  • pre-upgrade - يعمل عند تحديث إصدار Helm وتشغيله ، مثل pre-install ، بعد معالجة القوالب ، ولكن قبل إنشاء الموارد في Kubernetes.

مثال الوظيفة باستخدام هيلم والسنانير المذكورة:

 --- apiVersion: batch/v1 kind: Job metadata: name: {{ .Chart.Name }}-apply-migrations annotations: "helm.sh/hook": pre-install,pre-upgrade spec: activeDeadlineSeconds: 60 backoffLimit: 0 template: metadata: name: {{ .Chart.Name }}-apply-migrations spec: imagePullSecrets: - name: {{ required ".Values.registry.secret_name required" .Values.registry.secret_name }} containers: - name: job command: ["/usr/bin/php7.2", "artisan", "migrate", "--force"] {{ tuple "backend" . | include "werf_container_image" | indent 8 }} env: {{ tuple "backend" . | include "werf_container_env" | indent 8 }} - name: DB_HOST value: postgres restartPolicy: Never 

ملاحظة : تم إنشاء قالب YAML أعلاه مع مراعاة خصوصيات werf. لتكييفها مع رأس "نظيف" ، يكفي:

  • يستعاض عن {{ tuple "backend" . | include "werf_container_image" | indent 8 }} {{ tuple "backend" . | include "werf_container_image" | indent 8 }} {{ tuple "backend" . | include "werf_container_image" | indent 8 }} لصورة الحاوية التي تحتاج إليها ؛
  • احذف السطر {{ tuple "backend" . | include "werf_container_env" | indent 8 }} {{ tuple "backend" . | include "werf_container_env" | indent 8 }} {{ tuple "backend" . | include "werf_container_env" | indent 8 }} ، والتي تم تحديدها في مفتاح env .

لذلك ، سوف تحتاج إلى إضافة قالب Helm إلى دليل .helm/templates ، والذي يحتوي بالفعل على بقية موارد الإصدار. عند werf deploy --stages-storage :local استدعاء werf deploy --stages-storage :local ، ستتم معالجة جميع القوالب أولاً ، ثم يتم تحميلها في نظام Kubernetes.

بدء عمليات الترحيل أثناء عملية الإصدار


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

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

في هذه الحالة ، فإن السنانير المثبتة pre-upgrade ليست مناسبة لنا ، لأن التطبيق سيحاول تطبيق عمليات الترحيل على قاعدة البيانات غير الموجودة بعد . وبالتالي ، فمن الضروري إجراء الهجرات بعد الإفراج.

عند استخدام Helm ، تكون هذه المهمة قابلة للتحقيق ، لأنها لا تراقب حالة التطبيقات. بعد تحميل الموارد في Kubernetes ، يتم إطلاق خطافات النشر دائمًا :

  • post-install - بعد تحميل جميع الموارد في K8s في الإصدار الأول ؛
  • post-upgrade - بعد تحديث جميع الموارد في K8s عند تحديث الإصدار.

ومع ذلك ، كما ذكرنا أعلاه ، لدى werf نظام تتبع موارد أثناء الإصدار. سوف أتناول هذا بالتفصيل أكثر قليلاً:

  • للتتبع ، يستخدم werf إمكانيات مكتبة kubedog ، التي تحدثنا عنها بالفعل في المدونة.
  • تتيح لنا هذه الميزة في werf تحديد حالة الإصدار وعرض المعلومات بشكل فريد عن الإكمال الناجح أو غير الناجح للنشر في واجهة نظام CI / CD.
  • دون تلقي هذه المعلومات ، لا يمكن للمرء أن يتحدث عن أي أتمتة لعملية الإصدار ، لأن الإنشاء الناجح للموارد في مجموعة Kubernetes هو واحد فقط من المراحل. على سبيل المثال ، قد لا يبدأ التطبيق بسبب تكوين غير صحيح أو بسبب مشكلة في الشبكة ، ولكن لمشاهدة ذلك بعد helm upgrade ، سيتعين عليك تنفيذ خطوات إضافية.

عاد الآن إلى تطبيق الهجرات على هيلم بعد السنانير. المشاكل التي واجهناها:

  • تحقق العديد من التطبيقات قبل البدء بطريقة أو بأخرى من حالة الدائرة في قاعدة البيانات. لذلك ، بدون عمليات ترحيل جديدة ، قد لا يبدأ التطبيق.
  • نظرًا لأن werf ، افتراضيًا ، يضمن أن جميع الكائنات في حالة Ready ، فلن تعمل روابط النشر وستفشل عمليات الترحيل.
  • يمكن تعطيل كائنات التتبع من خلال التعليقات التوضيحية الإضافية ، ولكن بعد ذلك يستحيل الحصول على معلومات موثوقة حول نتائج النشر.

نتيجة لذلك ، توصلنا إلى ما يلي:

  • يتم إنشاء الوظائف قبل الموارد الرئيسية ، لذلك ليست هناك حاجة لاستخدام خطافات Helm للترحيل .
  • ومع ذلك ، يجب تشغيل وظيفة مع الترحيل في كل عملية نشر. لكي يحدث هذا ، يجب أن يكون لـ Job اسم فريد (عشوائي): في هذه الحالة ، بالنسبة لـ Helm ، يكون هذا في كل مرة كائنًا جديدًا في الإصدار ، سيتم إنشاؤه في Kubernetes.
  • مع هذا الإطلاق ، ليس هناك ما يدعو للقلق من أن Job سوف تتراكم مع عمليات الترحيل ، لأن جميعها سيكون لها أسماء فريدة ، وسيتم حذف Job السابق بإصدار جديد.
  • يجب أن تحتوي المهمة التي تحتوي على عمليات ترحيل على حاوية init التي تتحقق من توفر قاعدة البيانات - وإلا فإننا نحصل على نشر تم إسقاطه (سوف تقع المهمة على حاوية init).

يبدو التكوين الناتج مثل هذا:

 --- apiVersion: batch/v1 kind: Job metadata: name: {{ printf "%s-apply-migrations-%s" .Chart.Name (now | date "2006-01-02-15-04-05") }} spec: activeDeadlineSeconds: 60 backoffLimit: 0 template: metadata: name: {{ printf "%s-apply-migrations-%s" .Chart.Name (now | date "2006-01-02-15-04-05") }} spec: imagePullSecrets: - name: {{ required ".Values.registry.secret_name required" .Values.registry.secret_name }} initContainers: - name: wait-db image: alpine:3.6 ommand: ["/bin/sh", "-c", "while ! nc -z postgres 5432; do sleep 1; done;"] containers: - name: job command: ["/usr/bin/php7.2", "artisan", "migrate", "--force"] {{ tuple "backend" . | include "werf_container_image" | indent 8 }} env: {{ tuple "backend" . | include "werf_container_env" | indent 8 }} - name: DB_HOST value: postgres restartPolicy: Never 

ملاحظة : بالمعنى الدقيق للكلمة ، من الأفضل استخدام حاويات الحرف الأول للتحقق من توفر قاعدة البيانات على أي حال.

مثال على قالب عالمي لجميع عمليات النشر


ومع ذلك ، قد تكون العمليات التي يلزم إجراؤها أثناء الإصدار أكثر من إطلاق عمليات الترحيل المذكورة بالفعل. يمكنك التحكم في ترتيب تنفيذ Job ليس فقط من خلال أنواع السنانير ، ولكن أيضًا من خلال تعيين وزن لكل منهم - من خلال helm.sh/hook-weight . يتم فرز الخطافات حسب الوزن بترتيب تصاعدي ، وإذا كان الوزن هو نفسه ، حسب اسم المورد.

مع وجود عدد كبير من الوظائف ، من الملائم إنشاء قالب عالمي للوظائف ، ووضع التكوين في values.yaml . هذا الأخير قد يبدو مثل هذا:

 deploy_jobs: - name: migrate command: '["/usr/bin/php7.2", "artisan", "migrate", "--force"]' activeDeadlineSeconds: 120 when: production: 'pre-install,pre-upgrade' staging: 'pre-install,pre-upgrade' _default: '' - name: cache-clear command: '["/usr/bin/php7.2", "artisan", "responsecache:clear"]' activeDeadlineSeconds: 60 when: _default: 'post-install,post-upgrade' 

... والقالب نفسه يشبه هذا:

 {{- range $index, $job := .Values.deploy_jobs }} --- apiVersion: batch/v1 kind: Job metadata: name: {{ $.Chart.Name }}-{{ $job.name }} annotations: "helm.sh/hook": {{ pluck $.Values.global.env $job.when | first | default $job.when._default }} "helm.sh/hook-weight": "1{{ $index }}" spec: activeDeadlineSeconds: {{ $job.activeDeadlineSeconds }} backoffLimit: 0 template: metadata: name: {{ $.Chart.Name }}-{{ $job.name }} spec: imagePullSecrets: - name: {{ required "$.Values.registry.secret_name required" $.Values.registry.secret_name }} initContainers: - name: wait-db image: alpine:3.6 ommand: ["/bin/sh", "-c", "while ! nc -z postgres 5432; do sleep 1; done;"] containers: - name: job command: {{ $job.command }} {{ tuple "backend" $ | include "werf_container_image" | indent 8 }} env: {{ tuple "backend" $ | include "werf_container_env" | indent 8 }} - name: DB_HOST value: postgres restartPolicy: Never {{- end }} 

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

استنتاج


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

تعليق من المطورين werf:
في المستقبل ، تخطط werf لإدخال مراحل نشر قابلة للتكوين بواسطة المستخدم. بمساعدة هذه المراحل ، سيكون من الممكن وصف كلتا الحالتين وليس فقط.

PS


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

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


All Articles