Skripteistä omalle alustallemme: kuinka automatisoimme kehitystyötä CIANissa

Skripteistä omalle alustallemme: kuinka automatisoimme kehitystyötä CIANissa

RIT 2019:ssä kollegamme Alexander Korotkov teki raportti CIANin kehityksen automatisoinnista: elämän ja työn yksinkertaistamiseksi käytämme omaa Integro-alustaamme. Se seuraa tehtävien elinkaarta, vapauttaa kehittäjät rutiininomaisista toiminnoista ja vähentää merkittävästi tuotannon bugien määrää. Tässä viestissä täydennämme Alexanderin raporttia ja kerromme, kuinka pääsimme yksinkertaisista skripteistä avoimen lähdekoodin tuotteiden yhdistämiseen oman alustamme kautta ja mitä erillinen automaatiotiimimme tekee.
 

Nollataso

"Nollatasoa ei ole olemassa, en tiedä sellaista"
Mestari Shifu elokuvasta "Kung Fu Panda"

Automaatio CIANilla alkoi 14 vuotta yrityksen perustamisen jälkeen. Tuolloin kehitystiimissä oli 35 henkilöä. Vaikea uskoa, eikö? Tietysti automaatiota oli jossain muodossa, mutta erillinen suunta jatkuvalle integraatiolle ja koodin toimittamiselle alkoi muotoutua vuonna 2015. 

Tuolloin meillä oli valtava Python-, C#- ja PHP-monoliitti asennettuna Linux/Windows-palvelimille. Tämän hirviön käyttöönottoa varten meillä oli joukko skriptejä, jotka suoritimme manuaalisesti. Mukana oli myös monoliitin kokoaminen, joka toi tuskaa ja kärsimystä ristiriitojen vuoksi oksien yhdistämisessä, vikojen korjaamisessa ja uudelleenrakentamisessa "rakennuksen eri tehtävissä". Yksinkertaistettu prosessi näytti tältä:

Skripteistä omalle alustallemme: kuinka automatisoimme kehitystyötä CIANissa

Emme olleet tyytyväisiä tähän, ja halusimme rakentaa toistettavan, automatisoidun ja hallittavan rakennus- ja käyttöönottoprosessin. Tätä varten tarvitsimme CI/CD-järjestelmän ja valitsimme Teamcityn ilmaisen version ja Jenkinsin ilmaisen version välillä, koska työskentelimme heidän kanssaan ja molemmat sopivat meille toimintojen suhteen. Valitsimme Teamcityn uudemmaksi tuotteeksi. Tuolloin emme olleet vielä käyttäneet mikropalveluarkkitehtuuria emmekä odottaneet suurta määrää tehtäviä ja projekteja.

Tulemme ajatukseen omasta järjestelmästämme

Teamcityn käyttöönotto poisti vain osan manuaalisesta työstä: jäljelle jää Pull Requests -pyyntöjen luominen, ongelmien edistäminen tilan mukaan Jirassa ja julkaisujen valinta. Teamcity-järjestelmä ei enää kestänyt tätä. Oli tarpeen valita jatkoautomaation polku. Harkitsemme vaihtoehtoja skriptien kanssa työskentelemiseen Teamcityssä tai siirtymiseen kolmannen osapuolen automaatiojärjestelmiin. Mutta lopulta päätimme, että tarvitsemme maksimaalista joustavuutta, jota vain oma ratkaisumme voi tarjota. Näin ilmestyi ensimmäinen versio sisäisestä automaatiojärjestelmästä nimeltä Integro.

Teamcity käsittelee automatisointia rakennus- ja käyttöönottoprosessien käynnistämisen tasolla, kun taas Integro keskittyi kehitysprosessien huipputason automatisointiin. Oli tarpeen yhdistää työ Jiran ongelmiin liittyvien lähdekoodien käsittelyyn Bitbucketissa. Tässä vaiheessa Integrolla alkoi olla omat työnkulkunsa erityyppisten tehtävien parissa työskentelemiseen. 

Liiketoimintaprosessien automaation lisääntymisen myötä projektien ja ajojen määrä Teamcityssä on lisääntynyt. Niinpä tuli uusi ongelma: yksi ilmainen Teamcity-instanssi ei riittänyt (3 agenttia ja 100 projektia), lisäsimme toisen ilmentymän (3 agenttia lisää ja 100 projektia), sitten toisen. Tuloksena päädyimme useiden klustereiden järjestelmään, jota oli vaikea hallita:

Skripteistä omalle alustallemme: kuinka automatisoimme kehitystyötä CIANissa

Kun kysymys 4:stä tapauksesta heräsi, tajusimme, että emme voi jatkaa elämäämme näin, koska 4 tapauksen tukemisen kokonaiskustannukset eivät enää olleet rajoissa. Heräsi kysymys maksullisen Teamcityn ostamisesta tai ilmaisen Jenkinsin valitsemisesta. Teimme laskelmia instansseista ja automaatiosuunnitelmista ja päätimme, että elämme Jenkinsillä. Muutaman viikon kuluttua vaihdoimme Jenkinsiin ja poistimme osan päänsärystä, joka liittyi useiden Teamcity-instanssien ylläpitoon. Siksi pystyimme keskittymään Integron kehittämiseen ja Jenkinsin räätälöimiseen itsellemme.

Perusautomaation kasvun myötä (automaattisen vetopyyntöjen luomisen, koodin kattavuuden ja muiden tarkistusten keräämisen ja julkaisemisen muodossa) on vahva halu luopua manuaalisista julkaisuista mahdollisimman paljon ja antaa tämä työ roboteille. Lisäksi yritys alkoi siirtyä mikropalveluihin yrityksen sisällä, mikä edellytti toistuvia julkaisuja ja erikseen toisistaan. Näin pääsimme vähitellen mikropalveluidemme automaattisiin julkaisuihin (vapautamme tällä hetkellä monoliitin manuaalisesti prosessin monimutkaisuuden vuoksi). Mutta kuten yleensä tapahtuu, ilmaantui uusi monimutkaisuus. 

Automatisoimme testauksen

Skripteistä omalle alustallemme: kuinka automatisoimme kehitystyötä CIANissa

Julkaisujen automatisoinnin myötä kehitysprosessit ovat kiihtyneet, osittain johtuen joidenkin testausvaiheiden ohittamisesta. Ja tämä johti tilapäiseen laadun heikkenemiseen. Se kuulostaa triviaalilta, mutta julkaisujen kiihtymisen myötä tuotekehitysmetodologiaa oli tarpeen muuttaa. Oli tarpeen miettiä testauksen automatisointia, kehittäjän henkilökohtaisen vastuun juurruttamista (tässä puhumme "idean hyväksymisestä päähän", ei rahasakkoista) julkaistusta koodista ja siinä olevista virheistä sekä päätöstä vapauta/älä vapauta tehtävää automaattisen käyttöönoton avulla. 

Laatuongelmia eliminoimalla päädyimme kahteen tärkeään päätökseen: aloimme tehdä kanariatestauksia ja otimme käyttöön automaattisen virhetaustan valvonnan ja automaattisen vastauksen sen ylimäärään. Ensimmäinen ratkaisu mahdollisti ilmeisten virheiden löytämisen ennen kuin koodi otettiin kokonaan tuotantoon, toinen lyhensi vasteaikaa tuotannon ongelmiin. Virheitä tietysti tapahtuu, mutta emme käytä suurimman osan ajastamme ja vaivaamme niiden korjaamiseen, vaan niiden minimoimiseen. 

Automaatioryhmä

Meillä on tällä hetkellä 130 kehittäjää, ja jatkamme kasvaa. Jatkuvan integroinnin ja kooditoimituksen tiimi (jäljempänä Deploy and Integration tai DI-tiimi) koostuu 7 henkilöstä ja työskentelee kahdessa suunnassa: Integro-automaatioalustan ja DevOpsin kehittäminen. 

DevOps vastaa CIAN-sivuston Dev/Beta-ympäristöstä, Integro-ympäristöstä, auttaa kehittäjiä ratkaisemaan ongelmia ja kehittää uusia lähestymistapoja ympäristöjen skaalauskäyttöön. Integron kehityssuunta käsittelee sekä itse Integroa että siihen liittyviä palveluita, esimerkiksi Jenkinsin, Jiran, Confluencen lisäosia sekä kehittää apuohjelmia ja sovelluksia kehitystiimeille. 

DI-tiimi tekee yhteistyötä Platform-tiimin kanssa, joka kehittää arkkitehtuuria, kirjastoja ja kehityslähestymistapoja sisäisesti. Samaan aikaan kuka tahansa CIANin kehittäjä voi osallistua automaatioon, esimerkiksi tehdä mikroautomaatiota tiimin tarpeisiin sopivaksi tai jakaa hienon idean automaatiosta vieläkin parempaan.

Automaatiokerroskakku CIANissa

Skripteistä omalle alustallemme: kuinka automatisoimme kehitystyötä CIANissa

Kaikki automaatioon liittyvät järjestelmät voidaan jakaa useisiin kerroksiin:

  1. Ulkoiset järjestelmät (Jira, Bitbucket jne.). Kehitystiimit työskentelevät heidän kanssaan.
  2. Integro alusta. Useimmiten kehittäjät eivät työskentele sen kanssa suoraan, mutta se pitää kaiken automaation käynnissä.
  3. Toimitus-, orkestrointi- ja löytöpalvelut (esim. Jeknins, Consul, Nomad). Heidän avullaan otamme koodia käyttöön palvelimilla ja varmistamme, että palvelut toimivat keskenään.
  4. Fyysinen kerros (palvelimet, käyttöjärjestelmä, niihin liittyvät ohjelmistot). Koodimme toimii tällä tasolla. Tämä voi olla joko fyysinen tai virtuaalinen palvelin (LXC, KVM, Docker).

Tämän konseptin perusteella jaamme vastuualueet DI-tiimin sisällä. Kaksi ensimmäistä tasoa ovat Integron kehityssuunnan vastuualueella ja kaksi viimeistä tasoa ovat jo DevOpsin vastuualueella. Tämä erottaminen antaa meille mahdollisuuden keskittyä tehtäviin eikä häiritse vuorovaikutusta, koska olemme lähellä toisiamme ja vaihdamme jatkuvasti tietoja ja kokemuksia.

Ehjä

Keskitytään Integroon ja aloitetaan teknologiapinosta:

  • CentOS 7
  • Docker + Nomad + konsuli + holvi
  • Java 11 (vanha Integro-monoliitti jää Java 8:lle)
  • Spring Boot 2.X + Spring Cloud Config
  • PostgreSql 11
  • RabbitMQ 
  • Apache Ignite
  • Camunda (upotettu)
  • Grafana + grafiitti + Prometheus + jääkäri + ELK
  • Verkkokäyttöliittymä: React (CSR) + MobX
  • SSO: Avaimenperä

Noudatamme mikropalvelukehityksen periaatetta, vaikka meillä on perintöä Integron varhaisen version monoliitin muodossa. Jokainen mikropalvelu toimii omassa Docker-konttissaan, ja palvelut kommunikoivat keskenään HTTP-pyyntöjen ja RabbitMQ-sanomien kautta. Mikropalvelut löytävät toisensa Consulin kautta ja tekevät sille pyynnön välittäen valtuutuksen SSO:n (Keycloak, OAuth 2/OpenID Connect) kautta.

Skripteistä omalle alustallemme: kuinka automatisoimme kehitystyötä CIANissa

Harkitse tosielämän esimerkkinä vuorovaikutusta Jenkinsin kanssa, joka koostuu seuraavista vaiheista:

  1. Työnkulun hallinnan mikropalvelu (jäljempänä Flow-mikropalvelu) haluaa suorittaa koontiversion Jenkinsissä. Tätä varten hän etsii Consulin avulla mikropalvelun IP:PORT-osoitteen Jenkinsin kanssa integroitavaksi (jäljempänä Jenkins-mikropalvelu) ja lähettää sille asynkronisen pyynnön Jenkinsin rakentamisen aloittamisesta.
  2. Pyynnön saatuaan Jenkins-mikropalvelu luo ja vastaa työtunnuksella, jonka avulla voidaan tunnistaa työn tulos. Samaan aikaan se käynnistää Jenkinsin koontiversion REST API -kutsun kautta.
  3. Jenkins suorittaa koontiversion ja sen valmistuttua lähettää webhookin suoritustuloksineen Jenkinsin mikropalveluun.
  4. Jenkins-mikropalvelu vastaanotettuaan webhookin luo viestin pyynnön käsittelyn valmistumisesta ja liittää siihen suoritustulokset. Luotu viesti lähetetään RabbitMQ-jonoon.
  5. RabbitMQ:n kautta julkaistu viesti saapuu Flow-mikropalveluun, joka saa tietää tehtävänsä käsittelyn tuloksesta sovittamalla pyynnön ja vastaanotetun viestin Job ID:n.

Nyt meillä on noin 30 mikropalvelua, jotka voidaan jakaa useisiin ryhmiin:

  1. Kokoonpanon hallinta.
  2. Tietoa ja vuorovaikutusta käyttäjien kanssa (viestintälaitteet, posti).
  3. Työskentely lähdekoodin kanssa.
  4. Integrointi käyttöönottotyökalujen kanssa (jenkins, nomad, konsuli jne.).
  5. Valvonta (julkaisut, virheet jne.).
  6. Web-apuohjelmat (käyttöliittymä testiympäristöjen hallintaan, tilastojen keräämiseen jne.).
  7. Integrointi tehtävien seurantaan ja vastaaviin järjestelmiin.
  8. Työnkulun hallinta erilaisiin tehtäviin.

Työnkulkutehtävät

Integro automatisoi tehtävän elinkaareen liittyvät toiminnot. Yksinkertaistettuna tehtävän elinkaari ymmärretään Jiran tehtävän työnkulkuna. Kehitysprosesseillamme on useita työnkulkumuunnelmia projektista, tehtävän tyypistä ja tietyssä tehtävässä valituista vaihtoehdoista riippuen. 

Katsotaanpa useimmin käyttämäämme työnkulkua:

Skripteistä omalle alustallemme: kuinka automatisoimme kehitystyötä CIANissa

Kaaviossa hammaspyörä osoittaa, että Integro kutsuu siirtymän automaattisesti, kun taas ihmishahmo osoittaa, että henkilö kutsuu siirtymän manuaalisesti. Tarkastellaan useita polkuja, joita tehtävä voi kulkea tässä työnkulussa.

Täysin manuaalinen DEV+BETA-testaus ilman kanariatestejä (yleensä näin vapautamme monoliitin):

Skripteistä omalle alustallemme: kuinka automatisoimme kehitystyötä CIANissa

Muita siirtymäyhdistelmiä voi olla. Joskus ongelman polku voidaan valita Jiran vaihtoehdoista.

Tehtävän liike

Katsotaanpa tärkeimpiä vaiheita, jotka suoritetaan, kun tehtävä siirtyy "DEV-testaus + Canary-testit" -työnkulun läpi:

1. Kehittäjä tai PM luo tehtävän.

2. Kehittäjä ottaa tehtävän työhönsä. Kun se on valmis, se vaihtaa KATSAUS-tilaan.

3. Jira lähettää Webhookin Jiran mikropalveluun (vastaa integroinnista Jiran kanssa).

4. Jira-mikropalvelu lähettää Flow-palvelulle (vastaa sisäisistä työnkuluista, joissa työtä tehdään) pyynnön aloittaa työnkulku.

5. Flow-palvelun sisällä:

  • Tehtävään määrätään arvioijat (Käyttäjien mikropalvelu, joka tietää kaiken käyttäjistä + Jira-mikropalvelu).
  • Lähde-mikropalvelun kautta (se tietää arkistot ja haarat, mutta ei toimi itse koodin kanssa) etsitään arkistoja, jotka sisältävät ongelmamme haaran (haun yksinkertaistamiseksi haaran nimi on sama kuin ongelma numero Jirassa). Useimmiten tehtävällä on vain yksi haara yhdessä arkistossa; tämä yksinkertaistaa käyttöönottojonon hallintaa ja vähentää tietovarastojen välistä yhteyttä.
  • Jokaiselle löydetylle haaralle suoritetaan seuraava toimintosarja:

    i) Päähaaran päivittäminen (Git-mikropalvelu koodin kanssa työskentelemiseen).
    ii) Kehittäjä on estänyt haaran muutoksilta (Bitbucket-mikropalvelu).
    iii) Tälle haaralle luodaan vetopyyntö (Bitbucket-mikropalvelu).
    iv) Viesti uudesta Pull Request -pyynnöstä lähetetään kehittäjäkeskusteluihin (Notify microservice for ilmoitukset).
    v) Rakennus-, testaus- ja käyttöönottotehtävät aloitetaan DEV:ssä (Jenkinsin mikropalvelu Jenkinsin kanssa työskentelyyn).
    vi) Jos kaikki aiemmat vaiheet on suoritettu onnistuneesti, Integro asettaa hyväksynnän vetopyyntöön (Bitbucket-mikropalvelu).

  • Integro odottaa hyväksymispyyntöä nimetyiltä arvioijilta.
  • Heti kun kaikki tarvittavat hyväksynnät on saatu (mukaan lukien automaattiset testit ovat läpäisseet positiivisesti), Integro siirtää tehtävän Test on Dev (Jira-mikropalvelu) -tilaan.

6. Testaajat testaavat tehtävän. Jos ongelmia ei ole, tehtävä siirretään Ready For Build -tilaan.

7. Integro "näkee", että tehtävä on valmis julkaisuun ja aloittaa sen käyttöönoton kanaaritilassa (Jenkins-mikropalvelu). Vapautusvalmius määräytyy säännöillä. Esimerkiksi tehtävä on vaaditussa tilassa, muita tehtäviä ei ole lukittu, tämän mikropalvelun aktiivisia latauksia ei ole tällä hetkellä jne.

8. Tehtävä siirretään Kanarian tilaan (Jira-mikropalvelu).

9. Jenkins käynnistää käyttöönottotehtävän Nomadin kautta canary-tilassa (yleensä 1-3 esiintymää) ja ilmoittaa käyttöönotosta julkaisujen valvontapalvelulle (DeployWatch microservice).

10. DeployWatch-mikropalvelu kerää virhetaustan ja reagoi siihen tarvittaessa. Jos virhetausta ylittyy (taustanormi lasketaan automaattisesti), kehittäjille ilmoitetaan asiasta Notify-mikropalvelun kautta. Jos kehittäjä ei ole vastannut viiden minuutin kuluttua (napsautti Palauta tai Pysy), Canary-instanssien automaattinen palautus käynnistetään. Jos taustaa ei ylitetä, kehittäjän on käynnistettävä tehtävän käyttöönotto tuotantoon manuaalisesti (napsauttamalla painiketta käyttöliittymässä). Jos kehittäjä ei ole käynnistänyt käyttöönottoa tuotantoon 5 minuutin kuluessa, myös Canary-esiintymät palautetaan turvallisuussyistä.

11. Kun käyttöönotto on aloitettu tuotantoon:

  • Tehtävä siirtyy tuotantotilaan (Jira-mikropalvelu).
  • Jenkins-mikropalvelu aloittaa käyttöönottoprosessin ja ilmoittaa DeployWatch-mikropalvelulle käyttöönotosta.
  • DeployWatch-mikropalvelu tarkistaa, että kaikki tuotannon säilöt on päivitetty (joissakin tapauksissa kaikkia ei päivitetty).
  • Notify-mikropalvelun kautta ilmoitus käyttöönoton tuloksista lähetetään tuotantoon.

12. Kehittäjällä on 30 minuuttia aikaa aloittaa tehtävän peruuttaminen tuotannosta, jos havaitaan virheellinen mikropalvelukäyttäytyminen. Tämän ajan jälkeen tehtävä yhdistetään automaattisesti masteriin (Git-mikropalvelu).

13. Onnistuneen yhdistämisen jälkeen pääsovellukseen tehtävän tilaksi vaihtuu Suljettu (Jira-mikropalvelu).

Kaavio ei väitä olevan täysin yksityiskohtainen (todellisuudessa vaiheita on vielä enemmän), mutta sen avulla voit arvioida integraatioastetta prosesseihin. Emme pidä tätä järjestelmää ihanteellisena ja parannamme automaattisen julkaisun ja käyttöönottotuen prosesseja.

Mitä seuraavaksi

Meillä on suuria suunnitelmia automaation kehittämiselle, esimerkiksi poistamalla manuaaliset toiminnot monoliittijulkaisujen aikana, parantamalla valvontaa automaattisen käyttöönoton aikana ja parantamalla vuorovaikutusta kehittäjien kanssa.

Mutta lopetetaan nyt tähän. Käsittelimme automaatiokatsauksessa monia aiheita pintapuolisesti, joihinkin ei puututtu ollenkaan, joten vastaamme mielellämme kysymyksiin. Odotamme ehdotuksia siitä, mitä kattaa yksityiskohtaisesti, kirjoita kommentteihin.

Lähde: will.com

Lisää kommentti