
RIT 2019-da əməkdaşımız Aleksandr Korotkov avtomatlaşdırma haqqında danışdı CİAN-da inkişaf üçün: işimizi asanlaşdırmaq məqsədilə öz platformamız Integro-dan istifadə edirik. Bu platforma tapşırıqların həyat dövrünü izləyir, inkişafçılardan gündəlik əməliyyatları götürərək production-da olan xəta sayını əhəmiyyətli dərəcədə azaldır. Bu yazıda Aleksandrın təqdimatını tamamlayacaq və sadə skriptlərdən öz platformamız vasitəsilə open source məhsulların birləşdirilməsi yolunu necə gəzdiyimizi, habelə avtomatlaşdırma üzrə xüsusi komandamızın nələr etdiyini izah edəcəyik.
Sıfır səviyyəsi
«Sıfır səviyyəsi olmur, belə bir şey tanımıram»
Şifu Usta, «Kung Fu Panda» cizgi filmindən
CİAN-da avtomatlaşdırma şirkət qurulandan 14 il sonra başlayıb. O zaman inkişaf komandasında 35 insan vardı. Düşünmək çətindir, düzdür? Əlbəttə ki, müəyyən bir dərəcədə avtomatlaşdırma mövcud idi, lakin davamlı inteqrasiya və kodun çatdırılması üzrə ayrı bir istiqamət 2015-ci ildən formalaşmağa başladı.
O vaxt bizim Python, C# və PHP-dən ibarət böyük bir monolit var idi, Linux/Windows serverlərində yerləşdirilmişdi. Bu canavarı yerləşdirmək üçün əl ilə işə saldığımız skriptlərdən ibarət bir toplanmamız var idi. Həmçinin monolitin qurulması da var idi, bu isə budaqların birləşdirilməsində konfliktlər, qüsurların düzəlişi və «digər tapşırıqlar ilə yenidən qurulma» səbəbindən ağrı və əzab gətirirdi. Sadə ifadə ilə proses belə görünürdü:

Bundan məmnun deyildik və təkrarlana bilən, avtomatlaşdırılmış və idarə olunan bir qurma və yerləşdirmə prosesi yaratmaq istəyirdik. Bunun üçün CI/CD sisteminə ehtiyacımız var idi və pulsuz versiya olan Teamcity ilə pulsuz Jenkins arasında seçim edirdik, çünki onlarla işləyirdik və hər ikisi funksiyaları üzrə bizi qane edirdi. Daha yeni bir məhsul olduğu üçün Teamcity-ni seçdik. O zaman mikrosistem arxitekturasından istifadə etmirdik və çox sayda tapşırıqlar və layihələr gözləmirdik.
Öz sistemimizin ideyasına gəlirik
Teamcity-nin tətbiqi yalnız bir hissəsini əl işindən çıxardı: hələ də Pull Request-lərin yaradılması, Jira-da tapşırıqların statuslarına irəliləməsi, buraxılış üçün tapşırıqların seçilməsi qalırdı. Teamcity bu işlərin öhdəsindən gəlmirdi. Daha da avtomatlaşdırma yolu seçilməli idi. Teamcity-də skriptlərlə işləmə variantlarını və ya xarici avtomatlaşdırma sistemlərinə keçidi nəzərdən keçirdik. Ancaq nəticədə qərara aldıq ki, yalnız öz həllimizlə əldə edilən maksimal çeviklik lazımdır. Beləliklə, Integro adlı daxili avtomatlaşdırma sisteminin ilk versiyası yarandı.
Teamcity, yığma və yerləşdirmə proseslərinin avtomatlaşdırılması ilə məşğuldur, Integro isə proqram inkişaf proseslərinin üst səviyyədə avtomatlaşdırılmasına fokuslandı. Jira-da tapşırıq işləməyi Bitbucket-da əlaqəli mənbə kodu ilə birləşdirmək lazım idi. Bu mərhələdə Integro daxilində müxtəlif növ tapşırıqlar üçün öz iş axınları yaranmağa başladı.
Biznes proseslərində avtomatlaşdırmanın artması ilə birlikdə Teamcity-də layihələrin və run-ların sayı artdı. Beləliklə yeni bir problem ortaya çıxdı: bir pulsuz Teamcity instansiyası (3 agent və 100 layihə) artıq yetərli olmurdu, biz əlavə bir instansiya (daha 3 agent və 100 layihə) əlavə etdik, sonra bir daha. Nəticədə çətin idarə olunan bir neçə klasterdən ibarət sistem əldə etdik:

4-cü instansiya ilə bağlı sual ortaya çıxanda, bildik ki, bu cür yaşamağın mümkünsüz olduğu, çünki 4 instansiyanın dəstəklənməsi üçün cəmi xərclər artıq heç bir çərçivəyə sığmırdı. Pulsuz Jenkins-i seçmək və ya ödənişli Teamcity almaq barədə sual yarandı. Instansiyalar və avtomatlaşdırma planları üzərində hesablamalar aparıb, Jenkins-də yaşamağa qərar verdik. Bir neçə həftədən sonra Jenkins-ə keçdik və bir neçə Teamcity instansiyasını dəstəkləmə ilə bağlı olan bəzi ağrılardan qurtulmuş olduq. Beləliklə, Integro inkişafına və Jenkins-dən özümüzə uyğunlaşdırmağa daha çox fokuslana bildik.
Əsas avtomatlaşdırmanın artması ilə ( avtomatik Pull Request-lərin yaradılması, Code coverage-in yığılması və dərc edilməsi və digər yoxlamalar) əl ilə buraxılışlardan mümkün qədər imtina etmək və bu işi robotlara vermək istəyi yarandı. Bundan əlavə, şirkət daxilində mikroservislərə keçid başladı ki, bu da müstəqil şəkildə tez-tez buraxılışları tələb edirdi. Beləliklə, biz tədricən mikroservislərimizin avtomatik buraxılışlarına gəldik (monolit prosesin mürəkkəbliyi səbəbindən əl ilə buraxılır). Ancaq adətən olduğu kimi, yeni çətinliklər yarandı.
Testlərin avtomatlaşdırılması

Buraxılışların avtomatlaşdırılması inkişaf proseslərini sürətləndirdi, bir hissəsi isə bəzi test mərhələlərinin atlanması hesabına baş verdi. Bu da keyfiyyətin müvəqqəti itirilməsinə səbəb oldu. Banal səslənir, amma buraxılışların sürətlənməsi ilə məhsul inkişaf metodologiyasını da dəyişmək vacib idi. Testlərin avtomatlaşdırılması, inkişaf etdiricinin buraxılan kod və içindəki səhvlərə görə fərdi məsuliyyətini (burada söhbət «başda ideyaya qəbul» haqqında gedir, maliyyə cərimələri deyil) nəzərə almaq və avtomatik yerləşdirmə vasitəsilə tapşırıqın buraxılması / buraxılmaması qərarını verməyə düşünmək lazım idi.
Keyfiyyət problemlərini aradan qaldırarkən iki mühüm qərara gəldik: kanar testləri keçirməyə başladıq və avtomatik monitorinq sistemini tətbiq etdik ki, bu da onun aşılmasına avtomatik cavab verməyi təmin edir. Birinci qərar, kodun production-a tam girişindən əvvəl açıq səhvləri tapmağa kömək etdi, ikinci isə production-da problemlərə reaksiyaların vaxtını azaltdı. Səhvlər əlbəttə var, amma biz vaxtımızın və enerjimizin daha çoxunu düzəltməyə deyil, minimallaşdırmağa sərf edirik.
Avtomatlaşdırma komandası
İndi 130 inkişaf etdiricidən ibarət komandamız var və biz davam edirik . Davamlı inteqrasiya və kod çatdırılması komandası (daha sonra — Deploy and Integration komandası və ya DI) 7 nəfərdən ibarətdir və 2 istiqamətdə çalışır: Integro avtomatlaşdırma platformasının inkişafı və DevOps.
DevOps, CIAN saytının Dev/Beta mühitinə, Integro mühitinə cavabdehdir, inkişaf etdiricilərə problemlərinin həllində kömək edir və mühitlərin ölçeklənməsi üçün yeni yanaşmalar hazırlayır. Integro inkişafı həm Integro-nun özünü, həm də Jenkins, Jira, Confluence kimi əlaqəli xidmətləri, eləcə də inkişaf komandaları üçün köməkçi dəst və tətbiqlər hazırlayır.
DI komandası, şirkət daxilində arxitektura, kitabxanalar və inkişaf yanaşmaları üzərində işləyən Platform komandası ilə birgə fəaliyyət göstərir. Bununla yanaşı, CIAN içərisində hər bir inkişaf etdirici avtomatlaşdırmaya töhfə verə bilər, məsələn, komandanın ehtiyaclarına uyğun mikroavtomatlaşdırma həyata keçirə bilər və ya avtomatlaşdırmanı daha yaxşı etmək üçün gözəl bir ideya paylaşa bilər.
CIAN-da avtomatlaşdırma layneri

Avtomatlaşdırmada istifadə olunan bütün sistemləri bir neçə layə ayırmaq mümkündür:
- Xarici sistemlər (Jira, Bitbucket və s.). Onlarla inkişaf etdirici komandalar işləyir.
- Integro Platforması. Çox vaxt inkişaf etdiricilər bu ilə birbaşa işləmirlər, lakin avtomatlaşdırmanın bütün işini dəstəkləyir.
- Çatdırılma, orkestrasiya və aşkar etmə xidmətləri (məsələn, Jenkins, Consul, Nomad). Onların köməyi ilə kodu serverlərdə yerləşdirir və xidmətlərin bir-biri ilə işləməsini təmin edirik.
- Fiziki səviyyə (serverlər, OS, əlaqəli proqram təminatı). Bu səviyyədə kodumuz işləyir. Bu, fiziki bir server, həm də virtual (LXC, KVM, Docker) ola bilər.
Bu konsepsiyadan irəliləyərək DI komandası içərisində məsuliyyət sahələrini bölürük. İlk iki səviyyə Integro inkişafı istiqamətinin məsuliyyətində, son iki səviyyə isə DevOps-un məsuliyyətindədir. Belə bir bölünmə vəzifələrə fokuslanmağa imkan tanıyır və qarşılıqlı fəaliyyətə mane olmur, çünki biz bir-birimizlə yan-yana dayanırıq və davamlı olaraq bilik və təcrübə mübadiləsi edirik.
Integro
Integro-ya fokuslanaq və texnoloji yığınla başlayaq:
- CentOs 7
- Docker + Nomad + Consul + Vault
- Java 11 (köhnə Integro monoliti Java 8-də qalacaq)
- Spring Boot 2.X + Spring Cloud Config
- PostgreSql 11
- RabbitMQ
- Apache Ignite
- Camunda (embedded)
- Grafana + Graphite + Prometheus + Jaeger + ELK
- Web UI: React (CSR) + MobX
- SSO: Keycloak
Mikroservis inkişafı prinsipinə riayət edirik, baxmayaraq ki, Integro-nun əvvəlki versiyası kimi bir monolit olan mirasımız da var. Hər bir mikroservis öz docker konteynerində işləyir, servislər bir-biri ilə HTTP sorğuları və RabbitMQ mesajları vasitəsilə ünsiyyət qururlar. Mikroservislər bir-birini Consul vasitəsilə tapır və ona sorğu göndərirlər, SSO (Keycloak, OAuth 2/OpenID Connect) vasitəsilə identifikasiya olunurlar.

Real bir misal olaraq Jenkins ilə qarşılıqlı əlaqəni aşağıdakı mərhələlərdən ibarət nəzərdən keçirək:
- Workflow idarəetmə mikroservisi (sonrakı Flow mikroservisi) Jenkins-də bir yığıncaq başlatmaq istəyir. Bunun üçün Consul vasitəsilə Jenkins-in inteqrasiya mikroservisinin IP:PORT ünvanını tapır və Jenkins-də yığıncağın başlanması üçün ona asinxron bir sorğu göndərir.
- Jenkins mikroservisi sorğunu aldıqdan sonra tapşırığın nəticəsini tanımaq üçün istifadə ediləcək İş ID-sini formalaşdırır və cavab olaraq təqdim edir. Bununla yanaşı, Jenkins-də yığıncağı başlatmaq üçün REST API-dən çağırış edir.
- Jenkins, yığıncağı başa çatdırdıqdan sonra Jenkins mikroservisinə nəticələri ilə birlikdə webhook göndərir.
- Jenkins mikroservisi webhook-u aldıqdan sonra sorğunun işlənməsinin başa çatması haqqında məlumat mesajını formalaşdırır və nəticələri ona əlavə edir. Formalaşdırılmış mesaj RabbitMQ növbəsinə göndərilir.
- RabbitMQ vasitəsilə yayımlanan mesaj Flow mikroservisinə çatır, bu da öz tapşırığının nəticəsi haqqında məlumat alır, sorğudakı İş ID-si ilə alınan mesajı uyğunlaşdıraraq.
Hazırda 30-a qədər mikroservisimiz var ki, bunları bir neçə qrupa ayırmaq mümkündür:
- Konfiqurasiyaların idarə edilməsi.
- İstifadəçilərlə məlumat mübadiləsi və qarşılıqlı əlaqə (messenger, e-poçt).
- Mənbə kodu ilə iş.
- Yayım alətləri ilə inteqrasiya (Jenkins, Nomad, Consul və s.).
- İzləmə (buraxılışlar, xətalar və s.).
- Web alətləri (test mühitlərinin idarəsi üçün UI, statistikaların toplanması və s.).
- Tapşırıq izləyiciləri və bənzər sistemlərlə inteqrasiya.
- Müxtəlif tapşırıqlar üçün workflow-un idarə edilməsi.
Tapşırığın workflow-u
Integro, tapşırığın həyat dövrü ilə bağlı hərəkətləri avtomatlaşdırır. Sadələşdirilmiş olaraq tapşırığın həyat dövrünü Jira-dakı tapşırığın workflow-u olaraq başa düşürük. Bizim inkişaf proseslərimizdə layihəyə, tapşırığın növünə və konkret tapşırıqda seçilmiş seçimlərə görə bir neçə workflow variantı var.
Çox istifadə etdiyimiz workflow-u nəzərdən keçirək:

Cədvəldəyken dişli, transition-un Integro tərəfindən avtomatik olaraq çağırıldığını göstərir, insan fiquru isə transition-un insan tərəfindən əl ilə çağırıldığını ifadə edir. Bir neçə yol ümumi axında (workflow) məsələnin keçə biləcəyini nəzərdən keçirək.
Tamamilə əl ilə test mühitində DEV+BETA kanarı testləri olmadan (adətən monolitləri belə buraxırıq):

Transition-un digər kombinasyonları da ola bilər. Bəzən məsələnin keçəcəyi yolu Jira-dakı seçimlərlə seçmək mümkündür.
Məsələnin hərəkəti
DEV + kanarı testlərində məsələni hərəkət etdirmək üçün icra olunan əsas mərhələləri nəzərdən keçirək:
1. İnkişafçı və ya PM məsələ yaradır.
2. İnkişafçı məsələni işə götürür. Tamamlandıqdan sonra onu IN REVIEW statusuna keçirir.
3. Jira, Jira-mikroservisinə Webhook göndərir (Jira ilə inteqrasiya üçün məsuliyyət daşıyır).
4. Jira-mikroservisi, workflow-u başlatmaq üçün Flow-servisinə sorğu göndərir (işin yerinə yetirildiyi daxili iş axınlarından məsuldur).
5. Flow-servisinin daxilində:
- Məsələyə revyuverlər təyin edilir (İstifadəçilər-mikroservisi, bütün istifadəçilər haqqında məlumatları bilən + Jira-mikroservisi).
- Source-mikroservisindən (repo və budaqlar haqqında məlumatı bilən, amma kodun özü ilə işləmir) məsələmizin budağı olan repo-ları tapmağa çalışır (axtarışı asanlaşdırmaq üçün budaq adı Jira-dakı məsələ nömrəsi ilə üst-üstə düşür). Adətən, məsələ yalnız bir budağa malik olsa, bu, dəploy üzrə sıranın idarə olunmasını asanlaşdırır və repo-lar arasında bağlılığı azaldır.
- Hər bir tapılan budaq üçün belə bir ardıcıllıqla addımlar icra olunur:
i) Master-budağa əlavə edilmə (Kodla iş üçün Git-mikroservisi).
ii) Budaq inkişafçı tərəfindən dəyişikliklərdən qorunur (Bitbucket-mikroservisi).
iii) Bu budaq üçün Pull Request yaradılır (Bitbucket-mikroservisi).
iv) İnkişafçıların chatlarına yeni Pull Request haqqında mesaj göndərilir (Olayların bildirişi üçün Notify-mikroservisi).
v) Məsələnin DEV-də yığılması, test edilməsi və daşıma işləri başlatılır (Jenkins-mikroservisi Jenkins ilə iş üçün).
vi) Əgər bütün əvvəlki nöqtələr uğurla başa çatarsa, Integro Pull Request-də özünü təsdiq edir (Bitbucket-mikroservisi). - Integro təyin olunan revyuverlərdən Pull Request-də təsdiq gözləyir.
- Lazımi təsdiqlər alındıqda (o cümlədən avtomatlaşdırılmış testlər müsbət keçirildikdə), Integro məsələni Test on Dev statusuna keçirir (Jira-mikroservisi).
6. Testçilər vəzifənin testini aparırlar. Əgər problem yoxdursa, vəzifəni Ready For Build statusuna keçirirlər.
7. Integro görür ki, vəzifə buraxılışa hazırdır və onu kanar rejimində (Jenkins-mikroservis) yerləşdirməyə başlayır. Buraxılışa hazır olma bir sıra qaydalarla müəyyən edilir. Məsələn, vəzifə lazım olan statusdadır, digər vəzifələrdə heç bir blokaj yoxdur, hazırda bu mikroservis üçün aktiv göndərişlər yoxdur və s.
8. Vəzifə Canary statusuna keçirilir (Jira-mikroservis).
9. Jenkins, Nomad vasitəsi ilə vəzifəni kanar rejimində (ümumiyyətlə 1-3 instans) yerləşdirir və buraxılış izləmə xidməti (DeployWatch-mikroservis) ilə məlumat verir.
10. DeployWatch-mikroservisi xəta fonunu toplayır və gerek olarsa ona reaksiya verir. Xəta fonu aşılarsa (norma avtomatik hesablanır), inkişaf etdiricilərə Notify-mikroservisi vasitəsi ilə məlumat verilir. Əgər 5 dəqiqə ərzində inkişaf etdirici reaksiya verməzsə (Revert və ya Stay düyməsini basmazsa), kanar instansların avtomatik geri alınması başlayır. Əgər fon aşılmayıbsa, inkişaf etdirici, vəzifəni Production-da əl ilə yerləşdirməlidir (UI-da düyməni basaraq). Əgər 60 dəqiqə ərzində inkişaf etdirici Production-da yerləşdirməyi başlatmazsa, kanar instanslar təhlükəsizlik məqsədilə də geri alınacaq.
11. Production-da yerləşdirməyə başlandıqdan sonra:
- Vəzifə Production statusuna keçirilir (Jira-mikroservis).
- Jenkins-mikroservisi yerləşdirmə prosesini başlatır və DeployWatch-mikroservisinə buraxılış haqda məlumat verir.
- DeployWatch-mikroservisi Production-da bütün konteynerlərin yeniləndiyini yoxlayır (bəzən bütün konteynerlər yenilənmir).
- Notify-mikroservisi vasitəsi ilə Production-da yerləşdirmənin nəticələri barədə məlumat göndərilir.
12. İnkişaf etdiricilər, mikroservisin səhv davranışını aşkar etdikdə Production-dan vəzifəni geri almaq üçün 30 dəqiqəyə malikdirlər. Bu vaxt bitdikdən sonra vəzifə avtomatik olan master (Git-mikroservis) daxil ediləcək.
13. Master-da uğurlu birleştirmədən sonra vəzifənin statusu Closed (Jira-mikroservis) olaraq dəyişdiriləcək.
Schema tam detallılığa iddia etmir (real olaraq daha çox addım var), amma proseslərdə inteqrasiya dərəcəsini qiymətləndirməyə imkan verir. Biz bu schemanı ideal saymırıq və buraxılışlar və yerləşdirmələrin avtomatik müşayiət edilmə proseslərini təkmilləşdiririk.
Növbəti nələrdir
Bizim avtomatlaşdırma inkişafı üçün böyük planlarımız var, məsələn, monolitin buraxılışlarında əl əməliyyatlarından imtina, avtomatik yerləşdirmədə monitorinqin yaxşılaşdırılması və inkişaf etdiricilərlə əlaqələrin güçləndirilməsi.
Amma burada dayanarığ. Avtomatlaşdırma ilə bağlı çox mövzuları üst səviyyədə əhatə etdik, bəzilərini tamamilə toxunmadıq, buna görə də suallarınıza məmnuniyyətlə cavab verəcəyik. İstədiyiniz məsələləri daha ətraflı işıqlandırmaq üçün şərhlərdə yazın.
Mənbə: habr.com
