Van scripts tot ons eigen platform: hoe we de ontwikkeling bij CIAN hebben geautomatiseerd

Van scripts tot ons eigen platform: hoe we de ontwikkeling bij CIAN hebben geautomatiseerd

Op RIT 2019 maakte onze collega Alexander Korotkov verslag over automatisering van ontwikkeling bij CIAN: om leven en werk te vereenvoudigen gebruiken we ons eigen Integro-platform. Het volgt de levenscyclus van taken, ontlast ontwikkelaars van routinematige handelingen en vermindert het aantal bugs in de productie aanzienlijk. In dit bericht zullen we het rapport van Alexander aanvullen en vertellen hoe we van eenvoudige scripts zijn overgegaan naar het combineren van open source-producten via ons eigen platform en wat ons afzonderlijke automatiseringsteam doet.
 

Nul niveau

β€œEr bestaat niet zoiets als een nulniveau, ik ken zoiets niet”
Meester Shifu uit de film "Kung Fu Panda"

De automatisering bij CIAN begon 14 jaar na de oprichting van het bedrijf. Op dat moment waren er 35 mensen in het ontwikkelteam. Moeilijk te geloven, toch? Natuurlijk bestond automatisering in een of andere vorm, maar in 2015 begon een aparte richting voor continue integratie en codelevering vorm te krijgen. 

Destijds hadden we een enorme monoliet van Python, C# en PHP, geΓ―mplementeerd op Linux/Windows-servers. Om dit monster in te zetten, hadden we een set scripts die we handmatig uitvoerden. Er was ook de montage van de monoliet, die pijn en lijden met zich meebracht als gevolg van conflicten bij het samenvoegen van takken, het corrigeren van defecten en het opnieuw opbouwen β€˜met een andere reeks taken tijdens de bouw’. Een vereenvoudigd proces zag er als volgt uit:

Van scripts tot ons eigen platform: hoe we de ontwikkeling bij CIAN hebben geautomatiseerd

We waren hier niet blij mee en we wilden een herhaalbaar, geautomatiseerd en beheersbaar bouw- en implementatieproces bouwen. Hiervoor hadden we een CI/CD-systeem nodig en we kozen tussen de gratis versie van Teamcity en de gratis versie van Jenkins, omdat we ermee werkten en beide bij ons pasten qua functionaliteit. Wij kozen voor Teamcity als recenter product. Destijds hadden we nog geen microservice-architectuur gebruikt en hadden we geen groot aantal taken en projecten verwacht.

We komen op het idee van ons eigen systeem

De implementatie van Teamcity heeft slechts een deel van het handmatige werk weggenomen: wat overblijft is het aanmaken van Pull Requests, het promoten van issues op status in Jira en het selecteren van issues voor release. Het Teamcity-systeem kon dit niet meer aan. Het was noodzakelijk om het pad van verdere automatisering te kiezen. We hebben gekeken naar mogelijkheden om met scripts in Teamcity te werken of over te stappen naar automatiseringssystemen van derden. Maar uiteindelijk besloten we dat we maximale flexibiliteit nodig hadden, die alleen onze eigen oplossing kan bieden. Zo verscheen de eerste versie van het interne automatiseringssysteem genaamd Integro.

Teamcity houdt zich bezig met automatisering op het niveau van het lanceren van de bouw- en implementatieprocessen, terwijl Integro zich richtte op de automatisering van ontwikkelingsprocessen op het hoogste niveau. Het was noodzakelijk om het werken met issues in Jira te combineren met het verwerken van bijbehorende broncode in Bitbucket. In dit stadium begon Integro zijn eigen workflows te hebben voor het werken met verschillende soorten taken. 

Door de toenemende automatisering van bedrijfsprocessen is het aantal projecten en runs in Teamcity toegenomen. Er kwam dus een nieuw probleem: één gratis Teamcity-instantie was niet genoeg (3 agenten en 100 projecten), we voegden nog een instantie toe (nog 3 agenten en 100 projecten), en nog een. Hierdoor kwamen we terecht bij een systeem van meerdere clusters, dat lastig te beheren was:

Van scripts tot ons eigen platform: hoe we de ontwikkeling bij CIAN hebben geautomatiseerd

Toen de vraag van een 4e instantie opkwam, realiseerden we ons dat we zo niet konden blijven leven, omdat de totale kosten voor het ondersteunen van 4 instanties niet langer binnen de grenzen lagen. De vraag rees over het kopen van betaalde Teamcity of het kiezen van gratis Jenkins. We maakten berekeningen op instances en automatiseringsplannen en besloten dat we op Jenkins zouden gaan wonen. Na een paar weken zijn we overgestapt op Jenkins en hebben we een deel van de hoofdpijn weggenomen die gepaard ging met het onderhouden van meerdere Teamcity-instanties. Daarom konden we ons concentreren op de ontwikkeling van Integro en het aanpassen van Jenkins voor onszelf.

Met de groei van de basisautomatisering (in de vorm van het automatisch aanmaken van Pull Requests, het verzamelen en publiceren van Codedekking en andere controles) is er een sterke wens om handmatige releases zoveel mogelijk achterwege te laten en dit werk aan robots te geven. Bovendien begon het bedrijf over te stappen op microservices binnen het bedrijf, waarvoor frequente releases nodig waren, en afzonderlijk van elkaar. Zo kwamen we geleidelijk aan tot automatische releases van onze microservices (momenteel geven we de monoliet handmatig vrij vanwege de complexiteit van het proces). Maar zoals meestal gebeurt, ontstond er een nieuwe complexiteit. 

Wij automatiseren het testen

Van scripts tot ons eigen platform: hoe we de ontwikkeling bij CIAN hebben geautomatiseerd

Door de automatisering van releases zijn de ontwikkelingsprocessen versneld, deels doordat bepaalde testfasen zijn overgeslagen. En dit leidde tot een tijdelijk kwaliteitsverlies. Het klinkt triviaal, maar samen met de versnelling van de releases was het noodzakelijk om de productontwikkelingsmethodologie te veranderen. Het was noodzakelijk om na te denken over de automatisering van het testen, het bijbrengen van persoonlijke verantwoordelijkheid (hier hebben we het over "het accepteren van het idee in het hoofd", niet over geldboetes) van de ontwikkelaar voor de vrijgegeven code en bugs erin, evenals de beslissing om een taak vrijgeven/niet vrijgeven via automatische implementatie. 

Door kwaliteitsproblemen te elimineren, kwamen we tot twee belangrijke beslissingen: we begonnen kanarietests uit te voeren en introduceerden automatische monitoring van de foutachtergrond met een automatische reactie op het overschot ervan. De eerste oplossing maakte het mogelijk om duidelijke fouten te vinden voordat de code volledig in productie werd genomen, de tweede verkortte de responstijd op problemen in de productie. Natuurlijk gebeuren er fouten, maar we besteden het grootste deel van onze tijd en moeite niet aan het corrigeren ervan, maar aan het minimaliseren ervan. 

Automatiseringsteam

Momenteel hebben we een personeelsbestand van 130 ontwikkelaars, en dat gaan we door opgroeien. Het team voor continue integratie en code delivery (hierna het Deploy and Integration of DI-team) bestaat uit 7 personen en werkt in 2 richtingen: ontwikkeling van het Integro automatiseringsplatform en DevOps. 

DevOps is verantwoordelijk voor de Dev/Beta-omgeving van de CIAN-site, de Integro-omgeving, helpt ontwikkelaars problemen op te lossen en ontwikkelt nieuwe benaderingen voor het schalen van omgevingen. De ontwikkelingsrichting van Integro houdt zich bezig met zowel Integro zelf als aanverwante diensten, bijvoorbeeld plug-ins voor Jenkins, Jira, Confluence, en ontwikkelt ook hulpprogramma's en applicaties voor ontwikkelingsteams. 

Het DI-team werkt samen met het Platform-team, dat de architectuur, bibliotheken en ontwikkelingsbenaderingen intern ontwikkelt. Tegelijkertijd kan elke ontwikkelaar binnen CIAN een bijdrage leveren aan de automatisering, bijvoorbeeld door micro-automatisering te maken die past bij de behoeften van het team of een cool idee delen over hoe de automatisering nog beter kan worden gemaakt.

Laagjestaart van automatisering bij CIAN

Van scripts tot ons eigen platform: hoe we de ontwikkeling bij CIAN hebben geautomatiseerd

Alle systemen die betrokken zijn bij automatisering kunnen in verschillende lagen worden verdeeld:

  1. Externe systemen (Jira, Bitbucket, etc.). Ontwikkelteams werken met hen samen.
  2. Integro-platform. Meestal werken ontwikkelaars er niet rechtstreeks mee, maar het is wel wat alle automatisering draaiende houdt.
  3. Leverings-, orkestratie- en ontdekkingsdiensten (bijvoorbeeld Jeknins, Consul, Nomad). Met hun hulp implementeren we code op servers en zorgen we ervoor dat services met elkaar samenwerken.
  4. Fysieke laag (servers, besturingssysteem, gerelateerde software). Onze code werkt op dit niveau. Dit kan een fysieke server zijn of een virtuele server (LXC, KVM, Docker).

Op basis van dit concept verdelen we de verantwoordelijkheidsgebieden binnen het DI-team. De eerste twee niveaus liggen op het gebied van de verantwoordelijkheid van de Integro-ontwikkelingsrichting, en de laatste twee niveaus liggen al op het gebied van de verantwoordelijkheid van DevOps. Door deze scheiding kunnen we ons concentreren op taken en wordt de interactie niet verstoord, omdat we dicht bij elkaar staan ​​en voortdurend kennis en ervaring uitwisselen.

Intact

Laten we ons concentreren op Integro en beginnen met de technologiestapel:

  • CentOS 7
  • Docker + Nomade + Consul + Kluis
  • Java 11 (de oude Integro-monoliet blijft op Java 8)
  • Spring Boot 2.X + Spring Cloud-configuratie
  • PostgreSql 11
  • RabbitMQ 
  • Apache Ontbranden
  • Camunda (ingebed)
  • Grafana + Grafiet + Prometheus + Jaeger + ELK
  • Webgebruikersinterface: React (CSR) + MobX
  • SSO: Sleutelmantel

We houden ons aan het principe van de ontwikkeling van microservices, hoewel we een erfenis hebben in de vorm van een monoliet van een vroege versie van Integro. Elke microservice draait in zijn eigen Docker-container en de services communiceren met elkaar via HTTP-verzoeken en RabbitMQ-berichten. Microservices vinden elkaar via Consul en doen daar een verzoek aan, waarbij autorisatie wordt doorgegeven via SSO (Keycloak, OAuth 2/OpenID Connect).

Van scripts tot ons eigen platform: hoe we de ontwikkeling bij CIAN hebben geautomatiseerd

Als voorbeeld uit de praktijk kunt u de interactie met Jenkins overwegen, die uit de volgende stappen bestaat:

  1. De microservice voor workflowbeheer (hierna de Flow-microservice genoemd) wil een build in Jenkins uitvoeren. Om dit te doen, gebruikt hij Consul om het IP:POORT van de microservice te vinden voor integratie met Jenkins (hierna Jenkins-microservice genoemd) en stuurt daar een asynchrone aanvraag naartoe om de build in Jenkins te starten.
  2. Na ontvangst van een verzoek genereert en reageert de Jenkins-microservice met een taak-ID, die vervolgens kan worden gebruikt om het resultaat van het werk te identificeren. Tegelijkertijd activeert het de ingebouwde Jenkins via een REST API-aanroep.
  3. Jenkins voert de build uit en stuurt na voltooiing een webhook met de uitvoeringsresultaten naar de Jenkins-microservice.
  4. De Jenkins-microservice genereert, nadat hij de webhook heeft ontvangen, een bericht over de voltooiing van de aanvraagverwerking en voegt daaraan de uitvoeringsresultaten toe. Het gegenereerde bericht wordt naar de RabbitMQ-wachtrij verzonden.
  5. Via RabbitMQ bereikt het gepubliceerde bericht de Flow-microservice, die leert over het resultaat van het verwerken van zijn taak door de taak-ID uit het verzoek en het ontvangen bericht te matchen.

Nu hebben we ongeveer 30 microservices, die in verschillende groepen kunnen worden verdeeld:

  1. Configuratiebeheer.
  2. Informatie en interactie met gebruikers (messengers, mail).
  3. Werken met broncode.
  4. Integratie met implementatietools (jenkins, nomad, consul, etc.).
  5. Monitoring (releases, fouten, etc.).
  6. Webhulpprogramma's (UI voor het beheren van testomgevingen, het verzamelen van statistieken, enz.).
  7. Integratie met taaktrackers en soortgelijke systemen.
  8. Workflowbeheer voor verschillende taken.

Workflow-taken

Integro automatiseert activiteiten die verband houden met de taaklevenscyclus. In vereenvoudigde termen wordt de levenscyclus van een taak begrepen als de workflow van een taak in Jira. Onze ontwikkelingsprocessen kennen verschillende workflowvariaties, afhankelijk van het project, het type taak en de opties die voor een bepaalde taak zijn geselecteerd. 

Laten we eens kijken naar de workflow die we het vaakst gebruiken:

Van scripts tot ons eigen platform: hoe we de ontwikkeling bij CIAN hebben geautomatiseerd

In het diagram geeft het tandwiel aan dat de transitie automatisch door Integro wordt aangeroepen, terwijl de menselijke figuur aangeeft dat de transitie handmatig door een persoon wordt opgeroepen. Laten we eens kijken naar de verschillende paden die een taak in deze workflow kan volgen.

Volledig handmatig testen op DEV+BETA zonder kanarietests (meestal geven we zo een monoliet vrij):

Van scripts tot ons eigen platform: hoe we de ontwikkeling bij CIAN hebben geautomatiseerd

Er kunnen andere overgangscombinaties zijn. Soms kan het pad dat een probleem zal volgen, worden geselecteerd via opties in Jira.

Taakbeweging

Laten we eens kijken naar de belangrijkste stappen die worden uitgevoerd wanneer een taak door de workflow β€œDEV Testing + Canary Tests” gaat:

1. De ontwikkelaar of PM maakt de taak aan.

2. De ontwikkelaar neemt de taak mee naar het werk. Na voltooiing schakelt het over naar de status IN REVIEW.

3. Jira stuurt een Webhook naar de Jira-microservice (verantwoordelijk voor integratie met Jira).

4. De Jira-microservice stuurt een verzoek naar de Flow-service (verantwoordelijk voor interne workflows waarin wordt gewerkt) om de workflow te starten.

5. Binnen de Flow-service:

  • Er worden reviewers toegewezen aan de taak (microservice Gebruikers die alles weet over gebruikers + Jira-microservice).
  • Via de Source-microservice (deze kent de repositories en branches, maar werkt niet met de code zelf) wordt gezocht naar repositories die een branch van ons probleem bevatten (om het zoeken te vereenvoudigen valt de naam van de branch samen met het issue nummer in Jira). Meestal heeft een taak slechts één vertakking in één opslagplaats; dit vereenvoudigt het beheer van de implementatiewachtrij en vermindert de connectiviteit tussen opslagplaatsen.
  • Voor elke gevonden tak wordt de volgende reeks acties uitgevoerd:

    i) Het bijwerken van de masterbranch (Git-microservice voor het werken met code).
    ii) De vertakking is geblokkeerd voor wijzigingen door de ontwikkelaar (Bitbucket-microservice).
    iii) Er wordt een Pull Request gemaakt voor deze vertakking (Bitbucket-microservice).
    iv) Er wordt een bericht over een nieuwe Pull Request verzonden naar chats van ontwikkelaars (Notify microservice voor het werken met meldingen).
    v) Bouw-, test- en implementatietaken worden gestart op DEV (Jenkins-microservice voor het werken met Jenkins).
    vi) Als alle voorgaande stappen met succes zijn voltooid, plaatst Integro de Approve in de Pull Request (Bitbucket-microservice).

  • Integro wacht op goedkeuring in Pull Request van aangewezen reviewers.
  • Zodra alle noodzakelijke goedkeuringen zijn ontvangen (inclusief geautomatiseerde tests die positief zijn geslaagd), draagt ​​Integro de taak over naar de status Test on Dev (Jira microservice).

6. Testers testen de taak. Als er geen problemen zijn, wordt de taak overgedragen naar de status Ready For Build.

7. Integro β€œziet” dat de taak klaar is voor release en start de implementatie ervan in de canarische modus (Jenkins-microservice). De gereedheid voor vrijgave wordt bepaald door een reeks regels. De taak heeft bijvoorbeeld de vereiste status, er zijn geen vergrendelingen op andere taken, er zijn momenteel geen actieve uploads van deze microservice, enz.

8. De taak wordt overgedragen naar de Canarische status (Jira-microservice).

9. Jenkins start een implementatietaak via Nomad in de canarische modus (meestal 1-3 exemplaren) en brengt de releasemonitoringservice (DeployWatch-microservice) op de hoogte van de implementatie.

10. De microservice DeployWatch verzamelt de foutachtergrond en reageert hierop indien nodig. Als de foutachtergrond wordt overschreden (de achtergrondnorm wordt automatisch berekend), worden ontwikkelaars hiervan op de hoogte gesteld via de Notify-microservice. Als de ontwikkelaar na 5 minuten niet heeft gereageerd (op Terugkeren of Blijven heeft geklikt), wordt een automatische terugdraaiing van de canary-instanties gestart. Als de achtergrond niet wordt overschreden, moet de ontwikkelaar de taakimplementatie handmatig naar Productie starten (door op een knop in de gebruikersinterface te klikken). Als de ontwikkelaar de implementatie niet binnen 60 minuten naar productie heeft gelanceerd, worden de canary-instanties om veiligheidsredenen ook teruggedraaid.

11. Na het starten van de implementatie naar Productie:

  • De taak wordt overgebracht naar de productiestatus (Jira-microservice).
  • De Jenkins-microservice start het implementatieproces en informeert de DeployWatch-microservice over de implementatie.
  • De microservice DeployWatch controleert of alle containers in Productie zijn bijgewerkt (er waren gevallen waarin niet alle containers waren bijgewerkt).
  • Via de Notify-microservice wordt een melding over de resultaten van de implementatie naar Productie gestuurd.

12. Ontwikkelaars hebben 30 minuten de tijd om een ​​taak uit Productie terug te draaien als er onjuist microservicegedrag wordt gedetecteerd. Na deze tijd wordt de taak automatisch samengevoegd in de master (Git-microservice).

13. Na een succesvolle samenvoeging met de master wordt de taakstatus gewijzigd in Gesloten (Jira-microservice).

Het diagram pretendeert niet volledig gedetailleerd te zijn (in werkelijkheid zijn er zelfs nog meer stappen), maar het stelt je in staat de mate van integratie in processen te beoordelen. We beschouwen dit plan niet als ideaal en verbeteren de processen voor automatische release- en implementatieondersteuning.

What's Next

We hebben grote plannen voor de ontwikkeling van automatisering, bijvoorbeeld door handmatige handelingen tijdens monolith-releases te elimineren, de monitoring tijdens automatische implementatie te verbeteren en de interactie met ontwikkelaars te verbeteren.

Maar laten we hier voorlopig stoppen. Veel onderwerpen in de automatiseringsreview hebben we oppervlakkig behandeld, sommige zijn helemaal niet besproken, dus we beantwoorden graag vragen. We wachten op suggesties over wat we in detail moeten behandelen, schrijf in de reacties.

Bron: www.habr.com

Voeg een reactie