دمج ثلاثي الاتجاهات في werf: نشر في Kubernetes مع Helm "على المنشطات"

حدث شيء أننا (وليس نحن فقط) ننتظره: werf ، أداة Open Source الخاصة بنا لإنشاء التطبيقات وتسليمها إلى Kubernetes ، تدعم الآن تطبيق التغييرات باستخدام تصحيحات دمج ثلاثية! بالإضافة إلى ذلك ، أصبح من الممكن اعتماد موارد K8 الموجودة في إصدارات Helm دون إعادة إنشاء هذه الموارد.



إذا كانت قصيرة جدًا ، WERF_THREE_WAY_MERGE=enabled بتعيين WERF_THREE_WAY_MERGE=enabled - نحصل على النشر "كما هو الحال في kubectl apply " ، متوافق مع عمليات التثبيت الموجودة على Helm 2 وأكثر من ذلك بقليل.

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

ما هو التصحيح 3 طريقة دمج؟


لذلك ، لنبدأ بمهمة نشر الموارد الموضحة في قوائم YAML في Kubernetes.

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

فرق kubectl حتمية


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

  • kubectl run الأمر kubectl run النشر أو الوظيفة:

     kubectl run --generator=deployment/apps.v1 DEPLOYMENT_NAME --image=IMAGE 
  • الأمر kubectl scale - تغيير عدد النسخ المتماثلة:

     kubectl scale --replicas=3 deployment/mysql 
  • إلخ

قد يبدو هذا النهج مناسبًا للوهلة الأولى. ومع ذلك ، هناك مشاكل:

  1. من الصعب التشغيل الآلي .
  2. كيف تعكس التكوين في جيت؟ كيفية مراجعة التغييرات التي تحدث على كتلة؟
  3. كيفية ضمان استنساخ التكوين في إعادة التشغيل؟
  4. ...

من الواضح أن هذا النهج لا يتناسب بشكل جيد مع تخزين التطبيق والبنية التحتية كرمز (IaC ؛ أو حتى GitOps كخيار أكثر حداثة ، واكتساب شعبية في نظام Kubernetes البيئي) مع الكود. لذلك ، لم تحصل هذه الفرق على مزيد من التطوير في kubectl.

إنشاء العمليات والحصول عليها واستبدالها وحذفها


مع الإنشاء الأساسي ، كل شيء بسيط: نرسل البيان إلى عملية create kube api ويتم إنشاء المورد. يمكن تخزين تمثيل YAML kubectl create -f manifest.yaml في Git ، ولإنشاء واستخدام الأمر kubectl create -f manifest.yaml .

الحذف بسيط أيضًا: kubectl delete -f manifest.yaml نفس manifest.yaml من Git في الأمر kubectl delete -f manifest.yaml .

تتيح لك عملية الاستبدال استبدال تكوين المورد بالكامل بتكوين جديد ، دون إعادة إنشاء المورد. هذا يعني أنه قبل إجراء تغيير على مورد ما ، فمن المنطقي أن تطلب الإصدار الحالي مع العملية get ، وتغييره ، والتحديث باستخدام عملية replace . يتم تأمين القفل الأمثل في kube apiserver ، وإذا كان الكائن قد تغير بعد get العملية ، فسوف تفشل عملية replace .

لتخزين التكوين في Git والتحديث باستخدام subst ، تحتاج إلى إجراء عملية get ، واحتفظ بالتكوين من Git باستخدام ما حصلنا عليه ، وقم بإجراء replace . عادةً ، يسمح لك kubectl فقط باستخدام الأمر kubectl replace -f manifest.yaml ، حيث يكون manifest.yaml هو manifest.yaml الكامل (في حالتنا ، المجاور) الذي تحتاج إلى تثبيته. اتضح أن المستخدم يحتاج إلى تطبيق بيانات الدمج ، ولكن هذه ليست مسألة تافهة ...

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

خلاصة القول: هل يمكننا إنشاء نسخة متواصلة فقط من خلال إنشاء واستبدال وحذف ، مع ضمان تخزين تكوين البنية التحتية في Git مع الرمز و CI / CD مناسب؟

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

  • يتحقق من وجود كائن في الكتلة ،
  • يؤدي الإنشاء الأولي للمورد ،
  • تحديثات أو حذفها.

عند التحديث ، يجب أن تأخذ في الاعتبار أن المورد قد يكون قد تغير منذ آخر get على حالة القفل المتفائل والتعامل معها تلقائيًا - قم بمحاولات متكررة للتحديث.

ومع ذلك ، لماذا تعيد اختراع العجلة عندما يقدم kube-apiserver طريقة أخرى لتحديث الموارد: عملية patch ، التي تزيل بعض المشكلات الموضحة من المستخدم؟

بقعة


لذلك وصلنا إلى بقع.

البقع هي الطريقة الأساسية لتطبيق التغييرات على الكائنات الموجودة في Kubernetes. تعمل عملية patch بحيث:

  • يحتاج المستخدم kube-apiserver إلى إرسال التصحيح بتنسيق JSON وتحديد الكائن ،
  • و apiserver نفسها سوف تتعامل مع الحالة الراهنة للكائن وإحضاره إلى الشكل المطلوب.

تأمين متفائل في هذه الحالة غير مطلوب. هذه العملية أكثر تعريفا مقارنة بالاستبدال ، رغم أنها قد تبدو في البداية عكس ذلك.

بهذه الطريقة:

  • باستخدام عملية create ، نقوم بإنشاء كائن من البيان من جيت ،
  • باستخدام delete - حذف إذا لم يعد الكائن مطلوبًا ،
  • باستخدام patch - نقوم بتعديل الكائن ، وننقله إلى النموذج الموضح في Git.

ومع ذلك ، للقيام بذلك ، يجب عليك إنشاء التصحيح الصحيح !

كيف تعمل التصحيحات في Helm 2: 2-way-merge


في المرة الأولى التي يتم فيها تثبيت الإصدار ، يقوم Helm بإجراء عملية create على موارد المخطط.

عند تحديث إصدار Helm لكل مورد:

  • بحساب التصحيح بين إصدار المورد من المخطط السابق والإصدار الحالي من المخطط ،
  • ينطبق هذا التصحيح.

سوف نطلق على هذا التصحيح patch -2-way-merge ، لأن هناك بيانان يشاركان في إنشائه:

  • بيان الموارد من الإصدار السابق ،
  • بيان المورد من المورد الحالي.

عند الحذف ، يتم استدعاء عملية delete في kube apiserver للموارد التي تم الإعلان عنها في الإصدار السابق ولكن لم يتم الإعلان عنها في الإصدار الحالي.

توجد مشكلة في الطريقة التي بها تصحيح دمج للطريقتين : تؤدي إلى إلغاء الحالة الحقيقية للمورد في المجموعة والبيان الظاهر في Git .

مثال على مشكلة


  • في Git ، يتم تخزين البيان على الرسم البياني الذي يحتوي فيه حقل image النشر على قيمة ubuntu:18.04 .
  • غير المستخدم من خلال kubectl edit قيمة هذا الحقل إلى ubuntu:19.04 .
  • عند إعادة نشر المخطط ، لا يقوم Helm بإنشاء تصحيح ، لأن حقل image في الإصدار السابق من الإصدار وفي المخطط الحالي متماثلان.
  • بعد النشر المتكرر image ، يبقى ubuntu:19.04 ، على الرغم من أن ubuntu:18.04 مكتوب على الرسم البياني.

لقد حصلنا على التصميم وفقدنا التصريح.

ما هو مورد متزامن؟


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

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

3-طريقة دمج التصحيح


الفكرة الرئيسية للتصحيح 3-way-merge : نقوم بإنشاء تصحيح بين الإصدار الأخير المطبق للبيان من Git والإصدار الهدف من البيان من Git ، مع مراعاة الإصدار الحالي للبيان من مجموعة العمل. يجب أن يتوافق التصحيح النهائي مع قاعدة الموارد المتزامنة:

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

بناءً على هذا المبدأ ، يتم إنشاء تصحيحات kubectl apply :

  • يتم تخزين الإصدار الأخير المطبق من البيان في التعليق التوضيحي للكائن نفسه ،
  • الهدف - مأخوذ من ملف YAML المحدد ،
  • الحالية - من كتلة العمل.

الآن وبعد أن توصلنا إلى النظرية ، حان الوقت لنخبرك بما فعلناه على الفور.

تطبيق التغييرات على werf


في وقت سابق ، استخدم werf ، مثل Helm 2 ، تصحيحات دمج ثنائية الاتجاه.

إصلاح التصحيح


من أجل التبديل إلى نوع جديد من التصحيحات - دمج ثلاثي الاتجاهات - الخطوة الأولى قدمنا ​​ما يسمى بقع الإصلاح .

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

في حالة وجود rassynchron ، في نهاية النشر ، يتلقى المستخدم تحذير مع الرسالة والتصحيح المناسبين ، والتي يجب تطبيقها من أجل إحضار المورد إلى نموذج متزامن. أيضًا ، يتم تسجيل هذا التصحيح في تعليق توضيحي خاص werf.io/repair-patch . من المفترض أن يقوم المستخدم نفسه بتطبيق هذا التصحيح بيديه: لن يقوم werf بتطبيقه من حيث المبدأ.

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

تصحيح ثلاثي الاتجاه للإصدارات الجديدة فقط


بدءًا من الأول من ديسمبر (كانون الأول) 2019 ، تبدأ الإصدارات التجريبية والألفا من werf افتراضيًا في استخدام تصحيحات دمج ثلاثية كاملة لتطبيق التغييرات فقط على إصدارات Helm الجديدة التي تم نشرها عبر werf. ستستمر الإصدارات الحالية في استخدام نهج التصحيح 2-way-merge + repair.

يمكنك تمكين وضع التشغيل هذا بشكل صريح عن طريق تعيين WERF_THREE_WAY_MERGE_MODE=onlyNewReleases الآن.

ملاحظة : ظهرت الميزة في werf على العديد من الإصدارات: في قناة ألفا ، أصبحت جاهزة من الإصدار v1.0.5-alpha.19 ، وفي قناة beta ذات الإصدار v1.0.4-beta.20 .

3-طريقة دمج التصحيح لجميع الإصدارات


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

يمكن WERF_THREE_WAY_MERGE_MODE=enabled وضع التشغيل هذا بشكل صريح WERF_THREE_WAY_MERGE_MODE=enabled تعيين WERF_THREE_WAY_MERGE_MODE=enabled الآن.

ماذا تفعل مع موارد autoscaling؟


Kubernetes لديه نوعان من autoscaling: HPA (أفقي) و VPA (عمودي).

أفقي يحدد تلقائيًا عدد النسخ المتماثلة والرأسي - عدد الموارد. يتم تحديد عدد النسخ المتماثلة ومتطلبات الموارد في بيان المورد (انظر spec.replicas أو spec.containers[].resources.limits.cpu ، spec.containers[].resources.limits.memory and others ).

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

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

  • werf.io/set-replicas-only-on-creation=true
  • werf.io/set-resources-only-on-creation=true

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

لمزيد من المعلومات ، راجع وثائق المشروع لـ HPA و VPA .

رفض استخدام تصحيح 3-طريقة دمج


لا يزال بإمكان المستخدم حظر استخدام تصحيحات جديدة في werf باستخدام متغير البيئة WERF_THREE_WAY_MERGE_MODE=disabled . ومع ذلك ، بدءًا من 1 مارس 2020 ، سيتوقف هذا الحظر عن العمل وسيكون من الممكن فقط استخدام تصحيحات دمج ثلاثي الاتجاه.

اعتماد الموارد في werf


إتقان طريقة تطبيق التغييرات في تصحيحات الدمج الثلاثية أتاح لنا أن ننفذ على الفور ميزة مثل اعتماد الموارد الموجودة في الكتلة في إصدار Helm.

يواجه Helm 2 مشكلة: لا يمكنك إضافة مورد بيان موجود بالفعل في الكتلة دون إعادة إنشاء هذا المورد من البداية (انظر # 6031 ، # 3275 ). علمنا werf لقبول الموارد الموجودة في الإصدار. للقيام بذلك ، تحتاج إلى تعيين تعليق توضيحي على إصدار المورد الحالي من مجموعة عمل (على سبيل المثال ، باستخدام kubectl edit ):

 "werf.io/allow-adoption-by-release": RELEASE_NAME 

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

ملاحظة : لا يؤثر إعداد WERF_THREE_WAY_MERGE_MODE على اعتماد الموارد - في حالة التبني ، يتم دائمًا استخدام تصحيح ثلاثي الاتجاهات.

التفاصيل في الوثائق .

الاستنتاجات وخطط المستقبل


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

لا تزال هناك بعض المشكلات والصعوبات في عملية النشر التي تشبه Helm ، مثل استخدام قوالب Go ، وسوف نستمر في حلها.

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

هيلم 3


ملاحظة خاصة تستحق الإصدار الرئيسي الجديد الذي تم إصداره مؤخرًا من Helm - v3 - والذي يستخدم أيضًا تصحيحات دمج ثلاثية الاتجاهات ويتخلص من Tiller. يتطلب الإصدار الجديد من Helm ترحيل المنشآت الموجودة لتحويلها إلى تنسيق تخزين إصدار جديد.

Werf ، من جانبها ، استبعد الآن استخدام Tiller ، وانتقل إلى الدمج الثلاثي الاتجاهات وأضف الكثير ، بينما يظل متوافقًا مع التركيبات الموجودة على Helm 2 (لا يلزم وجود نصوص ترحيل). لذلك ، حتى يتم تبديل werf إلى Helm 3 ، لا يفقد المستخدمون werf المزايا الرئيسية لـ Helm 3 على Helm 2 (وهي موجودة أيضًا في werf).

ومع ذلك ، فإن تبديل werf إلى قاعدة بيانات Helm 3 أمر لا مفر منه وسيحدث في المستقبل القريب. من المفترض أن تكون werf 1.1 أو werf 1.2 (في الوقت الحالي ، الإصدار الرئيسي من werf هو 1.0 ؛ لمزيد من التفاصيل حول جهاز تعيين الإصدار werf ، انظر هنا ). خلال هذا الوقت ، سيكون لدى Helm 3 وقت للاستقرار.

PS


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

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


All Articles