Fra scripts til vores egen platform: hvordan vi automatiserede udvikling hos CIAN

Fra scripts til vores egen platform: hvordan vi automatiserede udvikling hos CIAN

Ved RIT 2019 lavede vores kollega Alexander Korotkov rapport om automatisering af udvikling hos CIAN: For at forenkle liv og arbejde bruger vi vores egen Integro-platform. Det sporer opgavers livscyklus, aflaster udviklere for rutineoperationer og reducerer antallet af fejl i produktionen markant. I dette indlæg vil vi supplere Alexanders rapport og fortælle dig, hvordan vi gik fra simple scripts til at kombinere open source-produkter gennem vores egen platform, og hvad vores separate automatiseringsteam gør.
 

Nul niveau

"Der er ikke sådan noget som et nulniveau, sådan noget ved jeg ikke"
Master Shifu fra filmen "Kung Fu Panda"

Automatisering hos CIAN begyndte 14 år efter, at virksomheden blev grundlagt. På det tidspunkt havde udviklingsteamet 35 personer. Svært at tro, ikke? Selvfølgelig eksisterede automatisering i en eller anden form, men en separat retning for kontinuerlig integration og kodelevering begyndte at tage form i 2015. 

På det tidspunkt havde vi en enorm monolit af Python, C# og PHP, installeret på Linux/Windows-servere. For at implementere dette monster havde vi et sæt scripts, som vi kørte manuelt. Der var også samlingen af ​​monolitten, som medførte smerte og lidelse på grund af konflikter ved sammenlægning af grene, korrigering af defekter og genopbygning "med et andet sæt opgaver i bygningen." En forenklet proces så således ud:

Fra scripts til vores egen platform: hvordan vi automatiserede udvikling hos CIAN

Vi var ikke tilfredse med dette, og vi ønskede at bygge en gentagelig, automatiseret og håndterbar bygge- og implementeringsproces. Til dette havde vi brug for et CI/CD-system, og vi valgte mellem den gratis version af Teamcity og den gratis version af Jenkins, da vi arbejdede med dem og begge passede til os i forhold til sættet af funktioner. Vi valgte Teamcity som et nyere produkt. På det tidspunkt havde vi endnu ikke brugt mikroservicearkitektur og forventede ikke et stort antal opgaver og projekter.

Vi kommer til ideen om vores eget system

Implementeringen af ​​Teamcity fjernede kun en del af det manuelle arbejde: Hvad der er tilbage er oprettelsen af ​​Pull Requests, promovering af problemer efter status i Jira og udvælgelse af problemer til udgivelse. Teamcity-systemet kunne ikke længere klare dette. Det var nødvendigt at vælge vejen til yderligere automatisering. Vi overvejede muligheder for at arbejde med scripts i Teamcity eller skifte til tredjeparts automationssystemer. Men til sidst besluttede vi, at vi havde brug for maksimal fleksibilitet, som kun vores egen løsning kan give. Sådan fremstod den første version af det interne automatiseringssystem kaldet Integro.

Teamcity beskæftiger sig med automatisering på niveau med lancering af bygge- og implementeringsprocesserne, mens Integro fokuserede på automatisering på topniveau af udviklingsprocesser. Det var nødvendigt at kombinere arbejde med problemstillinger i Jira med behandling af tilhørende kildekode i Bitbucket. På dette tidspunkt begyndte Integro at have sine egne arbejdsgange til at arbejde med opgaver af forskellige typer. 

På grund af stigningen i automatisering i forretningsprocesser er antallet af projekter og kørsler i Teamcity steget. Så et nyt problem kom: én gratis Teamcity-instans var ikke nok (3 agenter og 100 projekter), vi tilføjede en anden instans (3 flere agenter og 100 projekter), så en anden. Som et resultat endte vi med et system med flere klynger, som var svært at administrere:

Fra scripts til vores egen platform: hvordan vi automatiserede udvikling hos CIAN

Da spørgsmålet om en 4. instans opstod, indså vi, at vi ikke kunne fortsætte med at leve sådan her, fordi de samlede omkostninger ved at støtte 4 instanser ikke længere var inden for nogen grænser. Spørgsmålet opstod om at købe betalt Teamcity eller at vælge gratis Jenkins. Vi lavede beregninger på instanser og automatiseringsplaner og besluttede, at vi ville bo på Jenkins. Efter et par uger skiftede vi til Jenkins og eliminerede noget af hovedpinen forbundet med at vedligeholde flere Teamcity-forekomster. Derfor kunne vi fokusere på at udvikle Integro og tilpasse Jenkins til os selv.

Med væksten af ​​grundlæggende automatisering (i form af automatisk oprettelse af Pull Requests, indsamling og offentliggørelse af kodedækning og andre kontroller), er der et stærkt ønske om at opgive manuelle udgivelser så meget som muligt og give dette arbejde til robotter. Derudover begyndte virksomheden at gå over til mikrotjenester inden for virksomheden, hvilket krævede hyppige udgivelser og adskilt fra hinanden. Sådan kom vi gradvist til automatiske udgivelser af vores mikrotjenester (vi udgiver i øjeblikket monolitten manuelt på grund af processens kompleksitet). Men som det plejer at ske, opstod der en ny kompleksitet. 

Vi automatiserer test

Fra scripts til vores egen platform: hvordan vi automatiserede udvikling hos CIAN

På grund af automatiseringen af ​​udgivelser er udviklingsprocesser accelereret, delvist på grund af springet af nogle teststadier. Og det førte til et midlertidigt kvalitetstab. Det lyder trivielt, men sammen med accelerationen af ​​udgivelser var det nødvendigt at ændre produktudviklingsmetoden. Det var nødvendigt at tænke på automatisering af test, indføring af personligt ansvar (her taler vi om "at acceptere ideen i hovedet", ikke pengebøder) af udvikleren for den frigivne kode og fejl i den, samt beslutningen om at frigive/ikke frigive en opgave gennem automatisk implementering. 

Ved at eliminere kvalitetsproblemer kom vi til to vigtige beslutninger: vi begyndte at udføre kanarie-test og indførte automatisk overvågning af fejlbaggrunden med en automatisk reaktion på dens overskud. Den første løsning gjorde det muligt at finde åbenlyse fejl, før koden var helt frigivet i produktionen, den anden reducerede responstiden på problemer i produktionen. Der sker selvfølgelig fejl, men vi bruger det meste af vores tid og kræfter ikke på at rette dem, men på at minimere dem. 

Automatiseringsteam

Vi har i øjeblikket en stab på 130 udviklere, og vi fortsætter at vokse. Teamet for kontinuerlig integration og kodelevering (herefter benævnt Deploy and Integration eller DI-teamet) består af 7 personer og arbejder i 2 retninger: udvikling af Integro automationsplatformen og DevOps. 

DevOps er ansvarlig for Dev/Beta-miljøet på CIAN-stedet, Integro-miljøet, hjælper udviklere med at løse problemer og udvikler nye tilgange til skalering af miljøer. Integro-udviklingsretningen omhandler både Integro selv og relaterede tjenester, for eksempel plugins til Jenkins, Jira, Confluence, og udvikler også hjælpeværktøjer og applikationer til udviklingsteams. 

DI-teamet arbejder sammen med Platform-teamet, som internt udvikler arkitektur, biblioteker og udviklingstilgange. Samtidig kan enhver udvikler inden for CIAN bidrage til automatisering, for eksempel lave mikroautomatisering, så den passer til teamets behov eller dele en fed idé om, hvordan man gør automatisering endnu bedre.

Lagkage af automatisering hos CIAN

Fra scripts til vores egen platform: hvordan vi automatiserede udvikling hos CIAN

Alle systemer involveret i automatisering kan opdeles i flere lag:

  1. Eksterne systemer (Jira, Bitbucket osv.). Udviklingsteams arbejder med dem.
  2. Integro platform. Oftest arbejder udviklere ikke direkte med det, men det er det, der holder al automatisering kørende.
  3. Leverings-, orkestrerings- og opdagelsestjenester (for eksempel Jeknins, Consul, Nomad). Med deres hjælp implementerer vi kode på servere og sikrer, at tjenester arbejder med hinanden.
  4. Fysisk lag (servere, OS, relateret software). Vores kode fungerer på dette niveau. Dette kan enten være en fysisk server eller en virtuel server (LXC, KVM, Docker).

Ud fra dette koncept opdeler vi ansvarsområder inden for DI-teamet. De første to niveauer er inden for ansvarsområdet for Integro-udviklingsretningen, og de sidste to niveauer er allerede inden for ansvarsområdet for DevOps. Denne adskillelse giver os mulighed for at fokusere på opgaverne og forstyrrer ikke interaktionen, da vi er tæt på hinanden og konstant udveksler viden og erfaringer.

Intakt

Lad os fokusere på Integro og starte med teknologistakken:

  • CentOS 7
  • Docker + Nomad + Consul + Vault
  • Java 11 (den gamle Integro-monolit forbliver på Java 8)
  • Spring Boot 2.X + Spring Cloud Config
  • PostgreSql 11
  • RabbitMQ 
  • Apache Ignite
  • Camunda (indlejret)
  • Grafana + Grafit + Prometheus + Jaeger + ELK
  • Web UI: React (CSR) + MobX
  • SSO: Keycloak

Vi overholder princippet om udvikling af mikrotjenester, selvom vi har arv i form af en monolit af en tidlig version af Integro. Hver mikroservice kører i sin egen Docker-container, og tjenesterne kommunikerer med hinanden via HTTP-anmodninger og RabbitMQ-meddelelser. Mikrotjenester finder hinanden gennem Consul og fremsender en anmodning til den og sender autorisation gennem SSO (Keycloak, OAuth 2/OpenID Connect).

Fra scripts til vores egen platform: hvordan vi automatiserede udvikling hos CIAN

Som et eksempel fra det virkelige liv kan du overveje at interagere med Jenkins, som består af følgende trin:

  1. Workflow-styringsmikrotjenesten (herefter benævnt Flow-mikrotjenesten) ønsker at køre en build i Jenkins. For at gøre dette bruger han Consul til at finde IP:PORT for mikrotjenesten til integration med Jenkins (herefter benævnt Jenkins mikrotjeneste) og sender en asynkron anmodning til den om at starte opbygningen i Jenkins.
  2. Efter at have modtaget en anmodning, genererer og svarer Jenkins mikroservice med et job-id, som derefter kan bruges til at identificere resultatet af arbejdet. Samtidig udløser det build i Jenkins via et REST API-kald.
  3. Jenkins udfører opbygningen og sender efter færdiggørelse en webhook med udførelsesresultaterne til Jenkins mikroservice.
  4. Efter at have modtaget webhook'en genererer Jenkins-mikrotjenesten en besked om færdiggørelsen af ​​anmodningsbehandlingen og vedhæfter udførelsesresultaterne til den. Den genererede besked sendes til RabbitMQ-køen.
  5. Gennem RabbitMQ når den offentliggjorte besked Flow-mikrotjenesten, som lærer om resultatet af behandlingen af ​​sin opgave ved at matche job-id'et fra anmodningen og den modtagne besked.

Nu har vi omkring 30 mikrotjenester, som kan opdeles i flere grupper:

  1. Konfigurationsstyring.
  2. Information og interaktion med brugere (budbringere, mail).
  3. Arbejder med kildekode.
  4. Integration med implementeringsværktøjer (jenkins, nomad, konsul osv.).
  5. Overvågning (udgivelser, fejl osv.).
  6. Webværktøjer (UI til styring af testmiljøer, indsamling af statistik osv.).
  7. Integration med task trackers og lignende systemer.
  8. Workflow management til forskellige opgaver.

Workflow opgaver

Integro automatiserer aktiviteter relateret til opgavens livscyklus. Forenklet set vil en opgaves livscyklus blive forstået som arbejdsgangen for en opgave i Jira. Vores udviklingsprocesser har flere workflow-variationer afhængigt af projektet, opgavetypen og de valgmuligheder, der er valgt i en bestemt opgave. 

Lad os se på den arbejdsgang, vi oftest bruger:

Fra scripts til vores egen platform: hvordan vi automatiserede udvikling hos CIAN

I diagrammet angiver gearet, at overgangen kaldes automatisk af Integro, mens den menneskelige figur angiver, at overgangen kaldes manuelt af en person. Lad os se på flere veje, som en opgave kan tage i denne arbejdsgang.

Fuldstændig manuel test på DEV+BETA uden kanarietest (normalt er det sådan, vi frigiver en monolit):

Fra scripts til vores egen platform: hvordan vi automatiserede udvikling hos CIAN

Der kan være andre overgangskombinationer. Nogle gange kan den vej, et problem vil tage, vælges gennem muligheder i Jira.

Opgavebevægelse

Lad os se på de vigtigste trin, der udføres, når en opgave bevæger sig gennem arbejdsgangen "DEV Testing + Canary Tests":

1. Udvikleren eller PM opretter opgaven.

2. Udvikleren tager opgaven på arbejde. Efter færdiggørelsen skifter den til IN REVIEW-status.

3. Jira sender en Webhook til Jira mikroservice (ansvarlig for integration med Jira).

4. Jira-mikrotjenesten sender en anmodning til Flow-tjenesten (ansvarlig for interne arbejdsgange, hvori arbejdet udføres) om at starte arbejdsgangen.

5. Inde i Flow-tjenesten:

  • Anmeldere tildeles opgaven (Users microservice, der ved alt om brugere + Jira microservice).
  • Gennem Source-mikrotjenesten (den kender til repositories og filialer, men fungerer ikke med selve koden), søges der efter repositories, der indeholder en gren af ​​vores problem (for at forenkle søgningen falder filialens navn sammen med problemet nummer i Jira). Oftest har en opgave kun én gren i ét lager; dette forenkler administrationen af ​​implementeringskøen og reducerer forbindelsen mellem lagre.
  • For hver fundet gren udføres følgende sekvens af handlinger:

    i) Opdatering af mastergrenen (Git microservice til arbejde med kode).
    ii) Filialen er blokeret fra ændringer af udvikleren (Bitbucket microservice).
    iii) Der oprettes en Pull Request for denne gren (Bitbucket microservice).
    iv) En besked om en ny Pull-anmodning sendes til udviklerchats (Giv besked til mikroservice for at arbejde med notifikationer).
    v) Opbygning, test og implementering af opgaver startes på DEV (Jenkins mikroservice til at arbejde med Jenkins).
    vi) Hvis alle tidligere trin er gennemført med succes, sætter Integro sin godkendelse i Pull Request (Bitbucket microservice).

  • Integro afventer Godkendelse i Pull-anmodning fra udpegede anmeldere.
  • Så snart alle nødvendige godkendelser er modtaget (inklusive automatiserede tests er bestået positivt), overfører Integro opgaven til Test on Dev (Jira microservice) status.

6. Testere tester opgaven. Hvis der ikke er nogen problemer, så overføres opgaven til Klar til byggestatus.

7. Integro "ser", at opgaven er klar til frigivelse og starter dens udrulning i canary mode (Jenkins microservice). Beredskab til frigivelse er bestemt af et sæt regler. For eksempel er opgaven i den påkrævede status, der er ingen låse på andre opgaver, der er i øjeblikket ingen aktive uploads af denne mikrotjeneste osv.

8. Opgaven overføres til kanarisk status (Jira microservice).

9. Jenkins starter en implementeringsopgave gennem Nomad i kanarietilstand (normalt 1-3 forekomster) og underretter udgivelsesovervågningstjenesten (DeployWatch microservice) om implementeringen.

10. DeployWatch-mikrotjenesten indsamler fejlbaggrunden og reagerer på den, hvis det er nødvendigt. Hvis fejlbaggrunden overskrides (baggrundsnormen beregnes automatisk), får udviklere besked via Notify-mikrotjenesten. Hvis udvikleren efter 5 minutter ikke har svaret (klikket på Tilbagevend eller Bliv), så startes en automatisk tilbagerulning af de kanariske forekomster. Hvis baggrunden ikke overskrides, skal udvikleren manuelt starte opgaveimplementeringen til produktion (ved at klikke på en knap i brugergrænsefladen). Hvis udvikleren inden for 60 minutter ikke har lanceret udrulningen til produktion, vil de kanariske forekomster også blive rullet tilbage af sikkerhedsmæssige årsager.

11. Efter lancering af implementeringen til produktion:

  • Opgaven overføres til produktionsstatus (Jira microservice).
  • Jenkins-mikrotjenesten starter implementeringsprocessen og giver DeployWatch-mikrotjenesten besked om implementeringen.
  • DeployWatch-mikrotjenesten kontrollerer, at alle containere på produktion er blevet opdateret (der var tilfælde, hvor ikke alle blev opdateret).
  • Via Notify-mikrotjenesten sendes en notifikation om resultaterne af implementeringen til Produktion.

12. Udviklere har 30 minutter til at begynde at rulle en opgave tilbage fra produktion, hvis der opdages forkert mikroserviceadfærd. Efter dette tidspunkt vil opgaven automatisk blive flettet ind i master (Git microservice).

13. Efter en vellykket fletning til master vil opgavestatus blive ændret til Lukket (Jira microservice).

Diagrammet foregiver ikke at være helt detaljeret (i virkeligheden er der endnu flere trin), men det giver dig mulighed for at vurdere graden af ​​integration i processer. Vi anser ikke denne ordning for ideel og forbedrer processerne for automatisk frigivelse og implementeringssupport.

Hvad er næste

Vi har store planer for udvikling af automatisering, for eksempel eliminering af manuelle operationer under monolitudgivelser, forbedring af overvågning under automatisk implementering og forbedring af interaktion med udviklere.

Men lad os stoppe her for nu. Vi dækkede mange emner i automatiseringsgennemgangen overfladisk, nogle blev slet ikke berørt, så vi svarer gerne på spørgsmål. Vi venter på forslag til, hvad der skal dækkes i detaljer, skriv i kommentarerne.

Kilde: www.habr.com

Tilføj en kommentar