Koodidelt oma platvormini: kuidas me automatisime arendust CIANis

Koodidelt oma platvormini: kuidas me automatisime arendust CIANis

RIT 2019 meie kolleeg Aleksandr Korotkov tegi aruanne esitluse arenduse automatiseerimisest CIANis: elu ja töö lihtsustamiseks kasutame oma platvormi Integro. See jälgib ülesannete elutsüklit, vabastab arendajaid rutiinsetest toimingutest ja vähendab märgatavalt bugide arvu tootmisjärgus. Selles postituses täiendame Aleksandri ettekannet ja räägime, kuidas läbisime teekonna lihtsatest skriptidest open source toodete ühendamise kaudu oma platvormini ja millega tegeleb meie automatiseerimise erimeeskond.
 

Nulltase

«Nulltaset pole, ma sellest ei tea»
Shifu Meister filmist «Kung Fu Panda»

Automatiseerimine CIANis algas 14 aastat pärast ettevõtte asutamist. Sel ajal oli arendustiimis 35 inimest. Raske uskuda, eks? Muidugi, mingil kujul automatiseerimine siiski olemas oli, kuid eraldi suund pideva integreerimise ja koodi tarnimise osas hakkas kujunema 2015. aastal. 

Siis oli meil suur monoliit Pythonist, C#-st ja PHP-st, mis oli paigaldatud Linuxi/Windows serveritele. Selle koletise juurutamiseks oli meil käsitsi käivitatav skriptide kogum. Samuti oli meil monoliidi kogumine, mis põhjustas valu ja kannatusi, kuna harude liitmise konfliktid, defektide parandamised ja „teise ülesannete kogumiga koostamine“ valmistasid meelehärmi. Üks lihtne protsess nägi välja järgmine:

Koodidelt oma platvormini: kuidas me automatisime arendust CIANis

Meid see ei rahuldanud, ja me soovisime luua korduva, automatiseeritud ja hallatava koostamise ja juurutamise protsessi. Selle jaoks oli meil vaja CI/CD süsteemi, ning me valisime tasuta Teamcity ja tasuta Jenkins'i vahel, kuna olime nendega töötanud ja mõlemad pakkusid meile sobivaid funktsioone. Valisime Teamcity, kuna see tundus uuem toode. Siis me veel ei kasutanud mikroteenuste arhitektuuri ega lootnud suurele hulgale ülesannetele ja projektidele.

Jõuame oma süsteemi idee juurde

Teamcity rakendamine vähendas vaid osa käsitööst: alles jäi veel Pull Requestide loomine, ülesannete edasiviimine Jira staatuste kaudu ja ülesannete valimine väljalaskmiseks. Selle süsteemiga Teamcity enam toime ei tulnud. Pidi valima edasise automatiseerimise tee. Kaalusime skriptide kasutamist Teamcitys või üleminekut kolmandate osapoolte automatiseerimissüsteemidele. Lõpuks otsustasime, et vajalik on maksimaalne paindlikkus, mida suudab pakkuda vaid kohandatud lahendus. Nii sai alguse esimene versioon sisemisest automatiseerimissüsteemist nimega Integro.

Teamcity tegeleb automatiseerimisega protsesside käivitamise tasemel, nagu koostamine ja juurutamine, kuid Integro keskendus kõrgema taseme arendusprotsesside automatiseerimisele. Oli vajalik liita Jira ülesannete töö koos Bitbucketis asuva lähtekoodiga. Sel hetkel hakkasid Integro sees arenema oma töövood erinevat tüüpi ülesannete töötlemiseks. 

Tänu äritegevuse automatiseerimise suurenemisele on projektide ja run'ide arv Teamcitys kasvanud. Nii tuli päevakorda uus probleem: üks tasuta Teamcity instants ei olnud piisav (3 agenti ja 100 projekti), lisasime veel ühe instantsi (veel 3 agenti ja 100 projekti), siis veel ühe. Lõpuks saime mitmest klastrist koosneva süsteemi, mida oli keeruline hallata:

Koodidelt oma platvormini: kuidas me automatisime arendust CIANis

Kui küsiti neljanda instantsi kohta, mõistsime, et nii enam edasi elada ei saa, kuna nelja instantsi ülalpidamiskulud ei mahtunud enam mingitesse raamidesse. Tuli küsimus osta tasuline Teamcity või valida tasuta Jenkins. Tegime instantside ja automatiseerimise plaanide arvutused ja otsustasime, et elame Jenkinsiga. Paar nädalat hiljem läksime üle Jenkinsile ja vabastasime end osaliselt Teamcity mitme instantsi haldamisega seotud muredest. Seetõttu suutsime keskenduda Integro arendamisele ja Jenkins enda jaoks kohandamisele.

Põhilise automatiseerimise (nt Pull Requestide automaatne loomine, koodi katvuse kogumine ja avaldamine ning muud kontrollid) kasvu tõttu tekkis püsiv soov vähendada käsitsi väljalaskeid ja anda see töö robotitele. Lisaks alustas ettevõte üleminekut mikroteenustele, mis nõudsid sagedasi ja eraldi väljalaseid. Nii jõudsime järk-järgult meie mikroteenuste automaatsete väljalasketeeni (monoliiti väljastame endiselt käsitsi protsessi keerukuse tõttu). Kuid nagu sageli juhtub, tekkis uus keerukus. 

Automatiseerime testimise

Koodidelt oma platvormini: kuidas me automatisime arendust CIANis

Tänu väljalaskmise automatiseerimisele on arendamisprotsessid kiirenema hakanud, osaliselt testimise teatud etappide vahelejätmise arvelt. See on viinud ajutise kvaliteetkao tekkimiseni. Kõlab labaselt, aga koos väljalaskmiste kiirenemisega tuli muuta ka toote arenduse metoodikat. Oli vajalik mõelda testimise automatiseerimisele, isikliku vastutuse määramisele (siin on jutt „idee peas hoidmisest“, mitte rahalistest trahvidest) arendajatele nende kirjutatud koodi ja sealsete vigade eest, samuti otsusele ülesande väljalaskmise/mitte väljalaskmise osas automaatse juurutamise kaudu. 

Kvaliteediprobleemide lahendamisel jõudsime kahe olulise lahenduseni: hakkasime läbiviima kanaritele katsed ja juurutame automaatset veamonitorimist automaatselt reageerimisega selle ületamisele. Esimene lahendus võimaldas leida ilmseid vigu enne, kui kood jõuab tootmisjärku, teine aga vähendas reageerimisaega tootmisprotsessis. Vigu esineb, aga me kulutame suurema osa ajast ja jõududest mitte parandamisele, vaid minimiseerimisele. 

Automatiseerimise meeskond

Praegu on meie ridades 130 arendajat ja me jätkame kasvamist. Jätkuva integratsiooni ja koodi kohaletoimetamise meeskond (edaspidi - Deploy and Integration meeskond või DI) koosneb seitsmest inimesest ja töötab kahes suunas: Integro automatiseerimise platvormi arendamine ja DevOps. 

DevOps vastutab CIANi saidi Dev/Beta keskkondade, Integro keskkondade eest, aitab arendajatel probleemide lahendamisel ning arendab uusi lähenemisviise keskkondade skaleerimiseks. Integro arendusmeeskond keskendub nii Integrole kui ka seotud teenustele, näiteks Lisa- ja Lisade jaoks Jenkinsile, Jira, Confluence'ile, ning arendab ka abiteenuseid ja rakendusi arendajate meeskondadele. 

DI meeskond teeb koostööd Platvormi meeskonnaga, mis tegeleb ettevõtte sisese arengu arhitektuuri, raamatukogude ja arenduse lähenemisviiside väljatöötamisega. Samuti saab iga arendaja CIANis panustada automatiseerimisse, näiteks luua mikroomatiseerimise vastavalt meeskonna vajadustele või jagada häid ideid automatiseerimise parandamiseks.

CIANi automatiseerimise kihiline kook

Koodidelt oma platvormini: kuidas me automatisime arendust CIANis

Kõik automatiseerimises osalevad süsteemid võib jagada mitmeks kihiks:

  1. Väline süsteemid (Jira, Bitbucket jne). Nendega töötavad arendajate meeskonnad.
  2. Integro platvorm. Arendajad ei pruugi selle otseselt kasutada, kuid just tema toetab kogu automatiseerimise toimimist.
  3. Tarnimise, orkestreerimise ja avastamise teenused (näiteks Jenkins, Consul, Nomad). Nende abil saadame koodi serveritesse ja tagame teenuste koostöö.
  4. Füüsiline kiht (serverid, operatsioonisüsteem, seotud tarkvara). Meie kood töötab just sellel tasemel. See võib olla nii füüsiline server kui ka virtuaalne (LXC, KVM, Docker).

Selle kontseptsiooni kohaselt jagame DI meeskonnas vastutuse alasid. Kaks esimest taset kuuluvad Integro arendussuunale, kaks viimast taset aga DevOpsi vastutusalasse. Selline jaotus võimaldab keskenduda ülesannetele ja ei sega koostööd, kuna oleme üksteise lähedal ja vahetame pidevalt teadmisi ning kogemusi.

Integro

Keskendume Integrole ning alustame tehnoloogilisest virnast:

  • CentOS 7
  • Docker + Nomad + Consul + Vault
  • Java 11 (vana Integro monoliit jääb Java 8 peale)
  • Spring Boot 2.X + Spring Cloud Config
  • PostgreSQL 11
  • RabbitMQ 
  • Apache Ignite
  • Camunda (sisse embeditud)
  • Grafana + Graphite + Prometheus + Jaeger + ELK
  • Veebi liides: React (CSR) + MobX
  • SSO: Keycloak

Me järgime mikroteenuste arendamise põhimõtet, kuigi meil on legacy, mis on varasema versiooni Integro monoliit. Iga mikroteenus töötab oma docker-konteineris, teenused suhtlevad omavahel HTTP-päringute ja RabbitMQ-sõnumite kaudu. Mikroteenused leiavad üksteist Consul'i kaudu ja esitavad sellele päringu, läbides autentimise SSO (Keycloak, OAuth 2/OpenID Connect) kaudu.

Koodidelt oma platvormini: kuidas me automatisime arendust CIANis

Reaalse näitena vaatleme koostööd Jenkinsiga, mis koosneb järgmistest sammudest:

  1. Töövoo haldamise mikroteenus (edaspidi Flow-mikroteenus) soovib Jenkinsis koostamist alustada. Selleks leiab ta Consul'i kaudu Jenkinsiga integreerimise mikroteenuse (edaspidi Jenkins-mikroteenus) IP:PORT ja saadab sellele asünkroonse päringu Jenkinsis koostamise alustamiseks.
  2. Jenkins-mikroteenus pärast päringu saamist koostab ja tagastab Job ID, mille järgi saab hiljem tulemuse identifitseerida. Samuti käivitab ta Jenkinsis koostamise läbi REST API kutse.
  3. Jenkins viib läbi koostamise ja pärast selle lõppemist saadab webhook'i tulemustega tagasi Jenkins-mikroteenusele.
  4. Jenkins-mikroteenus, pärast webhook'i saamist, koostab töötlemise lõppetappide teate ja lisab sellele teostuse tulemused. Koostatud teade saadetakse RabbitMQ järjekorda.
  5. RabbitMQ kaudu jõuab avaldatud teade Flow-mikroteenusele, mis saab teada oma ülesande töötlemise tulemusest, võrreldes Job ID-d päringust ja saadud teates.

Praegu on meil umbes 30 mikroteenust, mida saab jagada mitmeks grupiks:

  1. Konfigureerimise haldamine.
  2. Teabe edastamine ja suhtlemine kasutajatega (messengerid, e-post).
  3. Töö lähtekoodiga.
  4. Integratsioon juurutustööriistadega (jenkins, nomad, consul jne).
  5. Jälgimine (väljalasked, vead jne).
  6. Veebitööriistad (kasutajaliides testkeskkondade haldamiseks, statistika kogumiseks jne).
  7. Integratsioon ülesannejälgijate ja sarnaste süsteemidega.
  8. Töövoo haldamine erinevate ülesannete jaoks.

Ülesande töövoog

Integro automatiseerib ülesande elutsükliga seotud toimingud. Lihtsustatult mõistame ülesande elutsüklina Jira töövoogu. Meie arendusprotsessides on sõltuvalt projektist, ülesande tüübist ja konkreetses ülesandes valitud valikutest mitu töövoo varianti. 

Vaadakem töövoogu, mida kasutame kõige sagedamini:

Koodidelt oma platvormini: kuidas me automatisime arendust CIANis

Diagrammil näitab hammasratas, et üleminek toimub automaatselt Integro poolt, samal ajal kui inimese kujuke tähendab, et üleminek toimub käsitsi inimese poolt. Vaadakem mitmeid teid, mille kaudu ülesanne võib selles töövoos liikuda.

Täielik käsitsi testimine DEV+BETA ilma kanarakkude testideta (tavaliselt nii väljastame monoliiti):

Koodidelt oma platvormini: kuidas me automatisime arendust CIANis

Samas võivad olla ka teised ülemiste kombinatsioonid. Mõnikord saab valida, milliseid teid ülesanne järgib, Jira valikute kaudu.

Ülesande liikumine

Vaadakem põhietappe, mis täidetakse ülesande liikumisel töövoos "Testimine DEV + kanarakkude testid":

1. Arendaja või PM loob ülesande.

2. Arendaja võtab ülesande tööle. Pärast lõpetamist viib ta selle olekusse IN REVIEW.

3. Jira saadab Webhooki Jira mikroteenusele (mis vastutab Jira integreerimise eest).

4. Jira-mikrosvc saadab päringu Flow-teenusele (vastutab sisemiste töövoogude eest, milles töö toimub) töövoo käivitamiseks.

5. Flow-teenuse sees:

  • Määratakse ülesande ülevaatajad (Users-mikrosvc, mis teab kõike kasutajatest + Jira-mikrosvc).
  • Source-mikrosvc kaudu (teab reposid ja harudest, kuid ei tööta koodiga) otsitakse reposid, kus on meie ülesande haru (otsingu lihtsustamiseks haru nimi vastab Jira ülesande numbrile). Enamasti on ülesandel vaid üks haru ühes repos, mis lihtsustab juurdepääsu haldamist ja vähendab reposide vahelist seotust.
  • Iga leitud haru jaoks teostatakse järgmine tegevuste järjestus:

    i) Master-haru ühtlustamine (Git-mikrosvc koodi töötlemiseks).
    ii) Haru lukustatakse muudatuste eest arendaja poolt (Bitbucket-mikrosvc).
    iii) Loome Pull Request'i sellele harule (Bitbucket-mikrosvc).
    iv) Saadetakse teade uue Pull Request'i kohta arendajate vestlustesse (Notify-mikrosvc teavituste töötlemiseks).
    v) Alustatakse ülesande ehitamist, testimist ja juurutamist DEV-is (Jenkins-mikrosvc Jenkinsiga töötamiseks).
    vi) Kui kõik eelnevad punktid on edukalt lõpetatud, siis Integro annab oma Approve Pull Requestis (Bitbucket-mikroteenus).

  • Integro ootab Approve'i Pull Requestis määratud ülevaatajatelt.
  • Kui kõik vajalikud Approve'id on saadud (sealhulgas automaatsete testide positiivne läbimine), viib Integro ülesande staatuse Test on Dev (Jira-mikroteenus).

6. Testijad teostavad ülesande testimise. Kui probleeme ei ole, muudavad nad ülesande staatuseks Ready For Build.

7. Integro "näeb", et ülesanne on valmis välja andmiseks, ja käivitab selle deploy kanarie režiimis (Jenkins-mikroteenus). Valmidus väljaandmiseks määratakse reeglite kogumi põhjal. Näiteks peab ülesanne olema sobivas staatuses, teisi ülesandeid ei tohi blokeerida, aktiivseid väljatöötamisi selle mikroteenuse osas ei tohi hetkel olla jne.

8. Ülesanne muudetakse staatuseks Canary (Jira-mikroteenus).

9. Jenkins käivitab läbi Nomad ülesande väljatöötamise kanarie režiimis (tavaliselt 1-3 instantsi) ja teavitab väljatöötamisest teenust, mis jälgib väljalaskmisi (DeployWatch-mikroteenus).

10. DeployWatch mikroteenus kogub veateateid ja reageerib, kui see on vajalik. Kui veateateid on liiga palju (norm arvutatakse automaatselt), teavitatakse arendajaid Notify mikroteenuse kaudu. Kui arendaja ei reageeri 5 minuti jooksul (ei vajuta Revert või Stay), siis käivitatakse automaatne tagasi tõmbamine kanarootorite instantsidele. Kui veateateid pole, peab arendaja käsitsi käivitama ülesande juurutamise tootmisserverisse (vajutades nuppu kasutajaliideses). Kui arendaja ei käivita 60 minuti jooksul juurutamist tootmisserverisse, siis kanarootorite instantsid eemaldatakse ka turvalisuse kaalutlustel.

11. Pärast juurutamise käivitamist tootmisserverisse:

  • Ülesanne muudetakse tootmisstaatusesse (Jira mikroteenus).
  • Jenkins mikroteenus käivitab juurutamisprotsessi ja teavitab DeployWatch mikroteenust.
  • DeployWatch mikroteenus kontrollib, et kõik konteinerid oleksid tootmisserveris uuendatud (on olnud juhtumeid, kus mitte kõik uuendati).
  • Notify mikroteenus saadab teate juurutamise tulemustest tootmisserveris.

12. Arendajatel on 30 minutit aega, et käivitada ülesande tagasivõtmine tootmisest, kui mikroteenus käitub ebanormaalselt. Kui see aeg möödub, sisestatakse ülesanne automaatselt masterisse (Git-mikroteenus).

13. Pärast eduka merge'i toimimist masterisse muutub ülesande staatuseks Closed (Jira-mikroteenus).

Schema ei pretendeeri täielikule detailsusele (reaalsuses on samme veel rohkem), kuid võimaldab hinnata integreerimise astet protsessidesse. Me ei pea seda skeemi ideaaliks ja täiustame automatiseerimisprotsesse ja juurutamist.

Mis edasi

Meil on suured plaanid automatiseerimise arendamiseks, näiteks käsitsi toimingute lõpetamine monoliitide juurutamise ajal, automaatse juurutamise käigus jälgimise parandamine, arendajatega suhtlemise täiustamine.

Kuid jääme siinkohal peatuma. Paljusid automatiseerimise ülevaate teemasid oleme katnud pinnalt, mõnedest pole üldse rääkinud, seega vastame hea meelega küsimustele. Ootame ettepanekuid, mida üksikasjalikumalt käsitleda, kirjutage kommentaarides.

Allikas: habr.com

Osta usaldusväärne veebihosting DDoS kaitsega, VPS VDS serverid 🔥 Osta usaldusväärne veebihosting DDoS kaitsega, VPS VDS serverid | ProHoster