De skriptoj ĝis nia propra platformo: kiel ni aŭtomatigis disvolviĝon ĉe CIAN

De skriptoj ĝis nia propra platformo: kiel ni aŭtomatigis disvolviĝon ĉe CIAN

Ĉe RIT 2019, faris nia kolego Aleksandr Korotkov raporto pri aŭtomatigo de evoluo ĉe CIAN: por simpligi vivon kaj laboron, ni uzas nian propran Integro-platformon. Ĝi spuras la vivociklon de taskoj, malpezigas programistojn de rutinaj operacioj kaj signife reduktas la nombron da cimoj en produktado. En ĉi tiu afiŝo, ni kompletigos la raporton de Aleksandro kaj rakontos al vi kiel ni iris de simplaj skriptoj al kombinado de malfermfontaj produktoj per nia propra platformo kaj kion faras nia aparta aŭtomatiga teamo.
 

Nula nivelo

"Ne ekzistas nula nivelo, mi ne scias tian aferon"
Majstro Shifu de la filmo "Kung Fu Panda"

Aŭtomatigo ĉe CIAN komenciĝis 14 jarojn post kiam la firmao estis fondita. En tiu tempo ekzistis 35 homoj en la evoluigteamo. Malfacile kredi, ĉu ne? Kompreneble, aŭtomatigo ja ekzistis en iu formo, sed aparta direkto por kontinua integriĝo kaj koda livero komencis formiĝi en 2015. 

En tiu tempo, ni havis grandegan monoliton de Python, C# kaj PHP, deplojitan sur Linukso/Vindozaj serviloj. Por deploji ĉi tiun monstron, ni havis aron da skriptoj, kiujn ni rulis permane. Estis ankaŭ la muntado de la monolito, kiu alportis doloron kaj suferon pro konfliktoj dum kunfandado de branĉoj, korektado de difektoj kaj rekonstruado "kun malsama aro de taskoj en la konstruo." Simpligita procezo aspektis jene:

De skriptoj ĝis nia propra platformo: kiel ni aŭtomatigis disvolviĝon ĉe CIAN

Ni ne estis feliĉaj kun ĉi tio, kaj ni volis konstrui ripeteblan, aŭtomatigitan kaj regeblan konstruan kaj deplojan procezon. Por tio ni bezonis CI/KD-sistemon, kaj ni elektis inter la senpaga versio de Teamcity kaj la senpaga versio de Jenkins, ĉar ni laboris kun ili kaj ambaŭ konvenis al ni laŭ la aro de funkcioj. Ni elektis Teamcity kiel pli lastatempan produkton. Tiutempe, ni ankoraŭ ne uzis mikroservan arkitekturon kaj ne atendis grandan nombron da taskoj kaj projektoj.

Ni venas al la ideo de nia propra sistemo

La efektivigo de Teamcity forigis nur parton de la mana laboro: kio restas estas la kreado de Pull Requests, reklamado de temoj laŭ statuso en Jira, kaj elekto de temoj por liberigo. La Teamcity-sistemo ne plu povis elteni ĉi tion. Necesis elekti la vojon de plia aŭtomatigo. Ni pripensis eblojn por labori kun skriptoj en Teamcity aŭ ŝanĝi al triaj aŭtomatigaj sistemoj. Sed fine ni decidis, ke ni bezonas maksimuman flekseblecon, kiun nur nia propra solvo povas havigi. Tiel aperis la unua versio de la interna aŭtomatiga sistemo nomata Integro.

Teamcity traktas aŭtomatigon je la nivelo de lanĉado de la konstruaj kaj deplojprocezoj, dum Integro temigis altnivelan aŭtomatigon de evoluprocezoj. Necesis kombini laboron kun problemoj en Jira kun prilaborado de rilata fontkodo en Bitbucket. En ĉi tiu etapo, Integro komencis havi siajn proprajn laborfluojn por labori kun taskoj de malsamaj tipoj. 

Pro la pliiĝo de aŭtomatigo en komercaj procezoj, la nombro da projektoj kaj kuroj en Teamcity pliiĝis. Do venis nova problemo: unu senpaga Teamcity-instanco ne sufiĉis (3 agentoj kaj 100 projektoj), ni aldonis alian petskribon (3 pliaj agentoj kaj 100 projektoj), poste alian. Kiel rezulto, ni finis kun sistemo de pluraj aretoj, kiu estis malfacile administrebla:

De skriptoj ĝis nia propra platformo: kiel ni aŭtomatigis disvolviĝon ĉe CIAN

Kiam la demando pri 4-a okazo ekestis, ni rimarkis, ke ni ne povas daŭrigi vivi tiel, ĉar la totalaj kostoj de subteni 4-instancojn ne plu estis en iuj limoj. La demando ekestis pri aĉeto de pagita Teamcity aŭ elekto de senpagaj Jenkins. Ni faris kalkulojn pri okazoj kaj aŭtomatigaj planoj kaj decidis, ke ni loĝos sur Jenkins. Post kelkaj semajnoj, ni ŝanĝis al Jenkins kaj forigis iujn el la kapdoloroj asociitaj kun konservado de pluraj okazoj de Teamcity. Tial ni povis koncentriĝi pri evoluigado de Integro kaj personigo de Jenkins por ni mem.

Kun la kresko de baza aŭtomatigo (en la formo de aŭtomata kreado de Pull Requests, kolekto kaj publikigo de Koda kovrado kaj aliaj kontroloj), ekzistas forta deziro forlasi manajn eldonojn kiel eble plej multe kaj doni ĉi tiun laboron al robotoj. Krome, la firmao komencis moviĝi al mikroservoj ene de la firmao, kiuj postulis oftajn eldonojn, kaj aparte unu de la alia. Jen kiel ni iom post iom venis al aŭtomataj eldonoj de niaj mikroservoj (ni nuntempe liberigas la monoliton permane pro la komplekseco de la procezo). Sed, kiel kutime okazas, aperis nova komplekseco. 

Ni aŭtomatigas testadon

De skriptoj ĝis nia propra platformo: kiel ni aŭtomatigis disvolviĝon ĉe CIAN

Pro la aŭtomatigo de eldonoj, evoluprocezoj akcelis, parte pro la saltado de kelkaj testaj etapoj. Kaj ĉi tio kaŭzis provizoran perdon de kvalito. Ĝi sonas bagatela, sed kune kun la akcelo de eldonoj, estis necese ŝanĝi la produkt-disvolvan metodon. Necesis pensi pri aŭtomatigo de testado, instigi personan respondecon (ĉi tie ni parolas pri "akceptado de la ideo en la kapo", ne monaj monpunoj) de la programisto pro la liberigita kodo kaj eraroj en ĝi, kaj ankaŭ pri la decido pri tio. liberigi/ne liberigi taskon per aŭtomata deplojo. 

Forigante kvalitajn problemojn, ni venis al du gravaj decidoj: ni komencis fari kanariajn provojn kaj enkondukis aŭtomatan monitoradon de la erara fono kun aŭtomata respondo al ĝia troo. La unua solvo ebligis trovi evidentajn erarojn antaŭ ol la kodo estis plene liberigita en produktadon, la dua reduktis la respondtempon al problemoj en produktado. Eraroj, kompreneble, okazas, sed ni pasigas la plej grandan parton de nia tempo kaj penado ne por korekti ilin, sed por minimumigi ilin. 

Aŭtomatiga Teamo

Ni nuntempe havas kunlaborantaron de 130 programistoj, kaj ni daŭrigas kreskas. La teamo por kontinua integriĝo kaj koda livero (ĉi-poste nomata la teamo Deploy and Integration aŭ DI) konsistas el 7 homoj kaj funkcias en 2 direktoj: disvolviĝo de la platformo de aŭtomatigo Integro kaj DevOps. 

DevOps respondecas pri la Dev/Beta-medio de la CIAN-ejo, la Integro-medio, helpas programistojn solvi problemojn kaj disvolvas novajn alirojn por grimpi mediojn. La disvolva direkto de Integro traktas kaj Integro mem kaj rilatajn servojn, ekzemple, kromaĵojn por Jenkins, Jira, Confluence, kaj ankaŭ disvolvas helpajn ilojn kaj aplikojn por evoluigaj teamoj. 

La DI-teamo laboras kunlabore kun la Platform-teamo, kiu evoluigas la arkitekturon, bibliotekojn kaj evolualirojn interne. Samtempe, ajna programisto ene de CIAN povas kontribui al aŭtomatigo, ekzemple, fari mikroaŭtomatigon laŭ la bezonoj de la teamo aŭ dividi bonegan ideon pri kiel fari aŭtomatigon eĉ pli bona.

Tavolkuko de aŭtomatigo ĉe CIAN

De skriptoj ĝis nia propra platformo: kiel ni aŭtomatigis disvolviĝon ĉe CIAN

Ĉiuj sistemoj implikitaj en aŭtomatigo povas esti dividitaj en plurajn tavolojn:

  1. Eksteraj sistemoj (Jira, Bitbucket, ktp.). Disvolvaj teamoj laboras kun ili.
  2. Integra platformo. Plej ofte, programistoj ne laboras kun ĝi rekte, sed ĝi estas tio, kio daŭrigas la tutan aŭtomatigon funkcii.
  3. Livero, instrumentado kaj malkovroservoj (ekzemple, Jeknins, Konsulo, Nomado). Kun ilia helpo, ni deplojas kodon sur serviloj kaj certigas, ke servoj funkcias inter si.
  4. Fizika tavolo (serviloj, OS, rilata programaro). Nia kodo funkcias je ĉi tiu nivelo. Ĉi tio povas esti aŭ fizika servilo aŭ virtuala (LXC, KVM, Docker).

Surbaze de ĉi tiu koncepto, ni dividas respondecajn kampojn ene de la DI-teamo. La unuaj du niveloj estas en la areo de respondeco de la direkto de disvolviĝo de Integro, kaj la lastaj du niveloj jam estas en la areo de respondeco de DevOps. Ĉi tiu disiĝo permesas al ni koncentriĝi pri taskoj kaj ne malhelpas interagon, ĉar ni estas proksimaj unu al la alia kaj konstante interŝanĝas scion kaj sperton.

Nerompita

Ni koncentriĝu pri Integro kaj komencu per la teknologia stako:

  • CentOS 7
  • Docker + Nomado + Konsulo + Trezorejo
  • Java 11 (la malnova Integro-monolito restos sur Java 8)
  • Spring Boot 2.X + Spring Cloud Config
  • PostgreSql 11
  • KunikloMQ 
  • Apache Ignite
  • Camunda (enigita)
  • Grafana + Grafito + Prometeo + Jaeger + ELK
  • Reta UI: Reagi (CSR) + MobX
  • SSO: Ŝlosilmantelo

Ni aliĝas al la principo de mikroserva disvolviĝo, kvankam ni havas heredaĵon en formo de monolito de frua versio de Integro. Ĉiu mikroservo funkcias en sia propra Docker-ujo, kaj la servoj komunikas inter si per HTTP-petoj kaj RabbitMQ-mesaĝoj. Mikroservoj trovas unu la alian per Konsulo kaj faras peton al ĝi, pasante rajtigon per SSO (Keycloak, OAuth 2/OpenID Connect).

De skriptoj ĝis nia propra platformo: kiel ni aŭtomatigis disvolviĝon ĉe CIAN

Kiel realviva ekzemplo, konsideru interagi kun Jenkins, kiu konsistas el la sekvaj paŝoj:

  1. La mikroservo pri administrado de laborfluo (ĉi-poste nomata la mikroservo de Fluo) volas ruli konstruon en Jenkins. Por fari tion, li uzas Consul por trovi la IP:PORT de la mikroservo por integriĝo kun Jenkins (ĉi-poste nomata Jenkins mikroservo) kaj sendas nesinkronan peton al ĝi por komenci la konstruon en Jenkins.
  2. Post ricevi peton, la mikroservo de Jenkins generas kaj respondas per Job ID, kiu tiam povas esti uzata por identigi la rezulton de la laboro. Samtempe, ĝi ekigas la konstruon en Jenkins per REST API-voko.
  3. Jenkins plenumas la konstruon kaj, post kompletigo, sendas rethokon kun la ekzekutrezultoj al la mikroservo de Jenkins.
  4. La mikroservo de Jenkins, ricevinte la rethokon, generas mesaĝon pri la kompletigo de peto-prilaborado kaj aliĝas al ĝi la ekzekutrezultojn. La generita mesaĝo estas sendita al la RabbitMQ-vico.
  5. Per RabbitMQ, la publikigita mesaĝo atingas la Flow-mikroservon, kiu ekscias pri la rezulto de prilaborado de sia tasko kongruante kun la Job-ID de la peto kaj la ricevita mesaĝo.

Nun ni havas ĉirkaŭ 30 mikroservojn, kiuj povas esti dividitaj en plurajn grupojn:

  1. Administrado de agordo.
  2. Informoj kaj interago kun uzantoj (mesaĝiloj, poŝto).
  3. Laborante kun fontkodo.
  4. Integriĝo kun deplojiloj (jenkins, nomado, konsulo, ktp.).
  5. Monitorado (eldonoj, eraroj, ktp.).
  6. Retaj utilecoj (UI por administri testajn mediojn, kolekti statistikojn, ktp.).
  7. Integriĝo kun taskaj spuriloj kaj similaj sistemoj.
  8. Administrado de laborfluo por malsamaj taskoj.

Laborfluaj taskoj

Integro aŭtomatigas agadojn ligitajn al la taskovivciklo. En simpligitaj terminoj, la vivociklo de tasko estos komprenata kiel la laborfluo de tasko en Jira. Niaj evoluaj procezoj havas plurajn variadojn de laborfluo depende de la projekto, la speco de tasko kaj la elektoj elektitaj en aparta tasko. 

Ni rigardu la laborfluon, kiun ni plej ofte uzas:

De skriptoj ĝis nia propra platformo: kiel ni aŭtomatigis disvolviĝon ĉe CIAN

En la diagramo, la ilaro indikas ke transiro estas vokita aŭtomate fare de Integro, dum la homa figuro indikas ke transiro estas vokita permane fare de persono. Ni rigardu plurajn vojojn, kiujn tasko povas preni en ĉi tiu laborfluo.

Tute mana testado sur DEV+BETA sen kanariaj testoj (kutime jen kiel ni liberigas monoliton):

De skriptoj ĝis nia propra platformo: kiel ni aŭtomatigis disvolviĝon ĉe CIAN

Povas ekzisti aliaj transiraj kombinaĵoj. Kelkfoje la vojo, kiun temo prenos, povas esti elektita per elektoj en Jira.

Taska movado

Ni rigardu la ĉefajn paŝojn, kiuj estas faritaj kiam tasko moviĝas tra la laborfluo "DEV Testing + Canary Tests":

1. La programisto aŭ PM kreas la taskon.

2. La programisto prenas la taskon por labori. Post kompletigo, ĝi ŝanĝas al IN REVIEW statuso.

3. Jira sendas Webhook al la mikroservo Jira (respondeca pri integriĝo kun Jira).

4. La mikroservo Jira sendas peton al la Fluo-servo (respondeca pri internaj laborfluoj en kiuj laboro estas farita) por komenci la laborfluon.

5. Ene de la Flua servo:

  • Recenzistoj estas asignitaj al la tasko (Uzantoj mikroservo, kiu scias ĉion pri uzantoj + Jira mikroservo).
  • Per la mikroservo Fonto (ĝi scias pri deponejoj kaj branĉoj, sed ne funkcias kun la kodo mem), oni serĉas deponejojn, kiuj enhavas branĉon de nia afero (por simpligi la serĉon, la nomo de la branĉo koincidas kun la afero). nombro en Jira). Plej ofte, tasko havas nur unu branĉon en unu deponejo; tio simpligas administradon de la deploja atendovico kaj reduktas konekteblecon inter deponejoj.
  • Por ĉiu trovita branĉo, la sekva sekvenco de agoj estas farita:

    i) Ĝisdatigi la majstran branĉon (Git-mikroservo por labori kun kodo).
    ii) La branĉo estas blokita de ŝanĝoj fare de la programisto (Bitbucket-mikroservo).
    iii) Tiro-Peto estas kreita por ĉi tiu branĉo (Mikroservo de Bitbucket).
    iv) Mesaĝo pri nova Pull-Peto estas sendita al programistaj babilejoj (Informu mikroservon pri laboro kun sciigoj).
    v) Konstrui, testi kaj deploji taskojn estas komencitaj sur DEV (Jenkins mikroservo por labori kun Jenkins).
    vi) Se ĉiuj antaŭaj paŝoj estas kompletigitaj sukcese, tiam Integro metas sian Aprobi en la Pull-Peto (Bitbucket-mikroservo).

  • Integro atendas Aprobu en Pull-Peto de elektitaj recenzistoj.
  • Tuj kiam ĉiuj necesaj aproboj estas ricevitaj (inkluzive de aŭtomataj testoj pasis pozitive), Integro transdonas la taskon al Test on Dev (Jira mikroservo).

6. Testistoj testas la taskon. Se ne estas problemoj, tiam la tasko estas translokigita al la stato Preta Por Konstruo.

7. Integro "vidas" ke la tasko estas preta por liberigo kaj komencas sian deplojon en kanaria reĝimo (Jenkins mikroservo). Preteco por liberigo estas determinita de aro de reguloj. Ekzemple, la tasko estas en la bezonata stato, ne ekzistas ŝlosiloj en aliaj taskoj, nuntempe ne estas aktivaj alŝutoj de ĉi tiu mikroservo, ktp.

8. La tasko estas translokigita al Kanaria statuso (Jira mikroservo).

9. Jenkins lanĉas deplojan taskon per Nomad en kanaria reĝimo (kutime 1-3 okazoj) kaj sciigas la liberigon-monitorservon (DeployWatch-mikroservo) pri la deplojo.

10. La mikroservo DeployWatch kolektas la erarfonon kaj reagas al ĝi, se necese. Se la erarfono estas superita (la fonnormo estas kalkulita aŭtomate), programistoj estas sciigitaj per la Notify-mikroservo. Se post 5 minutoj la programisto ne respondis (alklakis Reverti aŭ Restu), tiam aŭtomata malfunkciigo de la kanariaj petskriboj estas lanĉita. Se la fono ne estas superita, tiam la programisto devas mane lanĉi la taskan deplojon al Produktado (alklakante butonon en la UI). Se ene de 60 minutoj la programisto ne lanĉis la deplojon al Produktado, tiam la kanariaj petskriboj ankaŭ estos refunkciigitaj pro sekurecaj kialoj.

11. Post lanĉo de la deplojo al Produktado:

  • La tasko estas transdonita al Produktada stato (Jira mikroservo).
  • La mikroservo de Jenkins komencas la procezon de deplojo kaj sciigas la mikroservon DeployWatch pri la deplojo.
  • La mikroservo DeployWatch kontrolas, ke ĉiuj ujoj en Produktado estis ĝisdatigitaj (ekzistis kazoj kiam ne ĉiuj estis ĝisdatigitaj).
  • Per la mikroservo Notify, sciigo pri la rezultoj de la deplojo estas sendita al Produktado.

12. Programistoj havos 30 minutojn por komenci refari taskon de Produktado se malĝusta mikroserva konduto estas detektita. Post ĉi tiu tempo, la tasko estos aŭtomate kunfandita en majstron (Git-mikroservo).

13. Post sukcesa kunfandiĝo en majstron, la taskostato estos ŝanĝita al Fermita (Jira mikroservo).

La diagramo ne ŝajnigas esti tute detala (en realeco estas eĉ pli da paŝoj), sed ĝi permesas taksi la gradon de integriĝo en procezojn. Ni ne konsideras ĉi tiun skemon ideala kaj plibonigas la procezojn de aŭtomata liberigo kaj disfalda subteno.

Kio sekvas

Ni havas grandajn planojn por la disvolviĝo de aŭtomatigo, ekzemple, forigi manajn operaciojn dum monolit-eldonoj, plibonigante monitoradon dum aŭtomata deplojo kaj plibonigante interagon kun programistoj.

Sed ni haltu ĉi tie nuntempe. Ni kovris multajn temojn en la aŭtomatiga revizio supraĵe, iuj tute ne estis tuŝitaj, do ni volonte respondos demandojn. Ni atendas sugestojn pri kio kovri detale, skribu en la komentoj.

fonto: www.habr.com

Aldoni komenton