Nga skriptet në platformën tonë: si e automatizuam zhvillimin në CIAN.

Nga skriptet në platformën tonë: si e automatizuam zhvillimin në CIAN.

Në RIT 2019, kolegu ynë Aleksandër Korotkov bëri referatin 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:

Nga skriptet në platformën tonë: si e automatizuam zhvillimin në CIAN.

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:

Nga skriptet në platformën tonë: si e automatizuam zhvillimin në CIAN.

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

Nga skriptet në platformën tonë: si e automatizuam zhvillimin në CIAN.

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Ă« tĂ« rritemi. 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

Nga skriptet në platformën tonë: si e automatizuam zhvillimin në CIAN.

Të gjitha sistemet e angazhuara në automatizim mund të ndahen në disa shtresa:

  1. Sistemet e jashtme (Jira, Bitbucket dhe të tjera). Ekipet e zhvillimit punojnë me to.
  2. Platforma Integro. Zhvilluesit zakonisht nuk punojnë direkt me të, por ajo mbështet funksionimin e gjithë automatizimit.
  3. 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.
  4. 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).

Nga skriptet në platformën tonë: si e automatizuam zhvillimin në CIAN.

Si një shembull real, le të shqyrtojmë ndërveprimin me Jenkins, i cili përbëhet nga hapat e mëposhtëm:

  1. 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.
  2. 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.
  3. Jenkins ekzekuton ndërtimin dhe pas përfundimit të tij dërgon një webhook me rezultatet e ekzekutimit në mikroshërbimin Jenkins.
  4. 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.
  5. 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:

  1. Menaxhimi i konfigurimeve.
  2. Informimi dhe ndërveprimi me përdoruesit (mesazherë, email).
  3. Puna me kodin burimor.
  4. Integrimi me mjetet e përhapjes (jenkins, nomad, consul, etj.).
  5. Monitorimi (lëshimeve, gabimeve, etj.).
  6. Veglat web (UI për menaxhimin e mjediseve testuese, mbledhjen e statistikave, etj.).
  7. Integrimi me sistemet e menaxhimit të detyrave dhe sisteme të ngjashme.
  8. 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:

Nga skriptet në platformën tonë: si e automatizuam zhvillimin në CIAN.

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):

Nga skriptet në platformën tonë: si e automatizuam zhvillimin në CIAN.

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

Blini hosting tĂ« besueshĂ«m pĂ«r faqe interneti me mbrojtje nga DDoS, serverĂ« VPS VDS đŸ”„ Blini hosting tĂ« besueshĂ«m pĂ«r faqe interneti me mbrojtje nga DDoS, serverĂ« VPS VDS | ProHoster