
Në RIT 2019, kolegu ynë Aleksandër Korotkov bëri për automatizimin e zhvillimit në CIAN: për të thjeshtuar jetën dhe punën, ne përdorim platformën tonë të brendshme Integro. Ajo ndjek ciklin e jetës së detyrave, heq nga zhvilluesit operacionet rutinë dhe zvogëlon ndjeshëm numrin e gabimeve në prodhim. Në këtë post, do të plotësojmë leksionin e Aleksandrit dhe do të tregojmë se si e kaluam rrugën nga skenarët e thjeshtë në integrimin e produkteve open source përmes platformës sonë dhe se me çfarë merret një ekip i veçantë automatizimi.
Â
Niveli zero
«Niveli zero nuk ekziston, nuk e di një të tillë»
Mjeshtri Shifu nga filmi «Kung Fu Panda»
Automatizimi nĂ« CIAN filloi 14 vjet pas themelimit tĂ« kompanisĂ«. AtĂ«herĂ« ekipi i zhvillimit kishte 35 njerĂ«z. VĂ«shtirĂ« tĂ« besohej, apo jo? Sigurisht, nĂ« njĂ« formĂ«, automatizimi ekzistonte, por njĂ« drejtim i veçantĂ« pĂ«r integrimin e vazhdueshĂ«m dhe shpĂ«rndarjen e kodit filloi tĂ« formohej pikĂ«risht nĂ« vitin 2015.Â
Në atë kohë, ne kishim një monolit të madh nga Python, C# dhe PHP, të instaluar në serverë Linux/Windows. Për depozimin e këtij monstruoze, ne kishim një grup skenarësh që i ekzekutonim manualisht. Ishte gjithashtu një ndërtim i monolitit, që sillte dhimbje dhe vuajtje për shkak të konflikteve të bashkimeve të degëve, rregullimeve të defekteve dhe ri-ndërtimit "me një grup tjetër detyrash në ndërtim". Thjesht, procesi dukej kështu:

Kjo nuk na kënaqte dhe ne donim të ndërtonim një proces të ndërtimit dhe shpërndarjes të përsëritur, automatizuar dhe të menaxhuar. Për këtë, na duhej një sistem CI/CD, dhe ne zgjodhëm midis versionit falas të Teamcity dhe Jenkins i lirë, pasi kishim punuar me të dhe të dy na kënaqin me grupin e funksioneve. Zgjodhëm Teamcity si një produkt më të ri. Në atë kohë, ne nuk po përdornim arkitekturë mikrosërvish dhe nuk prisnim një numër të madh detyrash dhe projektesh.
Arrijmë në idenë për një sistem të brendshëm
Përvoja e zbatimit të Teamcity reduktoi vetëm një pjesë të punës manuale: mbeti ende krijimi i Pull Request-eve, avancimi i detyrave në statuset në Jira, dhe përzgjedhja e detyrave për lëshim. Së bashku, sistemi Teamcity nuk mund ta menaxhonte këtë. Duhej të zgjidhnim rrugën për automatikën e mëtejshme. Ne shqyrtuam mundësitë e punës me skriptet në Teamcity ose kalimin në sisteme të jashtme automatizimi. Por në fund vendosëm se na nevojitej maksimalja fleksibilitetit që ofron vetëm një zgjidhje e brendshme. Kështu lindi versioni i parë i sistemit të brendshëm të automatizimit të quajtur Integro.
Teamcity merret me automatizimin nĂ« nivelin e nisjes sĂ« proceseve tĂ« ndĂ«rtimit dhe shpĂ«rndarrjes, ndĂ«rsa Integro Ă«shtĂ« fokusuar nĂ« automatizimin e proceseve tĂ« zhvillimit nĂ« nivel mĂ« tĂ« lartĂ«. Duhej tĂ« bashkoheshin punĂ«t me detyrat nĂ« Jira me pĂ«rpunimin e kodit burimor tĂ« lidhur nĂ« Bitbucket. NĂ« kĂ«tĂ« fazĂ«, brenda Integro filluan tĂ« shfaqen workflow-e tĂ« veta pĂ«r tĂ« punuar me detyra tĂ« llojeve tĂ« ndryshme.Â
Për shkak të rritjes së automatizmit në proceset e biznesit, u rrit numri i projekteve dhe run-eve në Teamcity. Kështu erdhi një problem i ri: një instancë falas e Teamcity nuk ishte e mjaftueshme (3 agjentë dhe 100 projekte), shtuam një instancë tjetër (3 agjentë dhe 100 projekte) dhe pastaj edhe një tjetër. Në përfundim, morëm një sistem me disa klasterë që ishte i vështirë për t'u menaxhuar:

Kur u shfaq pyetja për një instancë të katërt, ne kuptuam se nuk mund të vazhdojmë më kështu, pasi kostot e mbështetjes për 4 instanca tashmë ishin jashtë çdo kufiri. Lindën pyetja për blerjen e Teamcity të paguar ose zgjedhja e Jenkins falas. Ne bëmë llogaritjet mbi instancat dhe planet për automatizimin dhe vendosëm se do të jetonim me Jenkins. Pas disa javësh, u kaluam në Jenkins dhe iu shmangëm një pjese të dhimbjeve të kokës, lidhur me mbështetjen e disa instancave të Teamcity. Kështu, arritëm të përqendrohemi në zhvillimin e Integro dhe përshtatjen e Jenkins për ne.
Me rritja e automatizimit bazĂ« (siç Ă«shtĂ« krijimi automatik i Pull Request-eve, mbledhja dhe publikimi i Code coverage dhe kontrollimeve tĂ« tjera) ka sjellĂ« dĂ«shirĂ«n e fortĂ« pĂ«r t'u hequr dorĂ« maksimalisht nga lĂ«shimet manuale dhe pĂ«r t'i lĂ«nĂ« kĂ«to punĂ« roboteve. PĂ«rveç kĂ«saj, brenda kompanisĂ« ka filluar njĂ« trasladim nĂ« mikroshĂ«rbime, tĂ« cilat kĂ«rkonin lĂ«shime tĂ« shpeshta, madje dhe ndaras nga njĂ«ra-tjetra. KĂ«shtu, ne gradualisht arritĂ«m nĂ« lĂ«shimet automatike tĂ« mikroshĂ«rbimeve tona (monoliti ende e lĂ«shojmĂ« manualisht pĂ«r shkak tĂ« kompleksitetit tĂ« procesit). Por, siç ndodh zakonisht, u shfaq njĂ« vĂ«shtirĂ«si e re.Â
Po automatizojmë testimin

PĂ«r shkak tĂ« automatizimit tĂ« lĂ«shimeve, proceset e zhvillimit u pĂ«rshpejtuan, pjesĂ«risht pĂ«r shkak tĂ« anashkalimit tĂ« disa fazave tĂ« testimit. Kjo çoi nĂ« njĂ« humbje tĂ« pĂ«rkohshme tĂ« cilĂ«sisĂ«. Duket banal, por sĂ« bashku me pĂ«rshpejtimin e lĂ«shimeve, duhej tĂ« ndryshonim edhe metodologjinĂ« e zhvillimit tĂ« produktit. Duhej tĂ« mendonim pĂ«r automatizimin e testimit, pĂ«r ndjenjĂ«n e pĂ«rgjegjĂ«sisĂ« personale (kĂ«tu flitet pĂ«r "pranimin e ideve nĂ« mendje", jo pĂ«r dĂ«nime financiare) tĂ« zhvilluesve pĂ«r kodin qĂ« lĂ«shojnĂ« dhe gabimet nĂ« tĂ«, si dhe pĂ«r njĂ« zgjidhje pĂ«r lĂ«shimin/nĂ« lĂ«shimin e detyrave nĂ«pĂ«rmjet deploy-it automatik.Â
Duke eliminuar problemet me cilĂ«sinĂ«, arritĂ«m nĂ« dy vendime tĂ« rĂ«ndĂ«sishme: filluam tĂ« kryejmĂ« testime kanari dhe implementuam monitorim automatik tĂ« sfondit pĂ«r gabimet me reagim automatik nĂ«se ato tejkalonin njĂ« nivel tĂ« caktuar. Vendimi i parĂ« na lejoji tĂ« gjejmĂ« gabimet evidente para se kodi tĂ« arrinte nĂ« production, vendimi i dytĂ« reduktoi kohĂ«n e reagimit ndaj problemeve nĂ« production. Gabimet, sigurisht, ndodhin, por ne shpenzojmĂ« mĂ« shumĂ« kohĂ« dhe energji pĂ«r minimizimin e tyre sesa pĂ«r korrigjimin e tyre.Â
Ekipi i automatizimit
Tani kemi njĂ« staf prej 130 zhvilluesish, dhe vazhdojmĂ« . Ekipi pĂ«r integrimin dhe dorĂ«zimin e vazhdueshĂ«m tĂ« kodit (mĂ« pas â ekipi Deploy and Integration ose DI) pĂ«rbĂ«het nga 7 persona dhe punon nĂ« 2 drejtime: zhvillimi i platformĂ«s sĂ« automatizimit Integro dhe DevOps.Â
DevOps Ă«shtĂ« pĂ«rgjegjĂ«s pĂ«r mjediset Dev/Beta tĂ« faqes CIAN, mjediset Integro, ndihmon zhvilluesit nĂ« zgjidhjen e problemeve dhe zhvillon qasje tĂ« reja pĂ«r zgjerimin e mjediseve. Drejtimi i zhvillimit Integro merret si me vetĂ« Integro, ashtu edhe me shĂ«rbime tĂ« lidhura, siç janĂ« shtesat pĂ«r Jenkins, Jira, Confluence, dhe gjithashtu zhvillon mjete ndihmĂ«se dhe aplikacione pĂ«r ekipet e zhvilluesve.Â
Ekipi DI punon ngushtë me ekipin e Platformës, i cili merret me zhvillimin e arkitekturës, biblioteka dhe qasjes për zhvillim brenda kompanisë. Përveç kësaj, çdo zhvillues brenda CIAN mund të kontribuojë në automatizim, për shembull, të bëjë mikro-automatizim sipas nevojave të ekipit ose të ndajë një ide të shkëlqyer për të përmirësuar automatizimin.
Shtresa e automatizimit në CIAN

Të gjitha sistemet e angazhuara në automatizim mund të ndahen në disa shtresa:
- Sistemet e jashtme (Jira, Bitbucket dhe të tjera). Ekipet e zhvillimit punojnë me to.
- Platforma Integro. Zhvilluesit zakonisht nuk punojnë direkt me të, por ajo mbështet funksionimin e gjithë automatizimit.
- Shërbimet e dorëzimit, orkestrimit dhe zbulimit (p.sh., Jenkins, Consul, Nomad). Me ndihmën e tyre ne zhvillojmë kodin në servera dhe sigurojmë funksionimin e shërbimeve me njëri-tjetrin.
- Niveli fizik (serverat, OS, softueri përkatës). Në këtë nivel funksionon kodi ynë. Kjo mund të jetë si një server fizik, ashtu edhe një virtual (LXC, KVM, Docker).
Duke u bazuar në këtë koncept, ne ndajmë zonat e përgjegjësisë brenda ekipit DI. Dy nivelet e para bien në përgjegjësinë e drejtimit të zhvillimit Integro, ndërsa dy nivelet e fundit bie në përgjegjësinë e DevOps. Ky ndarje lejon fokusimin në detyra dhe nuk pengon bashkëpunimin, pasi ne jemi afër njëri-tjetrit dhe vazhdimisht shkëmbejmë njohuri dhe përvojë.
Integro
Le të fokusojmë në Integro dhe të fillojmë me stakun teknologjik:
- CentOs 7
- Docker + Nomad + Consul + Vault
- Java 11 (monoliti i vjetër Integro do të mbetet në Java 8)
- Spring Boot 2.X + Spring Cloud Config
- PostgreSql 11
- RabbitMQÂ
- Apache Ignite
- Camunda (embeddedd)
- Grafana + Graphite + Prometheus + Jaeger + ELK
- Web UI: React (CSR) + MobX
- SSO: Keycloak
Ne mbajmĂ« parimin e zhvillimit mikroshĂ«rbimeve, megjithĂ«se kemi edhe depĂ«rtime tĂ« vjetra nĂ« formĂ«n e monolitit tĂ« versionit tĂ« hershĂ«m tĂ« Integro. Ădo mikroshĂ«rbim operon nĂ« njĂ« kontenier docker tĂ« tij, shĂ«rbimet komunikojnĂ« me njĂ«ra-tjetrĂ«n pĂ«rmes kĂ«rkesave HTTP dhe mesazheve RabbitMQ. MikroshĂ«rbimet gjejnĂ« njĂ«ra-tjetrĂ«n pĂ«rmes Consul dhe kryejnĂ« njĂ« kĂ«rkesĂ« pĂ«r tĂ«, duke kaluar autorizimin nĂ«pĂ«rmjet SSO (Keycloak, OAuth 2/OpenID Connect).

Si një shembull real, le të shqyrtojmë ndërveprimin me Jenkins, i cili përbëhet nga hapat e mëposhtëm:
- Mikroshërbimi i menaxhimit të workflow (më tej mikroshërbimi Flow) dëshiron të nisë një ndërtim në Jenkins. Për këtë, ai përmes Consul gjen IP:PORT-in e mikroshërbimit të integrimit me Jenkins (më tej mikroshërbimi Jenkins) dhe i dërgon atij një kërkesë asinkrone për të nisur ndërtimin në Jenkins.
- MikroshĂ«rbimi Jenkins, pasi merr kĂ«rkesĂ«n, ŃĐŸŃĐŒon dhe kthen nĂ« pĂ«rgjigje Job ID, me tĂ« cilin mĂ« vonĂ« do tĂ« mund tĂ« identifikohet rezultati i punĂ«s. BashkĂ« me kĂ«tĂ«, ai nis ndĂ«rtimin nĂ« Jenkins pĂ«rmes njĂ« thirrjeje tĂ« REST API.
- Jenkins ekzekuton ndërtimin dhe pas përfundimit të tij dërgon një webhook me rezultatet e ekzekutimit në mikroshërbimin Jenkins.
- Mikroshërbimi Jenkins, pasi merr webhook, formon një mesazh për përfundimin e përpunimit të kërkesës dhe e ngjit tek ai rezultatet e ekzekutimit. Mesazhi i formuar dërgohet në radhën RabbitMQ.
- Përmes RabbitMQ, mesazhi i publikuar arrin te mikroshërbimi Flow, i cili merr informacion mbi rezultatin e përpunimit të detyrës së tij, duke krahasuar Job ID nga kërkesa dhe mesazhi i marrë.
Aktualisht kemi rreth 30 mikroshërbime, të cilat mund të ndahen në disa grupe:
- Menaxhimi i konfigurimeve.
- Informimi dhe ndërveprimi me përdoruesit (mesazherë, email).
- Puna me kodin burimor.
- Integrimi me mjetet e përhapjes (jenkins, nomad, consul, etj.).
- Monitorimi (lëshimeve, gabimeve, etj.).
- Veglat web (UI për menaxhimin e mjediseve testuese, mbledhjen e statistikave, etj.).
- Integrimi me sistemet e menaxhimit të detyrave dhe sisteme të ngjashme.
- Menaxhimi i workflow për detyra të ndryshme.
Workflow i detyrës
Integro automatizon veprimet qĂ« lidhen me ciklin jetĂ«sor tĂ« njĂ« detyre. NĂ« mĂ«nyrĂ« tĂ« thjeshtĂ«, nĂ«n ciklin jetĂ«sor tĂ« detyrĂ«s do tĂ« kuptojmĂ« workflow-in e detyrĂ«s nĂ« Jira. NĂ« proceset tona tĂ« zhvillimit ka disa variante workflow nĂ« varĂ«si tĂ« projektit, llojit tĂ« detyrĂ«s dhe opsioneve tĂ« zgjedhura nĂ« detyrĂ«n specifike.Â
Le të shqyrtojmë workflow-in që përdorim më shpesh:

Në diagram, ingranazhi tregon se kalimi thirret automatikisht nga Integro, ndërsa figura e njeriut tregon se kalimi thirret manualisht nga njeriu. Le të shqyrtojmë disa rrugë që mund të ndjekë detyra në këtë proces pune.
Testim krejtësisht manual në DEV+BETA pa teste kanarinë (zakonisht kështu e publikojmë monolitin):

Mund të ketë edhe kombinime të tjera kalimi. Ndonjëherë rruga që do të ndjekë detyra, mund të zgjidhet nëpërmjet opsioneve në Jira.
Lëvizja e detyrës
Le të shqyrtojmë hapat kryesorë që përmbushen gjatë lëvizjes së detyrës në procesin e punës "Testim në DEV + teste kanarinë":
1. Zhvilluesi ose PM krijon një detyrë.
2. Zhvilluesi merr detyrën për të punuar. Pas përfundimit, e kalon atë në statusin IN REVIEW.
3. Jira dërgon një Webhook në drejtim të mikro-shërbimit Jira (përgjegjës për integrimin me Jira).
4. Mikro-shërbimi Jira dërgon një kërkesë në shërbimin Flow (përgjegjës për proceset e brendshme të punës, në të cilat kryhet puna) për të nisur procesin e punës.
5. Brenda shërbimit Flow:
- Rishikuesit caktohen për detyrën (mikro-shërbimi Users, i cili di gjithçka për përdoruesit + mikro-shërbimi Jira).
- Nëpërmjet mikro-shërbimit Source (i cili di për repository-t dhe degët, por nuk punon me kodin e vet), bëhet kërkimi i repositorëve që kanë degë të detyrës tonë (për thjeshtimin e kërkimit, emri i degës përputhet me numrin e detyrës në Jira). Në shumicën e rasteve, detyra ka vetëm një degë në një repository, kjo e thjeshton menaxhimin e radhës për publikim dhe zvogëlon lidhshmërinë midis repositorëve.
- Për secilën degë të gjetur, kjo sekuencë veprimesh realizohet:
i) Përfshirja e degës master (mikro-shërbimi Git për punën me kodin).
ii) Dega bllokohet nga ndryshime nga zhvilluesi (mikro-shërbimi Bitbucket).
iii) Krijohet një Pull Request për këtë degë (mikro-shërbimi Bitbucket).
iv) Dërgohet një mesazh për Pull Request të ri në bisedat e zhvilluesve (mikro-shërbimi Notify për punën me njoftime).
v) Nisën ndërtimi, testimi dhe publikimi i detyrës në DEV (mikro-shërbimi Jenkins për punën me Jenkins).
vi) Nëse të gjitha pikat e mësipërme përfundojnë me sukses, atëherë Integro vendos aprovimin e tij në Pull Request (mikro-shërbimi Bitbucket). - Integro pret aprovimin në Pull Request nga rishikuesit e caktuar.
- Sapo të merren të gjitha aprovimet e nevojshme (në përfshirje të testeve automatike të kaluara pozitivisht), Integro e kalon detyrën në statusin Test on Dev (mikro-shërbimi Jira).
6. Testuesit kryejnë testimin e detyrës. Nëse nuk ka probleme, atëherë e kalojnë detyrën në statusin Ready For Build.
7. Integro «shikon», që detyra është gati për publikim, dhe e nisin deploy-n e saj në modin kanar (mikrosërvici Jenkins). Gatishmëria për publikim përcaktohet nga një grup rregullash. Për shembull, detyra është në statusin e duhur, nuk ka bllokime për detyra të tjera, aktualisht nuk ka publikime aktive të këtij mikroservici, etj.
8. Detyra kalon në statusin Canary (mikrosërvici Jira).
9. Jenkins nisin deploy-n e detyrës në modin kanar përmes Nomad (zakonisht 1-3 instanca) dhe njofton për publikimin shërbimin e monitorimit të publikimeve (mikrosërvici DeployWatch).
10. Mikrosërvici DeployWatch mbledh sfondin e gabimeve dhe reagon në të, nëse është e nevojshme. Nëse sfondi i gabimeve kalon limitin (norma e sfondit llogaritet automatikisht) bëhet njoftimi i zhvilluesve përmes mikrosërvicit Notify. Nëse zhvilluesi nuk reagon brenda 5 minutash (nëpërmjet shtypjes së Revert ose Stay), atëherë fillohet rregullimi automatik i instancave kanar. Nëse sfondi nuk kalon limitin, zhvilluesi duhet të nisë manualisht deploy-n e detyrës në Production (nëpërmjet një butoni në UI). Nëse brenda 60 minutash zhvilluesi nuk ka nisur deploy-n në Production, atëherë instancat kanar gjithashtu do të anulohen për siguri.
11. Pas nisjes së deploy-it në Production:
- Detyra kalon në statusin Production (mikrosërvici Jira).
- Mikrosërvici Jenkins nis procesin e deploy-it dhe njofton për publikimin mikrosërvicin DeployWatch.
- Mikrosërvici DeployWatch kontrollon që të gjithë kontenierët në Production janë përditësuar (ka pasur raste kur nuk përditësoheshin të gjithë).
- Përmes mikrosërvicit Notify dërgohet një njoftim për rezultatet e deploy-it në Production.
12. Zhvilluesit do të kenë 30 minuta për të nisur rregullimin e detyrës nga Production në rast se zbulohet sjellje incorrecte e mikrosërvicit. Pas përfundimit të kësaj kohe, detyra do të përfshihet automatikisht në master (mikrosërvici Git).
13. Pas një bashkimi të suksesshëm në master, statusi i detyrës do të ndryshohet në Closed (mikrosërvici Jira).
Schemat nuk pretendon për detajizimin e plotë (në realitet ka më shumë hapa), por lejon të vlerësohet shkalla e integrimit në procese. Ne nuk e konsiderojmë këtë schemën ideale dhe përmirësojmë proceset e mbështetjes automatike të publikimeve dhe deploy-it.
ĂfarĂ« pason
Kemi plane të mëdha për zhvillimin e automatizimit, për shembull, heqjen e operacioneve manuale gjatë lëshimeve të monolit, përmirësimin e monitorimit gjatë shpërndarjes automatike, dhe përmirësimin e bashkëpunimit me zhvilluesit.
Por këtu do të ndalemi për tani. Kemi prekur shumë tema në përmbledhjen e automatizimit në mënyrë sipërfaqësore dhe disa grahëm fare, prandaj gëzohemi të përgjigjemi për pyetje. Presim propozime se çfarë të flasim më në detaje, shkruani në komentet.
Burimi: habr.com
