Da i scripts à a nostra propria piattaforma: cumu avemu automatizatu u sviluppu à CIAN

Da i scripts à a nostra propria piattaforma: cumu avemu automatizatu u sviluppu à CIAN

À RIT 2019, u nostru cumpagnu Alexander Korotkov hà fattu rapportu circa l'automatizazione di u sviluppu in CIAN: per simplificà a vita è u travagliu, usemu a nostra propria piattaforma Integro. Traccia u ciclu di vita di i travaglii, allevia i sviluppatori di operazioni di rutina è riduce significativamente u numeru di bug in a produzzione. In questu post, completeremu u rapportu d'Alexandru è vi diceremu cumu si passava da script simplici à cumminà i prudutti open source attraversu a nostra propria piattaforma è ciò chì face a nostra squadra d'automatizazione separata.
 

Livellu zero

"Ùn ci hè nunda cum'è un livellu zero, ùn cunnoscu micca una cosa cusì"
Maestru Shifu da u filmu "Kung Fu Panda"

L'automatizazione in CIAN hà iniziatu 14 anni dopu a fondazione di a cumpagnia. À quellu tempu ci era 35 persone in a squadra di sviluppu. Difficile à crede, nò? Di sicuru, l'automatizazione esistia in una certa forma, ma una direzzione separata per l'integrazione cuntinua è a consegna di codice hà cuminciatu à piglià forma in 2015. 

À quellu tempu, avemu avutu un grande monolitu di Python, C# è PHP, implementatu nantu à i servitori Linux / Windows. Per implementà stu mostru, avemu avutu un inseme di script chì avemu eseguitu manualmente. Ci era ancu l'assemblea di u monolitu, chì hà purtatu u dulore è u soffrenu per via di cunflitti quandu unisce e rami, corregge i difetti, è ricustruisce "cun un altru settore di compiti in a custruzzione". Un prucessu simplificatu pareva cusì:

Da i scripts à a nostra propria piattaforma: cumu avemu automatizatu u sviluppu à CIAN

Ùn eramu micca cuntenti di questu, è vuliamu custruisce un prucessu di creazione è implementazione ripetibile, automatizatu è gestibile. Per questu, avemu bisognu di un sistema CI / CD, è avemu sceltu trà a versione libera di Teamcity è a versione libera di Jenkins, postu chì avemu travagliatu cun elli è tutti dui ci sò adattati in quantu à u settore di funzioni. Avemu sceltu Teamcity cum'è un pruduttu più recente. À quellu tempu, ùn aviamu micca ancu utilizatu l'architettura di microserviziu è ùn s'aspittava micca un gran numaru di travaglii è prughjetti.

Venemu à l'idea di u nostru sistema

L'implementazione di Teamcity hà eliminatu solu una parte di u travagliu manuale: ciò chì resta hè a creazione di Pull Requests, a prumuzione di prublemi per statutu in Jira, è a selezzione di prublemi per a liberazione. U sistema Teamcity ùn pudia più affruntà questu. Era necessariu di sceglie a strada di più automatizazione. Avemu cunsideratu l'opzioni per travaglià cù script in Teamcity o cambià à sistemi d'automatizazione di terzu. Ma à a fine avemu decisu chì avemu bisognu di flessibilità massima, chì solu a nostra propria suluzione pò furnisce. Hè cusì chì a prima versione di u sistema d'automatizazione internu chjamatu Integro hè apparsu.

Teamcity tratta di l'automatizazione à u livellu di lanciazione di i prucessi di custruzzione è di implementazione, mentre chì Integro si cuncintrau in l'automatizazione di u primu livellu di i prucessi di sviluppu. Era necessariu di cumminà u travagliu cù prublemi in Jira cù u processu di codice fonte assuciatu in Bitbucket. À questu stadiu, Integro hà cuminciatu à avè u so propiu flussu di travagliu per travaglià cù travaglii di diversi tipi. 

A causa di l'automatizazione in i prucessi di cummerciale, u numeru di prughjetti è corse in Teamcity hè aumentatu. Allora un novu prublema hè ghjuntu: una istanza libera di Teamcity ùn era micca abbastanza (3 agenti è 100 prughjetti), avemu aghjustatu un altru esempiu (3 più agenti è 100 prughjetti), dopu un altru. In u risultatu, avemu finitu cù un sistema di parechji clusters, chì era difficiule di gestisce:

Da i scripts à a nostra propria piattaforma: cumu avemu automatizatu u sviluppu à CIAN

Quandu a quistione di una 4a istanza hè ghjunta, avemu capitu chì ùn pudemu micca cuntinuà à campà cusì, perchè i costi totali di supportu 4 istanze ùn eranu più in alcun limite. A quistione hè ghjunta nantu à l'acquistu di Teamcity pagatu o di sceglie Jenkins gratuiti. Avemu fattu calculi nantu à istanze è piani d'automatizazione è decisu chì vivemu nantu à Jenkins. Dopu un paru di settimane, avemu cambiatu à Jenkins è eliminatu alcuni di u mal di testa assuciatu à mantene parechje istanze di Teamcity. Dunque, avemu pussutu fucalizza nantu à sviluppà Integro è persunalizà Jenkins per noi stessi.

Cù a crescita di l'automatizazione di basa (in a forma di creazione automatica di Pull Requests, cullizzioni è publicazione di a cobertura di u Code è altri cuntrolli), ci hè un forte desideriu di abbandunà e versioni manuali quant'è pussibule è dà stu travagliu à i robots. Inoltre, a cumpagnia hà cuminciatu à trasfurmà à i microservizi in a cumpagnia, chì necessitava liberazioni frequenti, è separatamente l'una di l'altru. Hè cusì chì avemu gradualmente ghjuntu à e versioni automatiche di i nostri microservizi (attualmente stendemu u monolitu manualmente per via di a cumplessità di u prucessu). Ma, cum'è di solitu succede, hè ghjunta una nova cumplessità. 

Automatizemu a prova

Da i scripts à a nostra propria piattaforma: cumu avemu automatizatu u sviluppu à CIAN

A causa di l'automatizazione di e versioni, i prucessi di sviluppu anu acceleratu, in parte per via di saltà di alcune tappe di prova. È questu hà purtatu à una perdita temporale di qualità. Sembra triviale, ma cù l'accelerazione di e versioni, era necessariu di cambià a metodulugia di sviluppu di u produttu. Hè statu necessariu di pensà à l'automatizazione di e teste, infundendu a rispunsabilità persunale (quì si parla di "accettà l'idea in u capu", micca fine monetaria) di u sviluppatore per u codice liberatu è i bug in questu, è ancu a decisione di liberate / micca liberate un compitu per mezu di implementazione automatica. 

Eliminendu i prublemi di qualità, avemu ghjuntu à duie decisioni impurtanti: avemu cuminciatu à fà una prova canaria è hà introduttu u monitoraghju automaticu di u fondu di errore cù una risposta automatica à u so eccessu. A prima suluzione hà permessu di truvà errori evidenti prima chì u codice hè stata liberata cumplettamente in a produzzione, a seconda hà riduciutu u tempu di risposta à i prublemi in a produzzione. L'errori, sicuru, succedenu, ma passamu a maiò parte di u nostru tempu è sforzu micca per correggerli, ma per minimizzà. 

Squadra di l'automatizazione

Avemu attualmente un staffu di sviluppatori 130, è cuntinuemu cresce. A squadra per l'integrazione cuntinuu è a spedizione di codice (in seguitu chjamata Deploy and Integration o squadra DI) hè custituita da 7 persone è travaglia in direzzione 2: sviluppu di a piattaforma d'automatizazione Integro è DevOps. 

DevOps hè rispunsevule per l'ambiente Dev / Beta di u situ CIAN, l'ambienti Integro, aiuta à i sviluppatori à risolve i prublemi è sviluppa novi approcci à scaling ambienti. A direzzione di sviluppu Integro si tratta di l'Integro stessu è di i servizii cunnessi, per esempiu, plugins per Jenkins, Jira, Confluence, è ancu sviluppa utilità ausiliarie è applicazioni per i gruppi di sviluppu. 

U squadra DI travaglia in cullaburazione cù a squadra di a Piattaforma, chì sviluppa l'architettura, biblioteche è approcci di sviluppu internamente. À u listessu tempu, ogni sviluppatore in CIAN pò cuntribuisce à l'automatizazione, per esempiu, fà micro-automatizazione per adattà à i bisogni di a squadra o sparte una idea fresca nantu à cumu fà l'automatizazione ancu megliu.

Torta à strati di l'automatizazione à u CIAN

Da i scripts à a nostra propria piattaforma: cumu avemu automatizatu u sviluppu à CIAN

Tutti i sistemi implicati in l'automatizazione ponu esse divisi in parechji strati:

  1. Sistemi esterni (Jira, Bitbucket, etc.). I gruppi di sviluppu travaglianu cun elli.
  2. piattaforma Integro. A maiò spessu, i sviluppatori ùn travaglianu micca direttamente cun ellu, ma hè ciò chì mantene tutte l'automatizazione in esecuzione.
  3. Servizi di consegna, orchestrazione è scuperta (per esempiu, Jeknins, Consul, Nomad). Cù u so aiutu, implementemu codice nantu à i servitori è assicuratemu chì i servizii travaglianu cun l'altri.
  4. Stratu fisicu (servitori, OS, software rilativi). U nostru codice opera à stu livellu. Questu pò esse un servitore fisicu o virtuale (LXC, KVM, Docker).

Basatu annantu à stu cuncettu, dividemu e zone di rispunsabilità in a squadra DI. I primi dui livelli sò in l'area di rispunsabilità di a direzzione di sviluppu Integro, è l'ultimi dui livelli sò digià in l'area di responsabilità di DevOps. Sta separazione ci permette di fucalizza nantu à i travaglii è ùn interferiscenu micca cù l'interazzione, postu chì simu vicinu à l'altru è scambià constantemente cunniscenze è sperienza.

Intactu

Fighjemu nantu à Integro è cuminciamu cù a pila di tecnulugia:

  • CentOS 7
  • Docker + Nomad + Consul + Vault
  • Java 11 (u vechju monolitu Integro resterà in Java 8)
  • Spring Boot 2.X + Spring Cloud Config
  • PostgreSql 11
  • Rabbit MQ 
  • Apache Ignite
  • Camunda (incrustata)
  • Grafana + Grafite + Prometheus + Jaeger + ELK
  • UI Web: React (CSR) + MobX
  • SSO: Keycloak

Aderemu à u principiu di u sviluppu di u microserviziu, ancu s'è avemu un legatu in forma di un monolitu di una prima versione di Integro. Ogni microserviziu funziona in u so propiu cuntainer Docker; i servizii cumunicanu cù l'altri via richieste HTTP è missaghji RabbitMQ. I microservizi si trovanu à traversu Consul è facenu una dumanda à ellu, passendu l'autorizazione per SSO (Keycloak, OAuth 2/OpenID Connect).

Da i scripts à a nostra propria piattaforma: cumu avemu automatizatu u sviluppu à CIAN

Cum'è un esempiu di a vita reale, cunzidira l'interazzione cù Jenkins, chì si compone di i seguenti passi:

  1. U microserviziu di gestione di u flussu di travagliu (in seguitu chjamatu u microserviziu Flow) vole eseguisce una custruzzione in Jenkins. Per fà questu, usa Consul per truvà l'IP: PORT di u microserviziu per l'integrazione cù Jenkins (in seguitu chjamatu Jenkins microservice) è li manda una dumanda asincrona per inizià a custruzione in Jenkins.
  2. Dopu avè ricivutu una dumanda, u microserviziu Jenkins genera è risponde cù un ID di travagliu, chì pò esse usatu per identificà u risultatu di u travagliu. À u listessu tempu, attiva a custruzione in Jenkins via una chjamata API REST.
  3. Jenkins esegue a custruzzione è, dopu à a fine, manda un webhook cù i risultati di l'esekzione à u microserviziu Jenkins.
  4. U microserviziu Jenkins, dopu avè ricevutu u webhook, genera un missaghju nantu à a fine di u processu di a dumanda è aghjunghje i risultati di l'esekzione. U messagiu generatu hè mandatu à a fila RabbitMQ.
  5. Per mezu di RabbitMQ, u missaghju publicatu ghjunghje à u microserviziu Flow, chì ampara nantu à u risultatu di trasfurmà u so compitu cumminendu l'ID di Job da a dumanda è u missaghju ricevutu.

Avà avemu circa 30 microservizi, chì ponu esse divisi in parechji gruppi:

  1. Gestione di a cunfigurazione.
  2. Infurmazione è interaczione cù l'utilizatori (messageri, mail).
  3. U travagliu cù u codice fonte.
  4. Integrazione cù strumenti di implementazione (jenkins, nomadi, cunsul, etc.).
  5. Monitoring (releases, errors, etc.).
  6. Utilità Web (UI per a gestione di l'ambienti di prova, a cullizzioni di statistiche, etc.).
  7. Integrazione cù trackers di attività è sistemi simili.
  8. Gestione di u flussu di travagliu per diverse attività.

I travaglii di u flussu di travagliu

Integro automatizza l'attività ligati à u ciclu di vita di u travagliu. In termini simplificati, u ciclu di vita di un compitu serà capitu cum'è u flussu di travagliu di un compitu in Jira. I nostri prucessi di sviluppu anu parechje variazioni di flussu di travagliu secondu u prughjettu, u tipu di compitu è ​​l'opzioni selezziunate in un compitu particulari. 

Fighjemu u flussu di travagliu chì usemu più spessu:

Da i scripts à a nostra propria piattaforma: cumu avemu automatizatu u sviluppu à CIAN

In u diagramma, l'ingranaggio indica chì a transizione hè chjamata automaticamente da Integro, mentri a figura umana indica chì a transizione hè chjamata manualmente da una persona. Fighjemu parechji percorsi chì un compitu pò piglià in stu flussu di travagliu.

Testu cumpletamente manuale nantu à DEV + BETA senza teste canari (di solitu hè cusì chì liberamu un monolitu):

Da i scripts à a nostra propria piattaforma: cumu avemu automatizatu u sviluppu à CIAN

Ci ponu esse altre combinazioni di transizione. Calchì volta u percorsu chì un prublema pigliarà pò esse sceltu attraversu l'opzioni in Jira.

U muvimentu di u travagliu

Fighjemu i passi principali chì sò realizati quandu un compitu si move attraversu u flussu di travagliu "Test DEV + Test Canary":

1. U sviluppatore o PM crea u compitu.

2. U sviluppatore piglia u compitu à travaglià. Dopu à a fine, passa à u statu IN REVIEW.

3. Jira manda un Webhook à u microservice Jira (rispunsevuli di integrazione cù Jira).

4. U microservice Jira manda una dumanda à u serviziu Flow (rispunsevuli di i flussi di travagliu internu in quale u travagliu hè realizatu) per inizià u flussu di travagliu.

5. Dentru u serviziu di flussu:

  • I revisori sò attribuiti à u compitu (Users microservice chì sapi tuttu di l'utilizatori + Jira microservice).
  • Per mezu di u microserviziu Source (sà di repositori è rami, ma ùn travaglia micca cù u codice stessu), una ricerca hè fatta per i repositori chì cuntenenu un ramu di u nostru prublema (per simplificà a ricerca, u nome di a ramu coincide cù u prublema). numeru in Jira). A maiò spessu, un compitu hà solu un ramu in un repository; questu simplifica a gestione di a fila di implementazione è riduce a connettività trà i repositori.
  • Per ogni ramu truvata, a seguente sequenza di azzioni hè realizata:

    i) Aghjurnà u ramu maestru (microserviziu Git per travaglià cù u codice).
    ii) U ramu hè bluccatu da i cambiamenti da u sviluppatore (microserviziu Bitbucket).
    iii) Una Pull Request hè creata per questa filiera (microserviziu Bitbucket).
    iv) Un missaghju nantu à una nova Pull Request hè mandatu à i chats di sviluppatore (Notifica microservice per travaglià cù notificazioni).
    v) Custruisce, teste è implementà i travaglii sò iniziati in DEV (microserviziu Jenkins per travaglià cù Jenkins).
    vi) Se tutti i passi precedenti sò cumpletati cù successu, allora Integro mette a so Approvazione in a Pull Request (microservice Bitbucket).

  • Integro aspetta l'Approvazione in Pull Request da i revisori designati.
  • Appena tutte l'appruvazioni necessarie sò state ricevute (cumprese e teste automatizzate sò passate positivamente), Integro trasferisce u compitu à u statu di Test on Dev (microservice Jira).

6. Testers pruvà u compitu. Se ùn ci sò micca prublemi, u compitu hè trasferitu à u statu di Ready For Build.

7. Integro "vede" chì u compitu hè prontu per a liberazione è principia a so implementazione in modu canariu (microservice Jenkins). A preparazione per a liberazione hè determinata da un inseme di regule. Per esempiu, u compitu hè in u statutu necessariu, ùn ci sò micca chjusi nantu à altre attività, ùn ci hè attualmente micca uploads attivu di stu microserviziu, etc.

8. U compitu hè trasferitu à u statu di Canary (microservice Jira).

9. Jenkins lancia un compitu di implementazione attraversu Nomad in modu canarinu (in solitu 1-3 casi) è notifica à u serviziu di monitoraghju di liberazione (microservice DeployWatch) nantu à a implementazione.

10. U microserviziu DeployWatch recullà u fondu di l'errore è reagisce à questu, se ne necessariu. Se u fondu di l'errore hè superatu (a norma di fondo hè calculata automaticamente), i sviluppatori sò notificati via u microserviziu Notify. Se dopu à 5 minuti u sviluppatore ùn hà micca rispostu (cliccatu Revert or Stay), allora un rollback automaticu di i casi canarii hè lanciatu. Se u sfondate ùn hè micca superatu, allora u sviluppatore deve lancià manualmente l'implementazione di u compitu in Produzione (cliccate un buttone in l'UI). Se in 60 minuti u sviluppatore ùn hà micca lanciatu l'implementazione à a Produzione, allora l'istanze canarie seranu ancu annullate per ragioni di sicurezza.

11. Dopu avè lanciatu a implementazione à a Produzione:

  • U compitu hè trasferitu à u statutu di Produzione (microservice Jira).
  • U microserviziu Jenkins principia u prucessu di implementazione è notifica à u microserviziu DeployWatch nantu à a implementazione.
  • U microserviziu DeployWatch verifica chì tutti i cuntenituri nantu à a Produzione sò stati aghjurnati (ci sò stati casi quandu micca tutti sò stati aghjurnati).
  • Per mezu di u microserviziu Notify, una notificazione nantu à i risultati di a implementazione hè mandata à Produzione.

12. I sviluppatori averebbenu 30 minuti per cumincià à ritruvà un compitu da a Produzione se un comportamentu di microserviziu incorrectu hè rilevatu. Dopu stu tempu, u compitu serà automaticamente unitu in maestru (microservice Git).

13. Dopu à una fusione successu in u maestru, u statutu di u compitu serà cambiatu in Closed (Jira microservice).

U diagramma ùn pretende micca esse cumpletamente detallatu (in realtà ci sò ancu più passi), ma permette di valutà u gradu di integrazione in i prucessi. Ùn cunsideremu micca stu schema ideale è migliurà i prucessi di liberazione automatica è supportu di implementazione.

Chì vene

Avemu grandi piani per u sviluppu di l'automatizazione, per esempiu, l'eliminazione di l'operazioni manuali durante e versioni di monoliti, a migliurà a monitorizazione durante l'implementazione automatica, è a migliurà l'interazzione cù i sviluppatori.

Ma fermemu quì per avà. Avemu cupertu assai temi in a rivista di l'automatizazione superficialmente, alcuni ùn sò micca stati toccu in tuttu, cusì seremu felici di risponde à e dumande. Aspittemu suggerimenti nantu à ciò chì copre in dettagliu, scrivite in i cumenti.

Source: www.habr.com

Add a comment