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



في RIT 2019 ، قدم زميلنا ألكساندر كوروتكوف تقريراً عن أتمتة التطوير في CIAN: لتبسيط الحياة والعمل ، نستخدم منصة Integro الخاصة بنا. يراقب دورة حياة المهام ، ويزيل العمليات الروتينية من المطورين ، ويقلل بدرجة كبيرة من عدد الأخطاء في الإنتاج. في هذا المنشور ، سنكمل تقرير ألكساندر ونخبرك بكيفية انتقالنا من البرامج النصية البسيطة إلى الجمع بين المنتجات مفتوحة المصدر من خلال منصتنا الخاصة وما يفعله فريق أتمتة منفصل.

مستوى الصفر


"لا يوجد مستوى صفر ، لا أعرف هذا"
شيفو سيد من فيلم "كونغ فو باندا"

بدأ التشغيل الآلي لشركة CIAN بعد 14 عامًا من تأسيس الشركة. ثم كان هناك 35 شخصًا في فريق التطوير. من الصعب تصديق ، أليس كذلك؟ بالطبع ، كانت الأتمتة موجودة في بعض الأشكال ، لكن منطقة منفصلة من التكامل المستمر وتسليم الكود بدأت في الظهور في عام 2015.

في ذلك الوقت ، كان لدينا مجموعة ضخمة من Python و C # و PHP التي تم نشرها على خوادم Linux / Windows. لنشر هذا الوحش ، كان لدينا مجموعة من النصوص التي ركضناها يدويًا. كان هناك أيضًا مجموعة متجانسة ، تسبب الألم والمعاناة بسبب النزاعات عند دمج الفروع وتحرير العيوب وإعادة البناء "مع مجموعة مختلفة من المهام في البنية". تبدو العملية المبسطة كما يلي:



هذا لم يناسبنا ، وأردنا إنشاء عملية بناء ونشر قابلة للتكرار ، وآلية ، ومراقبة. للقيام بذلك ، كنا بحاجة إلى نظام CI / CD ، واخترنا بين الإصدار المجاني من Teamcity و Jenkins المجاني ، حيث أننا عملنا معهم وكلاهما يناسبنا لمجموعة من الوظائف. لقد اخترنا Teamcity كمنتج أحدث. ثم لم نستخدم بنية microservice ولم نعتمد على عدد كبير من المهام والمشاريع.

نأتي إلى فكرة نظامنا الخاص


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

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

نظرًا للزيادة في الأتمتة في العمليات التجارية ، زاد عدد المشاريع والمشروعات في Teamcity. لذا فقد حدثت مشكلة جديدة: فقد تم فقدان مثيل Teamcity مجاني (3 وكلاء و 100 مشروع) ، وأضفنا مثيلًا آخر (3 وكلاء آخرين و 100 مشروع) ، ثم آخر. نتيجة لذلك ، حصلنا على نظام من عدة مجموعات ، كان من الصعب إدارته:



عندما أثير سؤال حول المثيل 4 ، أدركنا أنه لم يعد بمقدورنا أن نعيش بهذه الطريقة ، لأن التكاليف الإجمالية لدعم 4 حالات لم تعد مناسبة لأي إطار. نشأت مسألة شراء Teamcity مدفوعة الأجر أو اختيار جنكينز مجانا. أجرينا حسابات على مثيلات وخطط الأتمتة وقررنا أن نعيش على جنكينز. بعد أسبوعين ، انتقلنا إلى Jenkins وتخلصنا من جزء الصداع المرتبط بدعم مثيلات Teamcity المتعددة. لذلك ، تمكنا من التركيز على تطوير Integro واستكمال Jenkins لأنفسنا.

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

أتمتة الاختبار




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

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

فريق الأتمتة


الآن لدينا طاقم من 130 مطور ، ونحن مستمرون في النمو . يتكون فريق التكامل والتوصيل المستمر (المشار إليه فيما يلي باسم فريق النشر والتكامل أو فريق DI) من 7 أشخاص ويعمل في اتجاهين: تطوير نظام التشغيل الآلي لـ Integro و DevOps.

DevOps مسؤولة عن بيئة Dev / Beta لموقع CIAN على الويب ، وهي بيئة Integro ، وتساعد المطورين على حل المشكلات وتطوير أساليب جديدة لتوسيع نطاق البيئات. يتعامل خط أعمال Integro مع كل من Integro نفسها والخدمات ذات الصلة ، على سبيل المثال ، المكونات الإضافية لـ Jenkins و Jira و Confluence ، كما تعمل على تطوير أدوات مساعدة وتطبيقات مساعدة لفرق التطوير.

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

نفخة أتمتة فطيرة في سماوي




يمكن تقسيم جميع الأنظمة المشاركة في التشغيل الآلي إلى عدة طبقات:

  1. الأنظمة الخارجية (جيرا ، بيتبوكيت ، إلخ). فرق التطوير تعمل معهم.
  2. منصة متكاملة. في أغلب الأحيان ، لا يعمل المطورون معها بشكل مباشر ، لكنها هي التي تدعم عمل جميع عمليات التشغيل الآلي.
  3. خدمات التسليم والتنسيق والاكتشاف (على سبيل المثال Jeknins و Consul و Nomad). بمساعدتهم ، ننشر الكود على الخوادم ونوفر الخدمات مع بعضنا البعض.
  4. الطبقة المادية (الخادم ، نظام التشغيل ، البرامج ذات الصلة). في هذا المستوى ، يعمل رمزنا. يمكن أن يكون إما خادمًا فعليًا أو خادمًا افتراضيًا (LXC ، KVM ، Docker).

بناءً على هذا المفهوم ، نقسم مجالات المسؤولية داخل فريق DI. يقع المستويان الأولان في مجال مسؤولية منطقة تطوير Integro ، والمستوىان الأخيران في مجال مسؤولية DevOps. يسمح لك هذا الفصل بالتركيز على المهام وعدم التدخل في التفاعل ، لأننا بجانب بعضنا البعض ونتبادل باستمرار المعرفة والخبرات.

تكاملية


دعنا نركز على Integro ونبدأ بمجموعة التكنولوجيا:

  • CentOs 7
  • عامل الميناء + البدوي + القنصل + المدفن
  • Java 11 (ستظل سلسلة Integro القديمة في Java 8)
  • ربيع التمهيد 2.X + الربيع سحابة التكوين
  • PostgreSql 11
  • RabbitMQ
  • اباتشي تشعل
  • كاموندا (مضمن)
  • جرافانا + جرافيت + بروميثيوس + جايجر + إلك
  • واجهة المستخدم على الويب: React (CSR) + MobX
  • SSO: Keycloak

نحن نتمسك بمبدأ تطوير الخدمات المصغرة ، على الرغم من أننا نملك إرثًا في شكل متراصة من الإصدار السابق من Integro. كل microservice تدور في حاوية الإرساء ، وتتواصل الخدمات مع بعضها البعض من خلال طلبات HTTP ورسائل RabbitMQ. تجد Microservices بعضها البعض من خلال القنصل وتنفذ طلبًا منه ، وتمرير التفويض من خلال SSO (Keycloak ، OAuth 2 / OpenID Connect).



كمثال حقيقي ، فكر في التفاعل مع Jenkins ، والذي يتكون من الخطوات التالية:

  1. تريد خدمة microservice لإدارة سير العمل (المشار إليها فيما يلي باسم microservice Flow) تشغيل التجميع في Jenkins. للقيام بذلك ، يجد من خلال Consul IP: PORT microservice التكامل مع Jenkins (المشار إليها فيما يلي باسم Jenkins microservice) ويرسل إليه طلبًا غير متزامن لبدء التجميع في Jenkins.
  2. تقوم خدمة Jenkins microservice ، عند استلام الطلب ، بإنشاء معرف الوظيفة وإعادته ، بحيث يصبح من الممكن بعد ذلك تحديد نتيجة العمل. جنبا إلى جنب مع هذا ، بدأ بناء في جينكينز من خلال مكالمة إلى REST API.
  3. تقوم Jenkins ببناء و ، عند الانتهاء من ذلك ، تقوم بإرسال webhook مع النتائج إلى Jenkins microservice.
  4. تقوم خدمة Microservice من Jenkins ، بعد تلقيها لـ webhook ، بإنشاء رسالة حول إكمال معالجة الطلب وإرفاق نتائج التنفيذ بها. يتم إرسال الرسالة التي تم إنشاؤها إلى قائمة انتظار RabbitMQ.
  5. من خلال RabbitMQ ، تصل الرسالة المنشورة إلى Flow microservice ، والتي تتعرف على نتيجة معالجة مهمتها عن طريق مطابقة معرف الوظيفة من الطلب والرسالة المستلمة.

لدينا الآن حوالي 30 خدمة ميكروية يمكن تقسيمها إلى عدة مجموعات:

  1. إدارة التكوين.
  2. إعلام والتفاعل مع المستخدمين (الرسائل الفورية ، البريد).
  3. العمل مع شفرة المصدر.
  4. التكامل مع أدوات النشر (جنكينز ، بدوي ، قنصل ، إلخ).
  5. المراقبة (الإصدارات ، الأخطاء ، إلخ).
  6. أدوات الويب المساعدة (واجهة المستخدم لإدارة بيئات الاختبار ، وجمع الإحصاءات ، وما إلى ذلك).
  7. التكامل مع بتتبع المهام والأنظمة المماثلة.
  8. إدارة سير العمل للمهام المختلفة.

مهام سير العمل


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

النظر في سير العمل الذي نستخدمه في معظم الأحيان:



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

اختبار يدوي تمامًا لـ DEV + BETA دون اختبارات الكناري (عادةً ما نطلق متراصة):



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

حركة المهمة


النظر في الخطوات الأساسية التي يتم تنفيذها عند نقل المهمة على سير العمل "اختبار لاختبارات الكناري DEV +":

1. يقوم المطور أو PM بإنشاء المهمة.

2. المطور يأخذ المهمة للعمل. عند الانتهاء ، ينقلها إلى حالة المراجعة.

3. يرسل Jira Webhook نحو microservice Jira (مسؤول عن التكامل مع Jira).

4. ترسل خدمة microservice من Jira طلبًا إلى خدمة Flow (وهي مسؤولة عن سير العمل الداخلي الذي يتم فيه تنفيذ العمل) لبدء سير العمل.

5. داخل خدمة التدفق:

  • يتم تعيين المراجعين للمهمة (خدمة المستخدمين microservice التي تعرف كل شيء عن المستخدمين + Jira-microservice).
  • من خلال المصدر microservice (يعرف عن المستودعات والفروع ، لكنه لا يعمل مع الكود نفسه) ، فإنه يبحث عن مستودعات يوجد فيها فرع من مهمتنا (لتبسيط البحث ، يطابق اسم الفرع رقم المهمة في جيرا). في معظم الأحيان ، تحتوي المهمة على فرع واحد فقط في مستودع واحد ، وهذا يبسط إدارة قائمة الانتظار عند النشر ويقلل من الاتصال بين المستودعات.
  • لكل فرع موجود ، يتم تنفيذ تسلسل الإجراءات التالي:

    i) تأجيج الفرع الرئيسي (Git microservice للعمل مع الكود).
    ii) تم حظر الفرع من التغييرات بواسطة المطور (Bitbucket microservice).
    ج) يتم إنشاء طلب سحب على هذا الفرع (Bitbucket microservice).
    4) يتم إرسال رسالة حول طلب السحب الجديد إلى دردشات المطور (إخطار خدمة microservice للعمل باستخدام الإشعارات).
    v) إنشاء واختبار ونشر المهام إلى DEV (Jenkins microservice للعمل مع Jenkins).
    سادسا) إذا تم الانتهاء من جميع الفقرات السابقة بنجاح ، فإن Integro تضع موافقتها في طلب السحب (Bitbucket microservice).
  • تتوقع Integro قبول طلب السحب من المراجعين المعينين.
  • بمجرد استلام الموافقة اللازمة (بما في ذلك اجتياز الاختبارات الآلية بنجاح) ، تنقل Integro المهمة إلى حالة الاختبار على Dev (خدمة Jira microservice).

6. اختبار اختبار المهمة. إذا لم تكن هناك مشاكل ، فسوف يقومون بنقل المهمة إلى حالة Ready For Build.

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

8. يتم نقل المهمة إلى حالة الكناري (Jira-microservice).

9. يبدأ Jenkins من خلال Nomad بنشر المهام في وضع الكناري (عادةً 1-3 حالات) ويبلغ خدمة مراقبة الإصدار (DeployWatch microservice) بالحساب.

10. يقوم DeployWatch-microservice بجمع أخطاء الخلفية ويستجيب لها إذا لزم الأمر. إذا تم تجاوز خطأ الخلفية (يتم حساب معدل الخلفية تلقائيًا) ، فسيتم إخطار المطورين عبر خدمة الإبلاغ الجزئية في Notify. إذا لم يستجب المطور بعد 5 دقائق (تم النقر فوق الرجوع أو البقاء) ، فسيتم بدء الاستعادة التلقائية لحالات الكناري. إذا لم يتم تجاوز الخلفية ، فيجب على المطور بدء تشغيل المهمة على الإنتاج يدويًا (عن طريق الضغط على الزر في واجهة المستخدم). إذا لم يبدأ المطور في غضون 60 دقيقة عملية نشر في الإنتاج ، فسيتم أيضًا ضخ مثيلات الكناري لأسباب أمنية.

11. بعد إطلاق النشر إلى الإنتاج:

  • يتم نقل المهمة إلى حالة الإنتاج (Jira microservice).
  • Jenkins microservice يبدأ عملية النشر ويبلغ نشر Microservice DeployWatch.
  • يتحقق DeployWatch-microservice من أنه قد تم تحديث جميع الحاويات في الإنتاج (كانت هناك حالات لم يتم تحديثها جميعًا).
  • يتم إرسال إشعار حول نتائج النشر إلى الإنتاج من خلال خدمة الإبلاغ الجزئية.

12. سيكون لدى المطورين 30 دقيقة لبدء التراجع عن المهمة باستخدام "الإنتاج" في حالة اكتشاف السلوك غير الصحيح للجهاز microservice. بعد هذا الوقت ، سيتم سكب المهمة تلقائيًا في الملف الرئيسي (Git-microservice).

13. بعد دمج ناجح في برنامج الماجستير ، سيتم تغيير حالة المهمة إلى Closed (Jira microservice).

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

ما التالي


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

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

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


All Articles