Од скрипти до нашата сопствена платформа: како го автоматизиравме развојот во CIAN

Од скрипти до нашата сопствена платформа: како го автоматизиравме развојот во CIAN

На RIT 2019 направи нашиот колега Александар Коротков извештај за автоматизација на развојот во CIAN: за да ги поедноставиме животот и работата, ја користиме нашата сопствена платформа Integro. Го следи животниот циклус на задачите, ги ослободува програмерите од рутински операции и значително го намалува бројот на грешки во производството. Во оваа објава, ќе го надополниме извештајот на Александар и ќе ви кажеме како преминавме од едноставни скрипти до комбинирање на производи со отворен код преку нашата сопствена платформа и што прави нашиот посебен тим за автоматизација.
 

Нулта ниво

„Не постои такво нешто како нула ниво, јас не знам такво нешто“
Мајстор Шифу од филмот „Кунг фу панда“

Автоматизацијата во CIAN започна 14 години по основањето на компанијата. Во тоа време имаше 35 луѓе во тимот за развој. Тешко е да се поверува, нели? Се разбира, автоматизацијата постоеше во некоја форма, но посебна насока за континуирана интеграција и испорака на кодови почна да се формира во 2015 година. 

Во тоа време, имавме распореден огромен монолит од Python, C# и PHP на Linux/Windows сервери. За да го распоредиме ова чудовиште, имавме сет на скрипти што ги извршувавме рачно. Исто така, постоеше и монолитна градба, која донесе болка и страдање поради конфликти при спојување на гранки, поправање на дефекти и повторно градење „со различен сет на задачи во градбата“. Поедноставено, процесот изгледаше вака:

Од скрипти до нашата сопствена платформа: како го автоматизиравме развојот во CIAN

Не бевме задоволни со ова и сакавме да изградиме повторлив, автоматизиран и податлив процес на градење и распоредување. За ова ни требаше CI/CD систем и избравме помеѓу бесплатната верзија на Teamcity и бесплатната верзија на Џенкинс, бидејќи работевме со нив и двете ни одговараа во однос на множеството функции. Го избравме Teamcity како понов производ. Во тоа време, сè уште не користевме микросервис архитектура и не очекувавме голем број задачи и проекти.

Доаѓаме до идејата за нашиот сопствен систем

Имплементацијата на Teamcity отстрани само дел од мануелната работа: она што останува е создавање на барања за повлекување, промоција на прашања по статус во Jira и избор на прашања за објавување. Системот Teamcity повеќе не можеше да се справи со ова. Беше неопходно да се избере патот на понатамошна автоматизација. Разгледавме опции за работа со скрипти во Teamcity или префрлување на системи за автоматизација на трети лица. Но, на крајот решивме дека ни е потребна максимална флексибилност, која може да ја обезбеди само нашето сопствено решение. Така се појави првата верзија на системот за внатрешна автоматизација наречена Integro.

Teamcity се занимава со автоматизација на ниво на започнување на процесите на градење и распоредување, додека Integro се фокусираше на автоматизација на развојните процеси на највисоко ниво. Беше неопходно да се комбинира работата со проблеми во Jira со обработка на поврзаниот изворен код во Bitbucket. Во оваа фаза, Integro почна да има свои работни текови за работа со задачи од различни типови. 

Поради зголемувањето на автоматизацијата во деловните процеси, зголемен е бројот на проекти и работи во Teamcity. Така се појави нов проблем: еден бесплатен примерок на Teamcity не беше доволен (3 агенти и 100 проекти), додадовме уште еден пример (уште 3 агенти и 100 проекти), потоа уште еден. Како резултат на тоа, завршивме со систем од неколку кластери, што беше тешко да се управува:

Од скрипти до нашата сопствена платформа: како го автоматизиравме развојот во CIAN

Кога се појави прашањето за 4-та инстанца, сфативме дека не можеме да продолжиме да живееме вака, бидејќи вкупните трошоци за поддршка на 4 примероци веќе не беа во никакви граници. Се појави прашањето за купување на платен Teamcity или избор на бесплатен Џенкинс. Направивме пресметки за инстанци и планови за автоматизација и одлучивме дека ќе живееме на Џенкинс. По неколку недели, се префрливме на Џенкинс и елиминиравме дел од главоболката поврзана со одржувањето на повеќе примероци на Teamcity. Затоа, можевме да се фокусираме на развивање на Integro и прилагодување на Џенкинс за себе.

Со растот на основната автоматизација (во форма на автоматско креирање барања за повлекување, собирање и објавување на покривање на код и други проверки), постои силна желба да се напуштат рачните изданија колку што е можно повеќе и да се даде оваа работа на роботите. Дополнително, компанијата почна да се движи кон микросервиси во рамките на компанијата, кои бараа чести изданија, и одделно едни од други. Така постепено дојдовме до автоматско ослободување на нашите микросервиси (моментално го ослободуваме монолитот рачно поради сложеноста на процесот). Но, како што обично се случува, се појави нова сложеност. 

Ние го автоматизираме тестирањето

Од скрипти до нашата сопствена платформа: како го автоматизиравме развојот во CIAN

Поради автоматизацијата на изданијата, развојните процеси се забрзани, делумно поради прескокнувањето на некои фази на тестирање. И ова доведе до привремено губење на квалитетот. Звучи тривијално, но заедно со забрзувањето на изданијата, неопходно беше да се промени методологијата за развој на производот. Требаше да се размислува за автоматизација на тестирањето, всадување лична одговорност (тука зборуваме за „прифаќање на идејата во главата“, а не парични казни) на развивачот за објавениот код и грешки во него, како и одлуката за ослободување/не ослободување задача преку автоматско распоредување. 

Елиминирајќи ги проблемите со квалитетот, дојдовме до две важни одлуки: почнавме да спроведуваме тестирање на канари и воведовме автоматско следење на позадината на грешката со автоматски одговор на нејзиниот вишок. Првото решение овозможи да се најдат очигледни грешки пред кодот целосно да се пушти во производство, второто го намали времето на одговор на проблемите во производството. Грешките, се разбира, се случуваат, но најголемиот дел од времето и напорот го трошиме не за да ги исправиме, туку да ги минимизираме. 

Тим за автоматизација

Во моментов имаме персонал од 130 програмери и продолжуваме растат. Тимот за континуирана интеграција и испорака на кодови (во натамошниот текст: Deploy and Integration или DI тим) се состои од 7 луѓе и работи во 2 насоки: развој на платформата за автоматизација Integro и DevOps. 

DevOps е одговорен за Dev/Beta околината на страницата CIAN, околината Integro, им помага на програмерите да ги решат проблемите и развиваат нови пристапи за средини за скалирање. Насоката за развој на Integro се занимава и со самиот Integro и со сродни услуги, на пример, приклучоци за Jenkins, Jira, Confluence, а исто така развива помошни комунални услуги и апликации за развојните тимови. 

Тимот DI соработува со тимот на Платформа, кој внатрешно ги развива архитектурата, библиотеките и развојните пристапи. Во исто време, секој развивач во CIAN може да придонесе за автоматизација, на пример, да направи микро-автоматизација за да одговара на потребите на тимот или да сподели одлична идеја за тоа како да се направи автоматизација уште подобра.

Слојна торта на автоматизација во CIAN

Од скрипти до нашата сопствена платформа: како го автоматизиравме развојот во CIAN

Сите системи вклучени во автоматизацијата можат да се поделат на неколку слоеви:

  1. Надворешни системи (Jira, Bitbucket, итн.). Развојните тимови работат со нив.
  2. Интегра платформа. Најчесто, програмерите не работат директно со него, но тоа е она што ја одржува целата автоматизација да работи.
  3. Услуги за испорака, оркестрација и откривање (на пример, Џекнинс, Конзул, Номад). Со нивна помош, распоредуваме код на серверите и обезбедуваме услугите да работат едни со други.
  4. Физички слој (сервери, ОС, поврзан софтвер). Нашиот код работи на ова ниво. Ова може да биде или физички сервер или виртуелен (LXC, KVM, Docker).

Врз основа на овој концепт, ние ги делиме областите на одговорност во тимот на DI. Првите две нивоа се во областа на одговорноста на насоката за развој на Integro, а последните две нивоа се веќе во областа на одговорноста на DevOps. Ова раздвојување ни овозможува да се фокусираме на задачите и не се меша во интеракцијата, бидејќи сме блиски еден до друг и постојано разменуваме знаење и искуство.

Непроменети

Ајде да се фокусираме на Integro и да започнеме со технолошкиот куп:

  • CentOs 7
  • Докер + Номад + Конзул + Свод
  • Java 11 (стариот монолит на Integro ќе остане на Java 8)
  • Spring Boot 2.X + Spring Cloud Config
  • PostgreSql 11
  • Зајакот MQ 
  • Apache Ignite
  • Камунда (вградена)
  • Графана + Графит + Прометеј + Јегер + ЕЛК
  • Web UI: React (CSR) + MobX
  • ДЗС: Клучник

Ние се придржуваме до принципот на развој на микросервис, иако имаме наследство во форма на монолит од раната верзија на Integro. Секој микросервис работи во својот Docker контејнер, а услугите комуницираат едни со други преку HTTP барања и RabbitMQ пораки. Микросервисите се пронаоѓаат меѓусебно преку конзулот и поднесуваат барање до него, пренесувајќи овластување преку ДЗС (Keycloak, OAuth 2/OpenID Connect).

Од скрипти до нашата сопствена платформа: како го автоматизиравме развојот во CIAN

Како пример од реалниот живот, размислете за интеракција со Џенкинс, која се состои од следните чекори:

  1. Микросервисот за управување со работниот тек (во натамошниот текст како микросервис за проток) сака да изврши градба во Џенкинс. За да го направите ова, тој го користи конзулот за да ја пронајде IP:PORT на микросервисот за интеграција со Џенкинс (во натамошниот текст како микросервис Џенкинс) и испраќа асинхроно барање до него да започне изградбата во Џенкинс.
  2. Откако ќе добие барање, микросервисот Џенкинс генерира и одговара со ИД за работа, кој потоа може да се користи за да се идентификува резултатот од работата. Во исто време, ја активира изградбата во Џенкинс преку повик REST API.
  3. Џенкинс ја извршува изградбата и, по завршувањето, испраќа веб-кука со резултатите од извршувањето до микросервисот Џенкинс.
  4. Микросервисот Џенкинс, откако ја доби веб-куката, генерира порака за завршување на обработката на барањата и ги прикачува резултатите од извршувањето на неа. Генерираната порака се испраќа до редот на RabbitMQ.
  5. Преку RabbitMQ, објавената порака стигнува до микросервисот Flow, кој дознава за резултатот од обработката на својата задача со усогласување на Job ID од барањето и добиената порака.

Сега имаме околу 30 микросервиси, кои можат да се поделат во неколку групи:

  1. Управување со конфигурација.
  2. Информации и интеракција со корисниците (месинџери, пошта).
  3. Работа со изворниот код.
  4. Интеграција со алатки за распоредување (џенкинс, номад, конзул, итн.).
  5. Следење (изданија, грешки, итн.).
  6. Веб комунални услуги (УИ за управување со тест околини, собирање статистики, итн.).
  7. Интеграција со тракери за задачи и слични системи.
  8. Управување со работниот тек за различни задачи.

Задачи на работниот тек

Integro ги автоматизира активностите поврзани со животниот циклус на задачите. Во поедноставени термини, животниот циклус на задачата ќе се разбере како работниот тек на задачата во Jira. Нашите развојни процеси имаат неколку варијации на работниот тек во зависност од проектот, видот на задачата и опциите избрани во одредена задача. 

Да го погледнеме работниот тек што најчесто го користиме:

Од скрипти до нашата сопствена платформа: како го автоматизиравме развојот во CIAN

На дијаграмот, запчаникот покажува дека транзицијата се повикува автоматски со Интегра, додека човечката фигура покажува дека транзицијата се повикува рачно од страна на лице. Ајде да погледнеме неколку патеки што може да ги помине една задача во овој работен тек.

Целосно рачно тестирање на DEV+BETA без тестови за канаринци (обично вака ослободуваме монолит):

Од скрипти до нашата сопствена платформа: како го автоматизиравме развојот во CIAN

Може да има и други комбинации на транзиција. Понекогаш патот по кој ќе оди проблемот може да се избере преку опции во Jira.

Движење на задачата

Ајде да ги погледнеме главните чекори што се изведуваат кога задачата се движи низ работниот тек „Тестирање на DEV + Тестови за канаринци“:

1. Програмерот или PM ја креираат задачата.

2. Програмерот ја презема задачата да работи. По завршувањето, се префрла на статус ВО ПРЕГЛЕД.

3. Jira испраќа Webhook до микросервисот Jira (одговорен за интеграција со Jira).

4. Микросервисот Jira испраќа барање до услугата Flow (одговорна за внатрешните работни текови во кои се извршува работата) за да го започне работниот тек.

5. Внатре во услугата Flow:

  • Рецензентите се доделени на задачата (Микросервис за корисници што знае сè за корисниците + микросервис Jira).
  • Преку микросервисот Source (знае за складишта и гранки, но не работи со самиот код), се врши пребарување на складишта кои содржат гранка на нашето издание (за да се поедностави пребарувањето, името на филијалата се совпаѓа со проблемот број во Jira). Најчесто, задачата има само една гранка во едно складиште; ова го поедноставува управувањето со редот за распоредување и ја намалува поврзаноста помеѓу складиштата.
  • За секоја пронајдена гранка, се врши следнава низа на дејства:

    з) Ажурирање на главната гранка (Git microservice за работа со код).
    ii) Филијалата е блокирана од промени од страна на развивачот (Bitbucket microservice).
    iii) Се креира барање за повлекување за оваа гранка (микросервис Bitbucket).
    iv) Порака за ново барање за повлекување е испратена до разговори за развивачи (Извести микросервис за работа со известувања).
    v) Задачите за градење, тестирање и распоредување се започнуваат на DEV (микросервис Џенкинс за работа со Џенкинс).
    vi) Ако сите претходни чекори се успешно завршени, тогаш Integro го става своето Одобрување во барањето за повлекување (микросервис Bitbucket).

  • Integro чека Одобрување во барањето за повлекување од назначените рецензенти.
  • Веднаш штом ќе се добијат сите потребни одобренија (вклучувајќи ги и автоматските тестови поминаа позитивно), Integro ја пренесува задачата во статусот Тест на Dev (Jira microservice).

6. Тестерите ја тестираат задачата. Ако нема проблеми, тогаш задачата се пренесува во статусот Ready For Build.

7. Integro „гледа“ дека задачата е подготвена за ослободување и го започнува нејзиното распоредување во режим на канари (микросервис Џенкинс). Подготвеноста за ослободување се одредува со збир на правила. На пример, задачата е во бараниот статус, нема брави за други задачи, моментално нема активни прикачувања на овој микросервис итн.

8. Задачата е префрлена во статус Канарски (Jira microservice).

9. Џенкинс започнува задача за распоредување преку Номад во режим на канари (обично 1-3 случаи) и ја известува услугата за следење на објавувањето (микросервис DeployWatch) за распоредувањето.

10. Микросервисот DeployWatch ја собира позадината на грешката и реагира на неа, доколку е потребно. Ако позадината на грешката е надмината (нормата за заднина се пресметува автоматски), програмерите се известуваат преку микросервисот Notify. Ако по 5 минути развивачот не одговори (кликна на Врати или Остани), тогаш се активира автоматско враќање на примероците на канари. Ако позадината не е надмината, тогаш програмерот мора рачно да го стартува распоредувањето на задачата во Production (со кликнување на копче во интерфејсот). Ако во рок од 60 минути развивачот не го стартува распоредувањето во Производство, тогаш и канарските примероци ќе се вратат назад од безбедносни причини.

11. По започнувањето на распоредувањето во Производство:

  • Задачата е префрлена во статус на Производство (Jira microservice).
  • Микросервисот Џенкинс го започнува процесот на распоредување и ја известува микросервисот DeployWatch за распоредувањето.
  • Микросервисот DeployWatch проверува дали сите контејнери на Production се ажурирани (имаше случаи кога не беа ажурирани сите).
  • Преку микросервисот Notify, известување за резултатите од распоредувањето се испраќа до Производство.

12. Програмерите ќе имаат 30 минути да почнат да враќаат задача од Производство ако се открие неправилно однесување на микросервис. По ова време, задачата автоматски ќе се спои во мастер (Git microservice).

13. По успешното спојување во господар, статусот на задачата ќе се смени во Затворена (Jira microservice).

Дијаграмот не се преправа дека е целосно детален (во реалноста има уште повеќе чекори), но ви овозможува да го процените степенот на интеграција во процесите. Оваа шема не ја сметаме за идеална и ги подобруваме процесите на автоматско ослободување и поддршка за распоредување.

Што е следно

Имаме големи планови за развој на автоматизација, на пример, елиминирање на рачните операции за време на монолитни изданија, подобрување на следењето при автоматско распоредување и подобрување на интеракцијата со програмерите.

Но, да застанеме овде засега. Површно опфативме многу теми во прегледот на автоматизацијата, некои воопшто не беа допрени, па со задоволство ќе одговориме на прашања. Очекуваме предлози што да покриеме детално, пишете во коментар.

Извор: www.habr.com

Купете доверлив хостинг за сајтови со DDoS заштита, VPS VDS сервери 🔥 Купете сигурен веб-хостинг со DDoS заштита, VPS VDS сервери | ProHoster