
Na RIT 2019 náš kolega Alexander Korotkov predstavil o automatizácii vývoja v CIAN: na zjednodušenie života a práce používame vlastnú platformu Integro. Táto platforma sleduje životný cyklus úloh, zbavuje vývojárov rutinných operácií a výrazne znižuje počet chýb v produkcii. V tomto príspevku doplníme Alexanderovu prednášku a povieme, ako sme prešli od jednoduchých skriptov k integrácii open source produktov cez vlastnú platformu a čomu sa venuje náš samostatný tím automatizácie.
Nulová úroveň
„Nulová úroveň neexistuje, niečo také nepoznám“
Majster Shifu z m/f „Kung-fu Panda“
Automatizácia v CIAN začala 14 rokov po založení spoločnosti. Vtedy bola v vývojovom tíme 35 členov. Ťažko tomu uveriť, však? Samozrejme, nejaká forma automatizácie už existovala, ale samostatná oblasť nepretržitej integrácie a dodávky kódu sa začala formovať práve v roku 2015.
Vtedy sme mali obrovský monolit z Pythonu, C# a PHP, nasadený na Linux/Windows serveroch. Na nasadenie tohto monštra sme mali sadu skriptov, ktoré sme spúšťali manuálne. Bolo tu tiež zostavovanie monolitu, spôsobujúce bolesť a utrpenie kvôli konfliktom pri zlúčení vetiev, opravám defektov a opätovnému zostavovaniu „s inou sadou úloh v zostave“. Zjednodušene proces vyzeral takto:

To nám nevyhovovalo a chceli sme vybudovať opakovateľný, automatizovaný a kontrolovaný proces zostavovania a nasadenia. Na to sme potrebovali systém CI/CD a vyberali sme medzi bezplatnou verziou Teamcity a bezplatným Jenkins, pretože sme s nimi pracovali a obidve spĺňali naše požiadavky. Vybrali sme Teamcity ako modernejší produkt. Vtedy sme ešte nepoužívali mikroslužbovú architektúru a neplánovali sme množstvo úloh a projektov.
Dostávame sa k myšlienke o vlastnom systéme
Implementácia Teamcity odstránila len časť manuálnej práce: zostalo ešte vytváranie Pull Requestov, presun úloh podľa stavov v Jira, výber úloh na uvoľnenie. S týmto systémom Teamcity už nespolupracoval. Bolo potrebné zvoliť cestu ďalšej automatizácie. Zvážili sme možnosti práce so skriptmi v Teamcity alebo prechod na externé automatizačné systémy. Nakoniec sme sa rozhodli, že potrebujeme maximálnu flexibilitu, ktorú poskytuje len vlastné riešenie. Tak vznikla prvá verzia vnútorného automatizačného systému s názvom Integro.
Teamcity sa zaoberá automatizáciou na úrovni spúšťania procesov kompilácie a nasadenia, zatiaľ čo Integro sa zameralo na vyššiu úroveň automatizácie vyvojových procesov. Bolo potrebné zlúčiť prácu s úlohami v Jira s spracovaním súvisiaceho zdrojového kódu v Bitbucket. V tejto fáze začali v Integro vzniknúť vlastné workflow pre prácu s rôznymi typmi úloh.
V dôsledku zvyšovania automatizácie v obchodných procesoch vzrástol počet projektov a runov v Teamcity. Tak prišla nová problém: jedno bezplatné inštančné Teamcity už nestačilo (3 agenti a 100 projektov), pridali sme ďalšie inštancie (ďalšie 3 agenti a 100 projektov), neskôr ďalšie. Nakoniec sme dostali systém z niekoľkých klastrov, ktorým bolo ťažké spravovať:

Keď nastala otázka o 4. inštancii, pochopili sme, že takto už nemôžeme žiť, pretože súhrnné náklady na údržbu 4 inštancií už neboli prijateľné. Vznikla otázka nákupu plateného Teamcity alebo voľby v prospech bezplatnej Jenkins. Urobili sme výpočty pre inštancie a plány na automatizáciu a rozhodli sme sa, že prejdeme na Jenkins. Po pár týždňoch sme prešli na Jenkins a zbavili sa časti bolesti hlavy spojené so správou niekoľkých inštancií Teamcity. Tak sme sa mohli sústrediť na vývoj Integro a úpravy Jenkins pre naše potreby.
S rastom základnej automatizácie (vo forme automatického vytvárania Pull Request-ov, zberu a publikovania Code coverage a iných kontrol) sa objavil trvalý záujem maximálne sa vzdať ručných release-ov a zveriť túto prácu robotom. Okrem toho sa vo vnútri spoločnosti začalo s presunom na mikroservisy, ktoré si vyžadovali časté release-y, pričom každý samostatne. Tak sme postupne prišli k automatickým release-om našich mikroservisov (monolit zatiaľ vydávame ručne kvôli zložitosti procesu). Ale, ako to už býva, objavila sa nová zložitost.
Automatizujeme testovanie

Vďaka automatizácii release-ov sa procesy vývoja urýchlili, pričom čiastočne na úkor preskočenia niektorých fáz testovania. To viedlo k dočasnej strate kvality. Znie to banálne, ale spolu s urýchlením release-ov bolo potrebné zmeniť aj metodológiu vývoja produktu. Museli sme uvažovať o automatizácii testovania, prerozdeľovaní osobnej zodpovednosti (tu ide o 'prijatie myšlienky v hlave', a nie o finančné pokuty) vývojára za vydaný kód a chyby v ňom, ako aj o rozhodnutí o vydaní/ne vydaní úlohy prostredníctvom automatického nasadenia.
Riešením problémov s kvalitou sme dospeli k dvom dôležitým rozhodnutiam: začali sme vykonávať kanárske testovanie a zaviedli sme automatické monitorovanie pozadia chýb s automatickým reagovaním na jeho presiahnutie. Prvé rozhodnutie umožnilo identifikovať zjavné chyby predtým, než sa kód dostal do produkcie, druhé znížilo čas reakcie na problémy v produkcii. Chyby sa samozrejme stávajú, ale väčšinu času a energie trávime nie na opravovanie, ale na minimalizáciu.
Tím automatizácie
Momentálne máme tím 130 vývojárov a pokračujeme . Tím pre kontinuálnu integráciu a dodávku kódu (ďalej — tím Deploy and Integration alebo DI) pozostáva zo 7 ľudí a pracuje v 2 smeroch: vývoj platformy automatizácie Integro a DevOps.
DevOps zodpovedá za Dev/Beta prostredia webu CIAN, prostredie Integro, pomáha vývojárom pri riešení problémov a vypracováva nové prístupy k škálovaniu prostredí. Oblasť vývoja Integro sa zaoberá nielen samotným Integro, ale aj príbuznými službami, ako sú pluginy pre Jenkins, Jira, Confluence, a tiež vyvíja pomocné nástroje a aplikácie pre týmy vývojárov.
Tím DI spolupracuje s tímom Platformy, ktorý sa zaoberá vývojom architektúry, knižníc a prístupov k vývoju v rámci spoločnosti. Okrem toho môže každý vývojár v CIAN prispieť k automatizácii, napríklad vytvorením mikroautomatizácie podľa potrieb tímu alebo zdieľaním skvelej myšlienky, ako zlepšiť automatizáciu.
Viacvrstvová štruktúra automatizácie v CIAN

Všetky systémy zapojené do automatizácie môžeme rozdeliť na niekoľko vrstiev:
- Externé systémy (Jira, Bitbucket a pod.). S nimi pracujú vývojárske tímy.
- Platforma Integro. Vývojári s ňou väčšinou nepracujú priamo, ale je to práve ona, ktorá podporuje funkciu celej automatizácie.
- Služby doručovania, orchestrácie a zistovania (napríklad Jenkins, Consul, Nomad). S ich pomocou nasadzujeme kód na serveroch a zabezpečujeme vzájomnú interakciu služieb.
- Fyzická úroveň (servery, OS, príbuzný softvér). Na tejto úrovni beží náš kód. Môže to byť fyzický server alebo virtuálny (LXC, KVM, Docker).
Na základe tejto koncepcie delíme zóny zodpovednosti v rámci tímu DI. Dve prvé úrovne spadajú pod zodpovednosť oblasti vývoja Integro, zatiaľ čo dve posledné úrovne spadajú pod zodpovednosť DevOps. Takéto rozdelenie umožňuje sústrediť sa na úlohy a nebráni interakcii, pretože sme blízko seba a neustále si vymieňame znalosti a skúsenosti.
Integro
Zamerajme sa na Integro a začneme technologickým zásobníkom:
- CentOs 7
- Docker + Nomad + Consul + Vault
- Java 11 (starý monolit Integro zostáva na Java 8)
- 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
Držíme sa zásady mikroslužieb, aj keď máme aj dedičstvo v podobe monolitu prvej verzie Integro. Každá mikroslužba beží vo svojej docker-kontejneri, služby komunikujú navzájom cez HTTP požiadavky a RabbitMQ správy. Mikroslužby sa nájdu pomocou Consul a vykonávajú k nemu požiadavku, pričom prechádzajú autorizáciou cez SSO (Keycloak, OAuth 2/OpenID Connect).

Ako reálny príklad sa pozrime na interakciu s Jenkins, ktorá pozostáva z nasledujúcich krokov:
- Mikroslužba správy workflow (ďalej Flow-mikroslužba) chce spustiť zostavenie v Jenkins. Na to nájde cez Consul IP:PORT mikroslužby integrácie s Jenkins (ďalej Jenkins-mikroslužba) a odošle do nej asynchrónny požiadavok na spustenie zostavenia v Jenkins.
- Jenkins-mikroslužba po prijatí požiadavky formuluje a vracia v odpovedi Job ID, podľa ktorého bude možné neskôr identifikovať výsledok práce. V spolupráci s tým spúšťa zostavenie v Jenkins cez volanie REST API.
- Jenkins vykoná zostavenie a po jeho skončení odošle webhook s výsledkami vykonania do Jenkins-mikroslužby.
- Jenkins-mikroslužba, ktorá prijala webhook, formuluje správu o skončení spracovania požiadavky a prikladá k nej výsledky vykonania. Sformulovaná správa sa posiela do fronty RabbitMQ.
- Cez RabbitMQ zverejnená správa sa dostane k Flow-mikroslužbe, ktorá sa dozvie o výsledku spracovania svojej úlohy, porovnaním Job ID z požiadavky a prijatej správy.
Momentálne máme okolo 30 mikroslužieb, ktoré môžeme rozdeliť do niekoľkých skupín:
- Správa konfigurácií.
- Informovanie a interakcia s používateľmi (messengery, e-mail).
- Práca so zdrojovým kódom.
- Integrácia s nástrojmi na nasadzovanie (jenkins, nomad, consul a pod.).
- Monitorovanie (verzií, chýb a pod.).
- Webové nástroje (UI na správu testovacích prostredí, zber štatistík a pod.).
- Integrácia s task trackermi a podobnými systémami.
- Správa workflow pre rôzne úlohy.
Workflow úlohy
Integro automatizuje akcie súvisiace so životným cyklom úlohy. Zjednodušene pod životným cyklom úlohy rozumieme workflow úlohy v Jira. V našich vývojových procesoch existuje niekoľko variácií workflow v závislosti od projektu, typu úlohy a možností vybraných v konkrétnej úlohe.
Pozrime sa na workflow, ktorý používame najčastejšie:

Na schéme ozubené kolo naznačuje, že prechod je iniciovaný automaticky prostredníctvom Integra, zatiaľ čo postava človeka naznačuje, že prechod je spustený manuálne osobou. Pozrime sa na niekoľko ciest, ktorými môže úloha prechádzať v tomto pracovnom postupe.
Úplne manuálne testovanie na DEV+BETA bez kanárikových testov (zvyčajne tak uvádzame monolit):

Môžu existovať aj iné kombinácie prechodu. Niekedy je možné zvoliť cestu, ktorou úloha pôjde, cez možnosti v Jira.
Pohyb úlohy
Pozrime sa na hlavné kroky, ktoré sa vykonávajú pri pohybe úlohy v pracovnom postupe „Testovanie na DEV + kanárikové testy“:
1. Vývojár alebo PM vytvorí úlohu.
2. Vývojár preberá úlohu do práce. Po dokončení ju preloží do stavu IN REVIEW.
3. Jira odošle Webhook smerom k Jira-mikroslužbe (zodpovedá za integráciu s Jira).
4. Jira-mikroslužba odošle požiadavku na Flow-službu (zodpovedá za vnútorné pracovné postupy, v ktorých sa vykonáva práca) na spustenie pracovného postupu.
5. V rámci Flow-služby:
- Sú určení recenzenti pre úlohu (Users-mikroslužba, ktorá vie všetko o používateľoch + Jira-mikroslužba).
- Cez Source-mikroslužbu (vie o repozitároch a vetvách, ale nepracuje so samotným kódom) sa vykonáva vyhľadávanie repozitárov, v ktorých je vetva našej úlohy (pre zjednodušenie vyhľadávania sa názov vetvy zhoduje s číslom úlohy v Jira). Najčastejšie má úloha iba jednu vetvu v jednom repozitári, čo zjednodušuje správu fronty na nasadenie a znižuje prepojenosť medzi repozitármi.
- Pre každú nájdenú vetvu sa vykonáva nasledujúca sekvencia krokov:
i) Zlúčenie s master-vetvou (Git-mikroslužba pre prácu s kódom).
ii) Vetva je zablokovaná pred zmenami vývojárom (Bitbucket-mikroslužba).
iii) Vytvára sa Pull Request na túto vetvu (Bitbucket-mikroslužba).
iv) Odesiela sa správa o novom Pull Requeste do chatov vývojárov (Notify-mikroslužba pre upozornenia).
v) Spúšťa sa zostavenie, testovanie a nasadenie úlohy na DEV (Jenkins-mikroslužba pre prácu s Jenkins).
vi) Ak všetky predchádzajúce body skončili úspešne, Integro vloží svoje schválenie do Pull Requestu (Bitbucket-mikroslužba). - Integro čaká na schválenie v Pull Requeste od určených recenzentov.
- Akonáhle sú všetky potrebné schválenia (vrátane pozitívne prebehnutých automatizovaných testov) získané, Integro prevádza úlohu do stavu Test on Dev (Jira-mikroslužba).
6. Testeri vykonávajú testovanie úlohy. Ak nie sú žiadne problémy, úloha sa prevedie do stavu Ready For Build.
7. Integro "vidí", že úloha je pripravená na vydanie, a spúšťa jej nasadenie v kanárskej verzii (Jenkins mikroslužba). Pripravenosť na vydanie sa určuje súborom pravidiel. Napríklad úloha je v správnom stave, nie sú žiadne blokácie na iné úlohy, aktuálne nie sú aktívne nasadenia tejto mikroslužby atď.
8. Úloha sa prevedie do stavu Canary (Jira mikroslužba).
9. Jenkins spúšťa nasadenie úlohy v kanárskej verzii cez Nomad (zvyčajne 1-3 inštancie) a informuje o nasadení službu monitorovania vydaní (DeployWatch mikroslužba).
10. DeployWatch mikroslužba zhromažďuje pozadie chýb a reaguje naň, ak je to potrebné. Pri prekročení pozadia chýb (norma pozadia sa vypočítava automaticky) sú vývojári informovaní cez Notify mikroslužbu. Ak vývojár nereagoval do 5 minút (stlačením Revert alebo Stay), automaticky sa spustí spätný chod kanárskych inštancií. Ak pozadie nie je prekročené, vývojár musí manuálne spustiť nasadenie úlohy na Production (stlačením tlačidla v UI). Ak vývojár nespustil nasadenie na Production do 60 minút, kanárske inštancie budú z bezpečnostných dôvodov tiež zrušené.
11. Po spustení nasadenia na Production:
- Úloha sa prevedie do stavu Production (Jira mikroslužba).
- Jenkins mikroslužba spúšťa proces nasadenia a informuje o nasadení DeployWatch mikroslužbu.
- DeployWatch mikroslužba kontroluje, či sa na Production aktualizovali všetky kontajnery (vyskytli sa prípady, keď sa neaktualizovalo všetko).
- Cez Notify mikroslužbu sa posiela oznámenie o výsledkoch nasadenia na Production.
12. Vývojári budú mať 30 minút na spustenie spätného chodu úlohy z Production v prípade zistenia nesprávneho správania mikroslužby. Po uplynutí tejto doby bude úloha automaticky zlúčená do master (Git mikroslužba).
13. Po úspešnom zlúčení do master bude stav úlohy zmenený na Closed (Jira mikroslužba).
Schéma si nenárokuje úplnú detailnosť (v skutočnosti je krokov ešte viac), ale umožňuje oceniť úroveň integrácie do procesov. Nepovažujeme túto schému za ideálnu a neustále zlepšujeme procesy automatického sprievodu vydaní a nasadenia.
Čo ďalej
Máme veľké plány na rozvoj automatizácie, ako napríklad odstránenie ručných operácií pri vydaniach monolitu, zlepšenie monitorovania pri automatickom nasadzovaní a vylepšenie spolupráce s vývojármi.
Ale tu zatiaľ zastavíme. Mnohé témy v prehľade automatizácie sme pokryli povrchne, niektoré sme vôbec nespomenuli, preto sa radi odpovieme na otázky. Čakáme na vaše návrhy, čo podrobne osvetliť, píšte do komentárov.
Zdroj: habr.com
