Fra skript til vår egen plattform: hvordan vi automatiserte utvikling hos CIAN

Fra skript til vår egen plattform: hvordan vi automatiserte utvikling hos CIAN

På RIT 2019 laget vår kollega Alexander Korotkov rapportere om automatisering av utvikling hos CIAN: for å forenkle liv og arbeid bruker vi vår egen Integro-plattform. Den sporer livssyklusen til oppgaver, avlaster utviklere for rutineoperasjoner og reduserer antallet feil i produksjonen betydelig. I dette innlegget vil vi utfylle Alexanders rapport og fortelle deg hvordan vi gikk fra enkle skript til å kombinere åpen kildekode-produkter gjennom vår egen plattform og hva vårt separate automatiseringsteam gjør.
 

Null nivå

"Det er ikke noe nullnivå, jeg vet ikke noe slikt"
Master Shifu fra filmen "Kung Fu Panda"

Automatisering hos CIAN begynte 14 år etter at selskapet ble grunnlagt. På den tiden var det 35 personer i utviklingsteamet. Vanskelig å tro, ikke sant? Selvfølgelig fantes automatisering i en eller annen form, men en egen retning for kontinuerlig integrasjon og kodelevering begynte å ta form i 2015. 

På den tiden hadde vi en enorm monolitt av Python, C# og PHP, distribuert på Linux/Windows-servere. For å distribuere dette monsteret hadde vi et sett med skript som vi kjørte manuelt. Det var også monteringen av monolitten, som førte til smerte og lidelse på grunn av konflikter ved sammenslåing av grener, korrigering av defekter og gjenoppbygging "med et annet sett med oppgaver i bygningen." En forenklet prosess så slik ut:

Fra skript til vår egen plattform: hvordan vi automatiserte utvikling hos CIAN

Vi var ikke fornøyd med dette, og vi ønsket å bygge en repeterbar, automatisert og håndterbar bygge- og distribusjonsprosess. Til dette trengte vi et CI/CD-system, og vi valgte mellom gratisversjonen av Teamcity og gratisversjonen av Jenkins, siden vi jobbet med dem og begge passet oss med tanke på settet med funksjoner. Vi valgte Teamcity som et nyere produkt. På det tidspunktet hadde vi ennå ikke brukt mikrotjenestearkitektur og forventet ikke et stort antall oppgaver og prosjekter.

Vi kommer til ideen om vårt eget system

Implementeringen av Teamcity fjernet bare en del av det manuelle arbeidet: det som gjenstår er opprettelsen av Pull-forespørsler, promotering av problemer etter status i Jira og valg av problemer for utgivelse. Teamcity-systemet kunne ikke lenger takle dette. Det var nødvendig å velge veien for videre automatisering. Vi vurderte alternativer for å jobbe med skript i Teamcity eller bytte til tredjeparts automasjonssystemer. Men til slutt bestemte vi oss for at vi trengte maksimal fleksibilitet, som bare vår egen løsning kan gi. Slik dukket den første versjonen av det interne automasjonssystemet kalt Integro ut.

Teamcity tar for seg automatisering på nivå med lansering av bygge- og distribusjonsprosesser, mens Integro fokuserte på automatisering av utviklingsprosesser på toppnivå. Det var nødvendig å kombinere arbeid med problemstillinger i Jira med behandling av tilhørende kildekode i Bitbucket. På dette stadiet begynte Integro å ha egne arbeidsflyter for å jobbe med oppgaver av ulike typer. 

På grunn av økningen i automatisering i forretningsprosesser har antall prosjekter og kjøringer i Teamcity økt. Så et nytt problem kom: én gratis Teamcity-forekomst var ikke nok (3 agenter og 100 prosjekter), vi la til en annen forekomst (3 flere agenter og 100 prosjekter), så en annen. Som et resultat endte vi opp med et system med flere klynger, som var vanskelig å administrere:

Fra skript til vår egen plattform: hvordan vi automatiserte utvikling hos CIAN

Da spørsmålet om en 4. instans dukket opp, innså vi at vi ikke kunne fortsette å leve slik, fordi de totale kostnadene ved å støtte 4 instanser ikke lenger var innenfor noen grenser. Spørsmålet dukket opp om å kjøpe betalt Teamcity eller velge gratis Jenkins. Vi gjorde beregninger på instanser og automatiseringsplaner og bestemte at vi skulle bo på Jenkins. Etter et par uker byttet vi til Jenkins og eliminerte noe av hodepinen forbundet med å opprettholde flere Teamcity-forekomster. Derfor kunne vi fokusere på å utvikle Integro og tilpasse Jenkins for oss selv.

Med veksten av grunnleggende automatisering (i form av automatisk opprettelse av Pull Requests, innsamling og publisering av kodedekning og andre kontroller), er det et sterkt ønske om å forlate manuelle utgivelser så mye som mulig og gi dette arbeidet til roboter. I tillegg begynte selskapet å gå over til mikrotjenester i selskapet, som krevde hyppige utgivelser, og separat fra hverandre. Dette er hvordan vi gradvis kom til automatiske utgivelser av mikrotjenestene våre (vi slipper for tiden monolitten manuelt på grunn av prosessens kompleksitet). Men, som det vanligvis skjer, oppsto en ny kompleksitet. 

Vi automatiserer testing

Fra skript til vår egen plattform: hvordan vi automatiserte utvikling hos CIAN

På grunn av automatisering av utgivelser har utviklingsprosessene akselerert, delvis på grunn av at noen teststadier hoppes over. Og dette førte til et midlertidig tap av kvalitet. Det høres trivielt ut, men sammen med akselerasjonen av utgivelser var det nødvendig å endre produktutviklingsmetodikken. Det var nødvendig å tenke på automatisering av testing, innføring av personlig ansvar (her snakker vi om å "godta ideen i hodet", ikke pengebøter) til utvikleren for den utgitte koden og feilene i den, samt beslutningen om å frigi/ikke frigi en oppgave gjennom automatisk distribusjon. 

Ved å eliminere kvalitetsproblemer kom vi til to viktige avgjørelser: vi begynte å utføre kanarietesting og introduserte automatisk overvåking av feilbakgrunnen med en automatisk respons på overskuddet. Den første løsningen gjorde det mulig å finne åpenbare feil før koden var fullstendig sluppet i produksjon, den andre reduserte responstiden på problemer i produksjonen. Feil skjer selvfølgelig, men vi bruker mesteparten av vår tid og krefter ikke på å rette dem, men på å minimere dem. 

Automatiseringsteam

Vi har for tiden en stab på 130 utviklere, og vi fortsetter vokse. Teamet for kontinuerlig integrasjon og kodelevering (heretter kalt Deploy and Integration eller DI-teamet) består av 7 personer og jobber i 2 retninger: utvikling av Integro automatiseringsplattform og DevOps. 

DevOps er ansvarlig for Dev/Beta-miljøet til CIAN-nettstedet, Integro-miljøet, hjelper utviklere med å løse problemer og utvikler nye tilnærminger til skaleringsmiljøer. Utviklingsretningen for Integro omhandler både selve Integro og relaterte tjenester, for eksempel plugins for Jenkins, Jira, Confluence, og utvikler også hjelpeverktøy og applikasjoner for utviklingsteam. 

DI-teamet samarbeider med plattformteamet, som utvikler arkitektur, biblioteker og utviklingstilnærminger internt. Samtidig kan enhver utvikler innen CIAN bidra til automatisering, for eksempel lage mikroautomatisering for å passe teamets behov eller dele en kul idé om hvordan man kan gjøre automatisering enda bedre.

Lagkake av automatisering hos CIAN

Fra skript til vår egen plattform: hvordan vi automatiserte utvikling hos CIAN

Alle systemer involvert i automatisering kan deles inn i flere lag:

  1. Eksterne systemer (Jira, Bitbucket, etc.). Utviklingsteam jobber med dem.
  2. Integro plattform. Oftest jobber ikke utviklere med det direkte, men det er det som holder all automatisering i gang.
  3. Leverings-, orkestrerings- og oppdagelsestjenester (for eksempel Jeknins, Consul, Nomad). Med deres hjelp distribuerer vi kode på servere og sikrer at tjenestene fungerer med hverandre.
  4. Fysisk lag (servere, OS, relatert programvare). Koden vår fungerer på dette nivået. Dette kan enten være en fysisk server eller en virtuell (LXC, KVM, Docker).

Med utgangspunkt i dette konseptet deler vi ansvarsområder innenfor DI-teamet. De to første nivåene er innenfor ansvarsområdet til Integro-utviklingsretningen, og de to siste nivåene er allerede innenfor ansvarsområdet til DevOps. Denne separasjonen lar oss fokusere på oppgaver og forstyrrer ikke samhandlingen, siden vi er nær hverandre og hele tiden utveksler kunnskap og erfaring.

Intakt

La oss fokusere på Integro og starte med teknologistabelen:

  • CentOS 7
  • Docker + Nomad + Consul + Vault
  • Java 11 (den gamle Integro-monolitten vil forbli på Java 8)
  • Spring Boot 2.X + Spring Cloud Config
  • PostgreSql 11
  • Kanin MQ 
  • Apache Ignite
  • Camunda (innebygd)
  • Grafana + Grafitt + Prometheus + Jaeger + ELK
  • Web UI: React (CSR) + MobX
  • SSO: Keycloak

Vi følger prinsippet om utvikling av mikrotjenester, selv om vi har arv i form av en monolitt av en tidlig versjon av Integro. Hver mikrotjeneste kjører i sin egen Docker-beholder, og tjenestene kommuniserer med hverandre via HTTP-forespørsler og RabbitMQ-meldinger. Mikrotjenester finner hverandre gjennom Consul og sender en forespørsel til den, og sender autorisasjon gjennom SSO (Keycloak, OAuth 2/OpenID Connect).

Fra skript til vår egen plattform: hvordan vi automatiserte utvikling hos CIAN

Som et virkelighetseksempel, vurder å samhandle med Jenkins, som består av følgende trinn:

  1. Arbeidsflytadministrasjonsmikrotjenesten (heretter referert til som Flow-mikrotjenesten) ønsker å kjøre en build i Jenkins. For å gjøre dette bruker han Consul for å finne IP:PORT for mikrotjenesten for integrasjon med Jenkins (heretter referert til som Jenkins mikrotjeneste) og sender en asynkron forespørsel til den om å starte byggingen i Jenkins.
  2. Etter å ha mottatt en forespørsel, genererer og svarer Jenkins-mikrotjenesten med en jobb-ID, som deretter kan brukes til å identifisere resultatet av arbeidet. Samtidig utløser den bygningen i Jenkins via et REST API-kall.
  3. Jenkins utfører byggingen og, etter fullføring, sender en webhook med utførelsesresultatene til Jenkins mikrotjeneste.
  4. Jenkins-mikrotjenesten, etter å ha mottatt webhook, genererer en melding om fullføring av forespørselsbehandling og legger ved utførelsesresultatene til den. Den genererte meldingen sendes til RabbitMQ-køen.
  5. Gjennom RabbitMQ når den publiserte meldingen Flow-mikrotjenesten, som lærer om resultatet av behandlingen av oppgaven ved å matche jobb-ID-en fra forespørselen og den mottatte meldingen.

Nå har vi rundt 30 mikrotjenester, som kan deles inn i flere grupper:

  1. Konfigurasjonsstyring.
  2. Informasjon og interaksjon med brukere (budbringere, post).
  3. Jobber med kildekode.
  4. Integrasjon med distribusjonsverktøy (jenkins, nomad, konsul, etc.).
  5. Overvåking (utgivelser, feil osv.).
  6. Webverktøy (UI for administrasjon av testmiljøer, innsamling av statistikk, etc.).
  7. Integrasjon med oppgavesporere og lignende systemer.
  8. Arbeidsflytstyring for ulike oppgaver.

Arbeidsflytoppgaver

Integro automatiserer aktiviteter relatert til oppgavens livssyklus. Forenklet sett vil livssyklusen til en oppgave forstås som arbeidsflyten til en oppgave i Jira. Våre utviklingsprosesser har flere arbeidsflytvariasjoner avhengig av prosjekt, type oppgave og alternativer valgt i en bestemt oppgave. 

La oss se på arbeidsflyten vi bruker oftest:

Fra skript til vår egen plattform: hvordan vi automatiserte utvikling hos CIAN

I diagrammet indikerer giret at overgang kalles automatisk av Integro, mens menneskefiguren indikerer at overgang kalles manuelt av en person. La oss se på flere veier som en oppgave kan ta i denne arbeidsflyten.

Fullstendig manuell testing på DEV+BETA uten kanarietester (vanligvis er det slik vi slipper en monolitt):

Fra skript til vår egen plattform: hvordan vi automatiserte utvikling hos CIAN

Det kan være andre overgangskombinasjoner. Noen ganger kan banen som et problem vil ta, velges gjennom alternativer i Jira.

Oppgavebevegelse

La oss se på hovedtrinnene som utføres når en oppgave beveger seg gjennom arbeidsflyten "DEV Testing + Canary Tests":

1. Utvikleren eller PM oppretter oppgaven.

2. Utbygger tar oppgaven på jobb. Etter ferdigstillelse bytter den til IN REVIEW-status.

3. Jira sender en Webhook til Jira mikrotjeneste (ansvarlig for integrasjon med Jira).

4. Jira-mikrotjenesten sender en forespørsel til Flow-tjenesten (ansvarlig for interne arbeidsflyter der arbeid utføres) om å starte arbeidsflyten.

5. Inne i Flow-tjenesten:

  • Anmeldere blir tildelt oppgaven (Users microservice som vet alt om brukere + Jira microservice).
  • Gjennom Source-mikrotjenesten (den kjenner til repositories og grener, men fungerer ikke med selve koden), søkes det etter repositories som inneholder en gren av problemet vårt (for å forenkle søket, sammenfaller navnet på grenen med problemet nummer i Jira). Oftest har en oppgave bare én gren i ett depot; dette forenkler administrasjonen av distribusjonskøen og reduserer tilkoblingen mellom depotene.
  • For hver funnet gren utføres følgende handlingssekvens:

    i) Oppdatering av mastergrenen (Git microservice for arbeid med kode).
    ii) Grenen er blokkert fra endringer av utvikleren (Bitbucket microservice).
    iii) En Pull-forespørsel opprettes for denne grenen (Bitbucket microservice).
    iv) En melding om en ny Pull-forespørsel sendes til utviklerchatter (Varsle mikrotjeneste for arbeid med varsler).
    v) Bygge-, test- og distribusjonsoppgaver startes på DEV (Jenkins microservice for arbeid med Jenkins).
    vi) Hvis alle tidligere trinn er fullført, legger Integro sin godkjenning i Pull Request (Bitbucket microservice).

  • Integro venter på Godkjenning i Pull-forespørsel fra utpekte anmeldere.
  • Så snart alle nødvendige godkjenninger er mottatt (inkludert automatiserte tester har bestått positivt), overfører Integro oppgaven til Test on Dev (Jira microservice) status.

6. Testere tester oppgaven. Hvis det ikke er noen problemer, overføres oppgaven til statusen Klar for bygg.

7. Integro "ser" at oppgaven er klar for utgivelse og starter distribusjonen i kanarimodus (Jenkins microservice). Beredskap for løslatelse bestemmes av et sett med regler. For eksempel er oppgaven i den nødvendige statusen, det er ingen låser på andre oppgaver, det er for øyeblikket ingen aktive opplastinger av denne mikrotjenesten, etc.

8. Oppgaven overføres til Canary-status (Jira microservice).

9. Jenkins starter en distribusjonsoppgave gjennom Nomad i kanarimodus (vanligvis 1-3 forekomster) og varsler utgivelsesovervåkingstjenesten (DeployWatch microservice) om utrullingen.

10. Mikrotjenesten DeployWatch samler inn feilbakgrunnen og reagerer på den om nødvendig. Hvis feilbakgrunnen overskrides (bakgrunnsnormen beregnes automatisk), blir utviklere varslet via Notify-mikrotjenesten. Hvis utvikleren etter 5 minutter ikke har svart (klikket Tilbake eller Stay), starter en automatisk tilbakerulling av kanariforekomstene. Hvis bakgrunnen ikke overskrides, må utvikleren manuelt starte oppgavedistribusjonen til produksjon (ved å klikke på en knapp i brukergrensesnittet). Hvis utvikleren innen 60 minutter ikke har lansert distribusjonen til produksjon, vil kanariforekomstene også bli rullet tilbake av sikkerhetsgrunner.

11. Etter lansering av distribusjonen til produksjon:

  • Oppgaven overføres til produksjonsstatus (Jira microservice).
  • Jenkins-mikrotjenesten starter distribusjonsprosessen og varsler DeployWatch-mikrotjenesten om distribusjonen.
  • DeployWatch-mikrotjenesten sjekker at alle beholdere på produksjon er oppdatert (det var tilfeller hvor ikke alle ble oppdatert).
  • Gjennom Notify-mikrotjenesten sendes et varsel om resultatene av distribusjonen til produksjon.

12. Utviklere vil ha 30 minutter på seg til å begynne å rulle tilbake en oppgave fra produksjonen hvis feil mikrotjenesteoppførsel oppdages. Etter denne tiden vil oppgaven automatisk bli slått sammen til master (Git microservice).

13. Etter en vellykket sammenslåing til master vil oppgavestatusen endres til Lukket (Jira microservice).

Diagrammet later ikke til å være fullstendig detaljert (i virkeligheten er det enda flere trinn), men det lar deg vurdere graden av integrering i prosesser. Vi anser ikke denne ordningen som ideell og forbedrer prosessene for automatisk utgivelse og distribusjonsstøtte.

Hva er neste

Vi har store planer for utvikling av automatisering, for eksempel eliminering av manuelle operasjoner under monolittutgivelser, forbedring av overvåking under automatisk distribusjon og forbedret samhandling med utviklere.

Men la oss stoppe her for nå. Vi dekket mange emner i automatiseringsgjennomgangen overfladisk, noen ble ikke berørt i det hele tatt, så vi svarer gjerne på spørsmål. Vi venter på forslag til hva vi skal dekke i detalj, skriv i kommentarfeltet.

Kilde: www.habr.com

Legg til en kommentar