In projekte wat verband hou met die ontwikkeling van mikrodiensargitektuur, beweeg CI/CD van die kategorie van 'n aangename geleentheid na die kategorie van 'n dringende noodsaaklikheid. Outomatiese toetsing is 'n integrale deel van deurlopende integrasie, 'n bekwame benadering tot wat die span baie aangename aande saam met familie en vriende kan gee. Andersins loop die projek die risiko om nooit voltooi te word nie.
Dit is moontlik om die hele mikrodienskode met eenheidstoetse met skynvoorwerpe te dek, maar dit los die probleem net gedeeltelik op en laat baie vrae en probleme, veral wanneer werk met data getoets word. Soos altyd is die dringendste om datakonsekwentheid in 'n relasionele databasis te toets, werk met wolkdienste te toets en verkeerde aannames te maak wanneer skynvoorwerpe geskryf word.
Dit alles en 'n bietjie meer kan opgelos word deur die hele mikrodiens in 'n Docker-houer te toets. ’n Ongetwyfelde voordeel om die geldigheid van toetse te verseker, is dat dieselfde Docker-beelde wat in produksie gaan, getoets word.
Outomatisering van hierdie benadering bied 'n aantal probleme, waarvan die oplossing hieronder beskryf sal word:
- konflikte van parallelle take in dieselfde docker-gasheer;
- identifiseerder konflikte in die databasis tydens toets iterasies;
- wag vir mikrodienste om gereed te wees;
- samevoeging en uitvoer van logs na eksterne stelsels;
- toets uitgaande HTTP-versoeke;
- websoktoetsing (met SignalR);
- toets OAuth-verifikasie en magtiging.
Hierdie artikel is gebaseer op
In hierdie artikel sal ek jou vertel hoe om 'n skrip te gebruik om die diens wat getoets word, 'n databasis en Amazon AWS-dienste in Docker te gebruik, toets dan op Postman en, nadat dit voltooi is, stop en vee die geskepte houers uit. Toetse word uitgevoer elke keer as die kode verander. Op hierdie manier maak ons seker dat elke weergawe korrek werk met die AWS databasis en dienste.
Dieselfde skrip word deur die ontwikkelaars self op hul Windows-rekenaars en deur die Gitlab CI-bediener onder Linux bestuur.
Om geregverdig te wees, moet die bekendstelling van nuwe toetse nie die installering van bykomende gereedskap vereis op die ontwikkelaar se rekenaar of op die bediener waar die toetse op 'n commit uitgevoer word nie. Docker los hierdie probleem op.
Die toets moet om die volgende redes op 'n plaaslike bediener loop:
- Die netwerk is nooit heeltemal betroubaar nie. Uit 'n duisend versoeke kan een misluk;
In hierdie geval sal die outomatiese toets nie werk nie, die werk sal stop, en jy sal die rede in die logs moet soek; - Te gereelde versoeke word nie deur sommige derdepartydienste toegelaat nie.
Daarbenewens is dit ongewens om die staander te gebruik omdat:
- 'n Stand kan nie net gebreek word deur slegte kode wat daarop loop nie, maar ook deur data wat die korrekte kode nie kan verwerk nie;
- Maak nie saak hoe hard ons probeer om al die veranderinge wat deur die toets tydens die toets self gemaak is, terug te keer nie, iets kan verkeerd gaan (anders, hoekom toets?).
Oor die projek en prosesorganisasie
Ons maatskappy het 'n mikrodiens-webtoepassing ontwikkel wat in Docker in die Amazon AWS-wolk loop. Eenheidtoetse is reeds op die projek gebruik, maar foute het dikwels voorgekom wat die eenheidstoetse nie opgespoor het nie. Dit was nodig om 'n hele mikrodiens saam met die databasis en Amazon-dienste te toets.
Die projek gebruik 'n standaard deurlopende integrasieproses, wat die toetsing van die mikrodiens met elke commit insluit. Nadat 'n taak toegewys is, maak die ontwikkelaar veranderinge aan die mikrodiens, toets dit met die hand en voer alle beskikbare outomatiese toetse uit. Indien nodig, verander die ontwikkelaar die toetse. As geen probleme gevind word nie, word 'n verbintenis aan die tak van hierdie uitgawe gemaak. Na elke commit word toetse outomaties op die bediener uitgevoer. Om in 'n gemeenskaplike tak saam te smelt en outomatiese toetse daarop te begin, vind plaas na 'n suksesvolle hersiening. As die toetse op die gedeelde tak slaag, word die diens outomaties opgedateer in die toetsomgewing op Amazon Elastic Container Service (bank). Die staander is nodig vir alle ontwikkelaars en toetsers, en dit is nie raadsaam om dit te breek nie. Toetsers in hierdie omgewing kontroleer 'n oplossing of 'n nuwe kenmerk deur handtoetse uit te voer.
Projek argitektuur
Die toepassing bestaan uit meer as tien dienste. Sommige van hulle is in .NET Core geskryf en sommige in NodeJs. Elke diens loop in 'n Docker-houer in die Amazon Elastic Container Service. Elkeen het sy eie Postgres-databasis, en sommige het ook Redis. Daar is geen algemene databasisse nie. As verskeie dienste dieselfde data benodig, word hierdie data, wanneer dit verander, na elk van hierdie dienste oorgedra via SNS (Simple Notification Service) en SQS (Amazon Simple Queue Service), en die dienste stoor dit in hul eie aparte databasisse.
SQS en SNS
SQS laat jou toe om boodskappe in 'n tou te plaas en boodskappe uit die tou te lees met behulp van die HTTPS-protokol.
As verskeie dienste een tou lees, kom elke boodskap slegs na een van hulle. Dit is nuttig wanneer verskeie gevalle van dieselfde diens uitgevoer word om die las tussen hulle te versprei.
As jy wil hê dat elke boodskap aan verskeie dienste afgelewer moet word, moet elke ontvanger sy eie tou hê, en SNS is nodig om boodskappe in veelvuldige toue te dupliseer.
In SNS skep jy 'n onderwerp en teken daarop in, byvoorbeeld 'n SQS-tou. Jy kan boodskappe na onderwerp stuur. In hierdie geval word die boodskap gestuur na elke tou wat op hierdie onderwerp ingeteken is. SNS het nie 'n metode om boodskappe te lees nie. As jy tydens ontfouting of toetsing moet uitvind wat na SNS gestuur word, kan jy 'n SQS-tou skep, dit op die verlangde onderwerp inteken en die tou lees.
API-poort
Die meeste dienste is nie direk vanaf die internet toeganklik nie. Toegang is via API Gateway, wat toegangsregte kontroleer. Dit is ook ons diens, en daar is ook toetse daarvoor.
Intydse kennisgewings
Die toepassing gebruik
Bekende toetsbenadering
Eenheidtoetse vervang dinge soos die databasis met skynvoorwerpe. As 'n mikrodiens, byvoorbeeld, probeer om 'n rekord in 'n tabel met 'n vreemde sleutel te skep, en die rekord waarna daardie sleutel verwys, bestaan nie, dan kan die versoek nie voltooi word nie. Eenheidtoetse kan dit nie opspoor nie.
В
In-geheue databasis is een van die DBBS'e wat deur die Entiteitsraamwerk ondersteun word. Dit is spesifiek vir toetsing geskep. Data in so 'n databasis word slegs gestoor totdat die proses wat dit gebruik, beëindig word. Dit vereis nie die skep van tabelle nie en kontroleer nie data-integriteit nie.
Bespotlike voorwerpe modelleer die klas wat hulle vervang slegs in die mate dat die toetsontwikkelaar verstaan hoe dit werk.
Hoe om Postgres te kry om outomaties migrasies te begin en uit te voer wanneer jy 'n toets uitvoer, word nie in die Microsoft-artikel gespesifiseer nie. My oplossing doen dit en voeg boonop geen kode spesifiek vir toetse by die mikrodiens self nie.
Kom ons gaan aan na die oplossing
Tydens die ontwikkelingsproses het dit duidelik geword dat eenheidstoetse nie genoeg was om alle probleme betyds op te spoor nie, daarom is besluit om hierdie kwessie vanuit 'n ander hoek te benader.
Die opstel van 'n toetsomgewing
Die eerste taak is om 'n toetsomgewing te ontplooi. Stappe wat nodig is om 'n mikrodiens te bestuur:
- Konfigureer die diens wat getoets word vir die plaaslike omgewing, spesifiseer die besonderhede vir koppeling aan die databasis en AWS in die omgewingsveranderlikes;
- Begin Postgres en voer die migrasie uit deur Liquibase uit te voer.
In relasionele DBBS'e, voordat u data in die databasis skryf, moet u 'n dataskema skep, met ander woorde, tabelle. Wanneer 'n toepassing opgedateer word, moet tabelle gebring word na die vorm wat deur die nuwe weergawe gebruik word, en verkieslik sonder om data te verloor. Dit word migrasie genoem. Die skep van tabelle in 'n aanvanklik leë databasis is 'n spesiale geval van migrasie. Migrasie kan in die toepassing self ingebou word. Beide .NET en NodeJS het migrasieraamwerke. In ons geval word mikrodienste om sekuriteitsredes die reg ontneem om die dataskema te verander, en die migrasie word met Liquibase uitgevoer. - Begin Amazon LocalStack. Dit is 'n implementering van AWS-dienste om tuis uit te voer. Daar is 'n klaargemaakte prent vir LocalStack op Docker Hub.
- Begin die skrip om die nodige entiteite in LocalStack te skep. Shell-skrifte gebruik die AWS CLI.
Word gebruik om op die projek te toets
Hoe werk die outomatiese toets?
Tydens die toets werk alles in Docker: die diens wat getoets word, Postgres, die migrasie-instrument, en Postman, of eerder sy konsole-weergawe - Newman.
Docker los 'n aantal probleme op:
- Onafhanklikheid van gasheerkonfigurasie;
- Installeer afhanklikhede: Docker laai beelde van Docker Hub af;
- Om die stelsel terug te keer na sy oorspronklike toestand: verwyder eenvoudig die houers.
Docker-komponeer verenig houers in 'n virtuele netwerk, geïsoleer van die internet, waarin houers mekaar deur domeinname vind.
Die toets word beheer deur 'n dopskrif. Om die toets op Windows uit te voer, gebruik ons git-bash. Dus, een skrif is genoeg vir beide Windows en Linux. Git en Docker word deur alle ontwikkelaars op die projek geïnstalleer. Wanneer Git op Windows geïnstalleer word, is git-bash geïnstalleer, so almal het dit ook.
Die skrip voer die volgende stappe uit:
- Bou docker-beelde
docker-compose build
- Begin die databasis en LocalStack
docker-compose up -d <контейнер>
- Databasismigrasie en voorbereiding van LocalStack
docker-compose run <контейнер>
- Die bekendstelling van die diens wat getoets word
docker-compose up -d <сервис>
- Hardloop die toets (Newman)
- Stop alle houers
docker-compose down
- Plaas resultate in Slack
Ons het 'n geselsie waar boodskappe met 'n groen regmerkie of 'n rooi kruis en 'n skakel na die log gaan.
Die volgende Docker-beelde is by hierdie stappe betrokke:
- Die diens wat getoets word, is dieselfde beeld as vir produksie. Die konfigurasie vir die toets is deur omgewingsveranderlikes.
- Vir Postgres, Redis en LocalStack word klaargemaakte beelde van Docker Hub gebruik. Daar is ook klaargemaakte beelde vir Liquibase en Newman. Ons bou ons s'n op hul skelet en voeg ons lêers daar by.
- Om LocalStack voor te berei, gebruik jy 'n klaargemaakte AWS CLI-beeld en skep 'n prent wat 'n skrif bevat wat daarop gebaseer is.
Die gebruik van
Probleme wat jy mag teëkom
Wag vir gereedheid
Wanneer 'n houer met 'n diens aan die gang is, beteken dit nie dat dit gereed is om verbindings te aanvaar nie. Jy moet wag vir die verbinding om voort te gaan.
Hierdie probleem word soms opgelos deur 'n skrip te gebruik
besluit: LocalStack-voorsiening-skrifte wat wag vir 'n 200-antwoord van beide SQS en SNS.
Parallelle taakkonflikte
Veelvuldige toetse kan gelyktydig op dieselfde Docker-gasheer uitgevoer word, so houer- en netwerkname moet uniek wees. Boonop kan toetse van verskillende takke van dieselfde diens ook gelyktydig loop, so dit is nie genoeg om hul name in elke opstellêer te skryf nie.
besluit: Die skrip stel die COMPOSE_PROJECT_NAME veranderlike op 'n unieke waarde.
Windows-kenmerke
Daar is 'n aantal dinge wat ek wil uitwys wanneer u Docker op Windows gebruik, aangesien hierdie ervarings belangrik is om te verstaan waarom foute voorkom.
- Shell-skrifte in 'n houer moet Linux-reëleindes hê.
Die dop CR simbool is 'n sintaksis fout. Dit is moeilik om uit die foutboodskap te sê dat dit die geval is. Wanneer u sulke skrifte op Windows redigeer, benodig u 'n behoorlike teksredigeerder. Daarbenewens moet die weergawebeheerstelsel behoorlik gekonfigureer word.
Dit is hoe git opgestel is:
git config core.autocrlf input
- Git-bash emuleer standaard Linux-vouers en, wanneer 'n exe-lêer (insluitend docker.exe) geroep word, vervang absolute Linux-paaie met Windows-paaie. Dit maak egter nie sin vir paaie wat nie op die plaaslike masjien (of paaie in 'n houer) is nie. Hierdie gedrag kan nie gedeaktiveer word nie.
besluit: voeg 'n bykomende skuinsstreep by die begin van die pad: //bin in plaas van /bin. Linux verstaan sulke paaie; daarvoor is verskeie skuinsstreepies dieselfde as een. Maar git-bash herken nie sulke paaie nie en probeer dit nie omskakel nie.
Log uitset
Wanneer ek toetse uitvoer, wil ek graag sien dat logs van beide Newman en die diens getoets word. Aangesien die gebeure van hierdie logboeke met mekaar verbind is, is dit baie geriefliker om dit in een konsole te kombineer as twee afsonderlike lêers. Newman loods via docker-compose run, en so beland sy uitset in die konsole. Al wat oorbly is om seker te maak dat die uitset van die diens ook daarheen gaan.
Die oorspronklike oplossing was om te doen docker-opstel geen vlag nie -d, maar gebruik die dop-vermoëns, stuur hierdie proses na die agtergrond:
docker-compose up <service> &
Dit het gewerk totdat dit nodig was om logs van Docker na 'n derdeparty-diens te stuur. docker-opstel opgehou om logs na die konsole uit te voer. Die span het egter gewerk docker heg.
besluit:
docker attach --no-stdin ${COMPOSE_PROJECT_NAME}_<сервис>_1 &
Identifiseerderkonflik tydens toetsiterasies
Toetse word in verskeie iterasies uitgevoer. Die databasis is nie skoongemaak nie. Rekords in die databasis het unieke ID's. As ons spesifieke ID's in versoeke neerskryf, sal ons 'n konflik kry by die tweede herhaling.
Om dit te vermy, moet óf die ID's uniek wees, óf alle voorwerpe wat deur die toets geskep is, moet uitgevee word. Sommige voorwerpe kan weens vereistes nie uitgevee word nie.
besluit: genereer GUID's met behulp van Postman-skrifte.
var uuid = require('uuid');
var myid = uuid.v4();
pm.environment.set('myUUID', myid);
Gebruik dan die simbool in die navraag {{myUUID}}, wat vervang sal word met die waarde van die veranderlike.
Samewerking via LocalStack
As die diens wat getoets word, 'n SQS-waglys lees of skryf, moet die toets self ook met hierdie tou werk om dit te verifieer.
besluit: versoeke van Postman na LocalStack.
Die AWS-dienste-API is gedokumenteer, sodat navrae sonder 'n SDK gemaak kan word.
As 'n diens na 'n tou skryf, lees ons dit en kontroleer die inhoud van die boodskap.
As die diens boodskappe na SNS stuur, skep LocalStack in die voorbereidingstadium ook 'n tou en teken in op hierdie SNS-onderwerp. Dan kom dit alles neer op wat hierbo beskryf is.
As die diens 'n boodskap uit die tou moet lees, skryf ons in die vorige toetsstap hierdie boodskap na die tou.
Toets HTTP-versoeke wat afkomstig is van die mikrodiens wat getoets word
Sommige dienste werk oor HTTP met iets anders as AWS, en sommige AWS-kenmerke word nie in LocalStack geïmplementeer nie.
besluit: in hierdie gevalle kan dit help
Toets tans OAuth-verifikasie en magtiging
Ons gebruik OAuth en
Alle interaksie tussen die diens en die OAuth-verskaffer kom neer op twee versoeke: eerstens word die konfigurasie versoek /.welbekende/openid-konfigurasie, en dan word die publieke sleutel (JWKS) by die adres van die konfigurasie aangevra. Dit alles is statiese inhoud.
besluit: Ons toets OAuth-verskaffer is 'n statiese inhoudbediener en twee lêers daarop. Die teken word een keer gegenereer en aan Git verbind.
Kenmerke van SignalR-toetsing
Posman werk nie met websockets nie. 'n Spesiale hulpmiddel is geskep om SignalR te toets.
'n SignalR-kliënt kan meer as net 'n blaaier wees. Daar is 'n kliëntbiblioteek daarvoor onder .NET Core. Die kliënt, geskryf in .NET Core, vestig 'n verbinding, word geverifieer en wag vir 'n spesifieke volgorde van boodskappe. As 'n onverwagte boodskap ontvang word of die verbinding word verloor, gaan die kliënt uit met 'n kode van 1. As die laaste verwagte boodskap ontvang word, gaan die kliënt uit met 'n kode van 0.
Newman werk gelyktydig met die kliënt. Verskeie kliënte word geloods om seker te maak dat boodskappe afgelewer word aan almal wat dit nodig het.
Gebruik die opsie om verskeie kliënte te laat loop --skaal op die docker-compose-opdragreël.
Voordat dit uitgevoer word, wag die Postman-skrip vir alle kliënte om verbindings te bewerkstellig.
Ons het reeds die probleem ondervind om vir 'n verbinding te wag. Maar daar was bedieners, en hier is die kliënt. ’n Ander benadering is nodig.
besluit: die kliënt in die houer gebruik die meganisme
HEALTHCHECK --interval=3s CMD if [ ! -e /healthcheck ]; then false; fi
Span docker inspekteer Toon die normale status, gesondheidstatus en uitgangkode vir die houer.
Nadat Newman voltooi het, kontroleer die skrip dat alle houers by die kliënt beëindig is, met kode 0.
Happinnes bestaan
Nadat ons die probleme hierbo beskryf het oorkom, het ons 'n stel stabiele hardlooptoetse gehad. In toetse werk elke diens as 'n enkele eenheid, in wisselwerking met die databasis en Amazon LocalStack.
Hierdie toetse beskerm 'n span van 30+ ontwikkelaars teen foute in 'n toepassing met komplekse interaksie van 10+ mikrodienste met gereelde ontplooiings.
Bron: will.com