Od skriptov k našej vlastnej platforme: ako sme automatizovali vývoj v CIAN

Od skriptov k našej vlastnej platforme: ako sme automatizovali vývoj v CIAN

Na RIT 2019 vyrobil náš kolega Alexander Korotkov správa o automatizácii vývoja v CIAN: na zjednodušenie života a práce využívame vlastnú platformu Integro. Sleduje životný cyklus úloh, odbremení vývojárov od rutinných operácií a výrazne zníži počet chýb vo výrobe. V tomto príspevku doplníme Alexandrovu správu a povieme vám, ako sme prešli od jednoduchých skriptov ku kombinovaniu produktov s otvoreným zdrojovým kódom prostredníctvom našej vlastnej platformy a čo robí náš samostatný automatizačný tím.
 

Nulová úroveň

"Neexistuje nič také ako nulová úroveň, nič také nepoznám"
Majster Shifu z filmu "Kung Fu Panda"

Automatizácia v CIAN začala 14 rokov po založení spoločnosti. V tom čase bolo vo vývojovom tíme 35 ľudí. Ťažko uveriť, však? Samozrejme, automatizácia v určitej forme existovala, no v roku 2015 sa začal formovať samostatný smer pre nepretržitú integráciu a dodávanie kódu. 

V tom čase sme mali obrovský monolit Pythonu, C# a PHP nasadených na serveroch Linux/Windows. Na nasadenie tohto monštra sme mali sadu skriptov, ktoré sme spúšťali manuálne. Došlo aj k montáži monolitu, čo prinieslo bolesť a utrpenie v dôsledku konfliktov pri spájaní vetiev, opravách defektov a prestavbe „s inou sadou úloh v stavbe“. Zjednodušený proces vyzeral takto:

Od skriptov k našej vlastnej platforme: ako sme automatizovali vývoj v CIAN

Neboli sme s tým spokojní a chceli sme vytvoriť opakovateľný, automatizovaný a spravovateľný proces zostavovania a nasadenia. Na to sme potrebovali CI/CD systém a vyberali sme si medzi bezplatnou verziou Teamcity a bezplatnou verziou Jenkins, keďže sme s nimi pracovali a obe nám vyhovovali z hľadiska sady funkcií. Ako novší produkt sme si vybrali Teamcity. V tom čase sme ešte nepoužívali mikroservisnú architektúru a neočakávali sme veľké množstvo úloh a projektov.

Dostávame sa k myšlienke vlastného systému

Implementácia Teamcity odstránila iba časť manuálnej práce: čo zostalo, je vytváranie požiadaviek na stiahnutie, podpora problémov podľa stavu v Jira a výber problémov na vydanie. Systém Teamcity si s tým už nevedel poradiť. Bolo potrebné zvoliť cestu ďalšej automatizácie. Zvažovali sme možnosti práce so skriptami v Teamcity alebo prechod na automatizačné systémy tretích strán. Nakoniec sme sa však rozhodli, že potrebujeme maximálnu flexibilitu, ktorú môže poskytnúť iba naše vlastné riešenie. Takto sa objavila prvá verzia interného automatizačného systému s názvom Integro.

Teamcity sa zaoberá automatizáciou na úrovni spúšťania procesov budovania a nasadzovania, kým Integro sa zameralo na špičkovú automatizáciu vývojových procesov. Bolo potrebné skombinovať prácu s problematikou v Jira so spracovaním súvisiaceho zdrojového kódu v Bitbuckete. V tejto fáze Integro začalo mať svoje vlastné pracovné postupy pre prácu s úlohami rôznych typov. 

V dôsledku nárastu automatizácie v obchodných procesoch sa zvýšil počet projektov a behov v Teamcity. Prišiel teda nový problém: jedna bezplatná inštancia Teamcity nestačila (3 agenti a 100 projektov), ​​pridali sme ďalšiu inštanciu (3 agentov a 100 projektov navyše), potom ďalšiu. V dôsledku toho sme skončili so systémom niekoľkých klastrov, ktorý bolo ťažké riadiť:

Od skriptov k našej vlastnej platforme: ako sme automatizovali vývoj v CIAN

Keď sa objavila otázka 4. inštancie, uvedomili sme si, že takto nemôžeme ďalej žiť, pretože celkové náklady na podporu 4 inštancií už neboli v medziach. Vyvstala otázka o kúpe plateného Teamcity alebo výbere bezplatného Jenkinsa. Urobili sme výpočty inštancií a plánov automatizácie a rozhodli sme sa, že budeme žiť na Jenkins. Po niekoľkých týždňoch sme prešli na Jenkins a odstránili sme niektoré bolesti hlavy spojené s udržiavaním viacerých inštancií Teamcity. Preto sme sa mohli sústrediť na vývoj Integro a prispôsobenie Jenkins pre seba.

S rastom základnej automatizácie (vo forme automatického vytvárania Pull Requestov, zhromažďovania a zverejňovania pokrytia kódom a iných kontrol) existuje silná túžba čo najviac opustiť manuálne uvoľňovanie a dať túto prácu robotom. Okrem toho sa spoločnosť začala presúvať na mikroslužby v rámci spoločnosti, ktoré si vyžadovali časté vydania a oddelene od seba. Takto sme sa postupne dostali k automatickým vydaniam našich mikroslužieb (momentálne kvôli zložitosti procesu uvoľňujeme monolit manuálne). Ale, ako sa to zvyčajne stáva, vznikla nová zložitosť. 

Automatizujeme testovanie

Od skriptov k našej vlastnej platforme: ako sme automatizovali vývoj v CIAN

V dôsledku automatizácie vydaní sa vývojové procesy zrýchlili, čiastočne v dôsledku preskočenia niektorých fáz testovania. A to viedlo k dočasnej strate kvality. Znie to triviálne, no spolu so zrýchľovaním releasov bolo potrebné zmeniť aj metodiku vývoja produktu. Bolo potrebné myslieť na automatizáciu testovania, navodenie osobnej zodpovednosti (tu hovoríme o „prijatí myšlienky do hlavy“, nie peňažných pokutách) vývojára za uvoľnený kód a chyby v ňom, ako aj rozhodnutie uvoľniť/neuvoľniť úlohu prostredníctvom automatického nasadenia. 

Po odstránení problémov s kvalitou sme dospeli k dvom dôležitým rozhodnutiam: začali sme vykonávať testovanie kanárikov a zaviedli sme automatické monitorovanie pozadia chyby s automatickou reakciou na jej prekročenie. Prvé riešenie umožnilo nájsť zjavné chyby ešte pred úplným uvoľnením kódu do výroby, druhé skrátilo čas odozvy na problémy vo výrobe. Chyby sa, samozrejme, stávajú, ale väčšinu času a úsilia netrávime ich opravou, ale minimalizáciou. 

Automatizačný tím

V súčasnosti zamestnávame 130 vývojárov a pokračujeme ďalej rásť, pestovať. Tím pre kontinuálnu integráciu a doručovanie kódu (ďalej len Deploy and Integration alebo DI tím) pozostáva zo 7 ľudí a pracuje v 2 smeroch: vývoj automatizačnej platformy Integro a DevOps. 

DevOps je zodpovedný za Dev/Beta prostredie stránky CIAN, prostredie Integro, pomáha vývojárom riešiť problémy a vyvíja nové prístupy k škálovaniu prostredí. Vývojový smer Integro sa zaoberá tak samotným Integrom, ako aj súvisiacimi službami, napríklad pluginy pre Jenkins, Jira, Confluence, a tiež vyvíja pomocné nástroje a aplikácie pre vývojové tímy. 

Tím DI spolupracuje s tímom Platformy, ktorý interne vyvíja architektúru, knižnice a vývojové prístupy. Zároveň môže každý vývojár v rámci CIAN prispieť k automatizácii, napríklad vytvoriť mikroautomatizáciu podľa potrieb tímu alebo zdieľať skvelý nápad, ako automatizáciu ešte vylepšiť.

Vrstvený koláč automatizácie v CIAN

Od skriptov k našej vlastnej platforme: ako sme automatizovali vývoj v CIAN

Všetky systémy zapojené do automatizácie možno rozdeliť do niekoľkých vrstiev:

  1. Externé systémy (Jira, Bitbucket atď.). Pracujú s nimi vývojové tímy.
  2. Platforma Integro. Najčastejšie s ním vývojári nepracujú priamo, ale je to to, čo udržuje všetku automatizáciu v chode.
  3. Doručovacie, organizačné a vyhľadávacie služby (napríklad Jeknins, Consul, Nomad). S ich pomocou nasadzujeme kód na servery a zabezpečujeme, aby služby navzájom spolupracovali.
  4. Fyzická vrstva (servery, OS, súvisiaci softvér). Náš kód funguje na tejto úrovni. Môže to byť buď fyzický server alebo virtuálny server (LXC, KVM, Docker).

Na základe tohto konceptu rozdeľujeme oblasti zodpovednosti v rámci DI tímu. Prvé dve úrovne sú v oblasti zodpovednosti smerovania vývoja Integro a posledné dve úrovne sú už v oblasti zodpovednosti DevOps. Toto oddelenie nám umožňuje sústrediť sa na úlohy a nezasahuje do interakcie, keďže sme si blízko a neustále si vymieňame poznatky a skúsenosti.

Neporušené

Zamerajme sa na Integro a začnime s technologickým zásobníkom:

  • CentOS 7
  • Docker + Nomad + Consul + Vault
  • Java 11 (starý monolit Integro zostane na Java 8)
  • Spring Boot 2.X + Spring Cloud Config
  • PostgreSql 11
  • RabbitMQ 
  • Apache Ignite
  • Camunda (vložené)
  • Grafana + Grafit + Prometheus + Jaeger + ELK
  • Webové rozhranie: React (CSR) + MobX
  • SSO: Kľúčenka

Dodržiavame princíp vývoja mikroslužieb, aj keď máme dedičstvo vo forme monolitu ranej verzie Integro. Každá mikroslužba beží vo vlastnom kontajneri Docker a služby medzi sebou komunikujú prostredníctvom HTTP požiadaviek a správ RabbitMQ. Mikroslužby sa navzájom nájdu cez Consul a požiadajú ho o autorizáciu prostredníctvom SSO (Keycloak, OAuth 2/OpenID Connect).

Od skriptov k našej vlastnej platforme: ako sme automatizovali vývoj v CIAN

Ako príklad zo skutočného života zvážte interakciu s Jenkinsom, ktorá pozostáva z nasledujúcich krokov:

  1. Mikroslužba riadenia pracovného toku (ďalej len mikroslužba Flow) chce spustiť zostavu v Jenkins. Na tento účel pomocou služby Consul nájde IP:PORT mikroslužby na integráciu s Jenkins (ďalej len mikroslužba Jenkins) a odošle jej asynchrónnu požiadavku na spustenie zostavenia v Jenkins.
  2. Po prijatí požiadavky mikroslužba Jenkins vygeneruje a odpovie ID úlohy, ktoré sa potom môže použiť na identifikáciu výsledku práce. Zároveň spúšťa zostavu v Jenkins prostredníctvom volania REST API.
  3. Jenkins vykoná zostavenie a po dokončení odošle webhook s výsledkami vykonania mikroslužbe Jenkins.
  4. Mikroslužba Jenkins po prijatí webhooku vygeneruje správu o dokončení spracovania požiadavky a pripojí k nej výsledky vykonania. Vygenerovaná správa sa odošle do frontu RabbitMQ.
  5. Prostredníctvom RabbitMQ sa zverejnená správa dostane do mikroslužby Flow, ktorá sa dozvie o výsledku spracovania svojej úlohy zhodou Job ID z požiadavky a prijatej správy.

Teraz máme asi 30 mikroslužieb, ktoré možno rozdeliť do niekoľkých skupín:

  1. Správa konfigurácie.
  2. Informácie a interakcia s používateľmi (posielači, pošta).
  3. Práca so zdrojovým kódom.
  4. Integrácia s nástrojmi nasadenia (jenkins, nomád, konzul atď.).
  5. Monitorovanie (uvoľnenia, chyby atď.).
  6. Webové nástroje (UI na správu testovacích prostredí, zhromažďovanie štatistík atď.).
  7. Integrácia s nástrojmi na sledovanie úloh a podobnými systémami.
  8. Riadenie pracovného toku pre rôzne úlohy.

Úlohy pracovného toku

Integro automatizuje činnosti súvisiace s životným cyklom úlohy. Zjednodušene povedané, životný cyklus úlohy sa bude chápať ako pracovný tok úlohy v Jira. Naše vývojové procesy majú niekoľko variácií pracovného toku v závislosti od projektu, typu úlohy a možností vybraných v konkrétnej úlohe. 

Pozrime sa na pracovný postup, ktorý používame najčastejšie:

Od skriptov k našej vlastnej platforme: ako sme automatizovali vývoj v CIAN

V diagrame ozubené koliesko ukazuje, že prechod je automaticky vyvolaný Integrom, zatiaľ čo ľudská postava ukazuje, že prechod je vyvolaný manuálne osobou. Pozrime sa na niekoľko ciest, ktorými sa môže úloha v tomto pracovnom postupe uberať.

Úplne manuálne testovanie na DEV+BETA bez kanárskych testov (zvyčajne takto vydávame monolit):

Od skriptov k našej vlastnej platforme: ako sme automatizovali vývoj v CIAN

Môžu existovať aj iné kombinácie prechodov. Niekedy sa cesta, ktorou sa problém uberie, dá vybrať cez možnosti v Jira.

Pohyb úlohy

Pozrime sa na hlavné kroky, ktoré sa vykonávajú pri prechode úlohy cez pracovný postup „DEV Testing + Canary Tests“:

1. Vývojár alebo PM vytvorí úlohu.

2. Vývojár prevezme úlohu do práce. Po dokončení sa prepne do stavu PREHĽAD.

3. Jira odošle webhook mikroslužbe Jira (zodpovednej za integráciu s Jira).

4. Mikroslužba Jira odošle službe Flow (zodpovednej za interné pracovné toky, v ktorých sa práca vykonáva) požiadavku na spustenie pracovného toku.

5. V rámci služby Flow:

  • K úlohe sú priradení recenzenti (Mikroslužba používateľov, ktorá vie všetko o používateľoch + mikroslužba Jira).
  • Cez mikroslužbu Source (vie o repozitároch a vetvách, ale nepracuje so samotným kódom) sa vyhľadávajú repozitáre, ktoré obsahujú vetvu našej problematiky (pre zjednodušenie vyhľadávania sa názov pobočky zhoduje s danou problematikou číslo v Jira). Úloha má najčastejšie iba jednu vetvu v jednom úložisku, čo zjednodušuje správu frontu nasadenia a znižuje konektivitu medzi úložiskami.
  • Pre každú nájdenú vetvu sa vykoná nasledujúca postupnosť akcií:

    i) Aktualizácia hlavnej vetvy (mikroslužba Git pre prácu s kódom).
    ii) Vývojár (mikroslužba Bitbucket) zablokuje pobočku pred zmenami.
    iii) Pre túto pobočku (mikroslužba Bitbucket) sa vytvorí požiadavka na stiahnutie.
    iv) Správa o novej požiadavke Pull sa odošle do vývojárskych chatov (Notify microservice pre prácu s upozorneniami).
    v) Úlohy zostavovania, testovania a nasadenia sa spúšťajú na DEV (mikroslužba Jenkins pre prácu s Jenkinsom).
    vi) Ak sú všetky predchádzajúce kroky úspešne dokončené, Integro vloží svoje schválenie do žiadosti o stiahnutie (mikroslužba Bitbucket).

  • Integro čaká na schválenie v žiadosti o stiahnutie od určených recenzentov.
  • Hneď po získaní všetkých potrebných schválení (vrátane pozitívnych automatických testov), ​​Integro presunie úlohu do stavu Test on Dev (mikroslužba Jira).

6. Testeri testujú úlohu. Ak sa nevyskytnú žiadne problémy, úloha sa prenesie do stavu Pripravené na zostavenie.

7. Integro „vidí“, že úloha je pripravená na uvoľnenie a spustí jej nasadenie v kanárikovom režime (mikroslužba Jenkins). Pripravenosť na prepustenie je určená súborom pravidiel. Úloha je napríklad v požadovanom stave, neexistujú žiadne zámky na iných úlohách, momentálne nie sú aktívne nahrávania tejto mikroslužby atď.

8. Úloha je prevedená na Kanársky status (mikroservis Jira).

9. Jenkins spustí úlohu nasadenia cez Nomad v kanárikovom režime (zvyčajne 1-3 inštancie) a upozorní službu na monitorovanie vydania (mikroslužba DeployWatch) o nasadení.

10. Mikroslužba DeployWatch zhromažďuje pozadie chyby a v prípade potreby naň reaguje. Ak dôjde k prekročeniu chybového pozadia (norma pozadia sa vypočíta automaticky), vývojári sú upozornení prostredníctvom mikroslužby Notify. Ak po 5 minútach vývojár neodpovedal (klikol na Revert alebo Stay), spustí sa automatické vrátenie kanárikov. Ak nie je prekročené pozadie, vývojár musí manuálne spustiť nasadenie úlohy do produkcie (kliknutím na tlačidlo v používateľskom rozhraní). Ak do 60 minút vývojár nespustí nasadenie do produkcie, potom budú z bezpečnostných dôvodov vrátené aj inštancie kanárikov.

11. Po spustení nasadenia do produkcie:

  • Úloha sa prenesie do stavu Výroba (mikroservis Jira).
  • Mikroslužba Jenkins spustí proces nasadenia a upozorní mikroslužbu DeployWatch o nasadení.
  • Mikroslužba DeployWatch kontroluje, či boli aktualizované všetky kontajnery v produkcii (vyskytli sa prípady, keď neboli aktualizované všetky).
  • Prostredníctvom mikroslužby Notify sa do produkcie posiela notifikácia o výsledkoch nasadenia.

12. Vývojári budú mať 30 minút na spustenie vrátenia úlohy z produkcie, ak sa zistí nesprávne správanie mikroslužieb. Po tomto čase sa úloha automaticky zlúči s hlavnou (mikroslužba Git).

13. Po úspešnom zlúčení do hlavnej sa stav úlohy zmení na Uzavreté (mikroservis Jira).

Diagram sa netvári ako úplne podrobný (v skutočnosti je krokov ešte viac), ale umožňuje posúdiť mieru integrácie do procesov. Túto schému nepovažujeme za ideálnu a zlepšujeme procesy podpory automatického uvoľnenia a nasadenia.

čo ďalej

Máme veľké plány na rozvoj automatizácie, napríklad odstránenie manuálnych operácií počas monolitných verzií, zlepšenie monitorovania počas automatického nasadenia a zlepšenie interakcie s vývojármi.

Tu sa však nateraz zastavme. Mnohým témam sme sa v recenzii automatizácie venovali povrchne, niektorých sme sa vôbec nedotkli, takže na otázky radi odpovieme. Čakáme na návrhy, čo podrobne pokryť, napíšte do komentárov.

Zdroj: hab.com

Pridať komentár