Dockerin mikropalvelujen automaattinen testaus jatkuvaa integrointia varten

Mikropalveluarkkitehtuurin kehittämiseen liittyvissä projekteissa CI/CD siirtyy miellyttävän mahdollisuuden kategoriasta kiireellisen välttämättömyyden kategoriaan. Automaattinen testaus on olennainen osa jatkuvaa integraatiota, jonka asiantunteva lähestymistapa voi tarjota tiimille monia miellyttäviä iltoja perheen ja ystävien kanssa. Muutoin on vaarana, että hanketta ei saada valmiiksi.

Koko mikropalvelukoodi on mahdollista peittää yksikkötesteillä valeobjekteilla, mutta tämä ratkaisee ongelman vain osittain ja jättää paljon kysymyksiä ja vaikeuksia, varsinkin kun testataan työtä datalla. Kuten aina, kiireellisimmät ovat tietojen johdonmukaisuuden testaus relaatiotietokannassa, pilvipalvelujen testaus ja virheellisten oletusten tekeminen valeobjekteja kirjoitettaessa.

Kaikki tämä ja vähän muutakin voidaan ratkaista testaamalla koko mikropalvelu Docker-säiliössä. Kiistaton etu testien oikeellisuuden varmistamisessa on, että testataan samat tuotantoon menevät Docker-kuvat.

Tämän lähestymistavan automatisointi tuo mukanaan useita ongelmia, joiden ratkaisua kuvataan alla:

  • rinnakkaisten tehtävien ristiriidat samassa telakointiasemassa;
  • tunnisteristiriidat tietokannassa testiiteraatioiden aikana;
  • odottaa mikropalvelujen valmistumista;
  • lokien yhdistäminen ja tulostaminen ulkoisiin järjestelmiin;
  • lähtevien HTTP-pyyntöjen testaus;
  • web-liitäntätestaus (SignalR:n avulla);
  • testata OAuth-todennusta ja valtuutusta.

Tämä artikkeli perustuu minun puheeni SECR 2019:ssä. Joten niille, jotka ovat liian laiskoja lukemaan, tässä puheen tallenne.

Dockerin mikropalvelujen automaattinen testaus jatkuvaa integrointia varten

Tässä artikkelissa kerron sinulle, kuinka komentosarjan avulla suoritetaan testattava palvelu, tietokanta ja Amazon AWS -palvelut Dockerissa, sitten testataan Postmanilla ja niiden valmistuttua lopetetaan ja poistetaan luodut säilöt. Testit suoritetaan aina, kun koodi muuttuu. Näin varmistamme, että jokainen versio toimii oikein AWS-tietokannan ja -palveluiden kanssa.

Samaa komentosarjaa käyttävät sekä kehittäjät itse Windows-työasemillaan että Gitlab CI -palvelin Linuxissa.

On perusteltua, että uusien testien käyttöönotto ei saisi vaatia lisätyökalujen asentamista kehittäjän tietokoneelle tai palvelimelle, jossa testit suoritetaan commitissa. Docker ratkaisee tämän ongelman.

Testin on suoritettava paikallisella palvelimella seuraavista syistä:

  • Verkko ei ole koskaan täysin luotettava. Tuhansista pyynnöistä yksi voi epäonnistua;
    Tässä tapauksessa automaattinen testi ei toimi, työ pysähtyy, ja sinun on etsittävä syy lokeista;
  • Jotkut kolmannen osapuolen palvelut eivät salli liian usein tehtyjä pyyntöjä.

Lisäksi telineen käyttö ei ole toivottavaa, koska:

  • Teline voi särkyä paitsi siinä käynnissä olevan huonon koodin lisäksi myös tiedoista, joita oikea koodi ei pysty käsittelemään;
  • Vaikka kuinka yritämme palauttaa kaikki testin tekemät muutokset itse testin aikana, jokin voi mennä pieleen (muuten miksi testata?).

Tietoja projektista ja prosessiorganisaatiosta

Yrityksemme kehitti mikropalveluverkkosovelluksen, joka toimii Dockerissa Amazon AWS -pilvessä. Projektissa käytettiin jo yksikkötestejä, mutta usein tapahtui virheitä, joita yksikkötestit eivät havainneet. Oli tarpeen testata koko mikropalvelu tietokannan ja Amazon-palveluineen.

Projektissa käytetään vakiomuotoista jatkuvaa integrointiprosessia, joka sisältää mikropalvelun testaamisen jokaisen sitoumuksen yhteydessä. Tehtävän antamisen jälkeen kehittäjä tekee muutoksia mikropalveluun, testaa sen manuaalisesti ja suorittaa kaikki saatavilla olevat automaattiset testit. Tarvittaessa kehittäjä muuttaa testejä. Jos ongelmia ei löydy, sitoutuu tämän ongelman haaraan. Jokaisen toimituksen jälkeen testit suoritetaan automaattisesti palvelimella. Sulautuminen yhteiseksi haaraksi ja automaattisten testien käynnistäminen tapahtuu onnistuneen tarkastelun jälkeen. Jos testit jaetulla haaralla kulkevat, palvelu päivittyy automaattisesti Amazon Elastic Container Servicen (penkki) testiympäristöön. Teline on välttämätön kaikille kehittäjille ja testaajille, eikä sitä kannata rikkoa. Tämän ympäristön testaajat tarkistavat korjauksen tai uuden ominaisuuden suorittamalla manuaalisia testejä.

Projektin arkkitehtuuri

Dockerin mikropalvelujen automaattinen testaus jatkuvaa integrointia varten

Sovellus koostuu yli kymmenestä palvelusta. Osa niistä on kirjoitettu .NET Coressa ja osa NodeJ:ssä. Jokainen palvelu toimii Docker-säiliössä Amazon Elastic Container Servicessä. Jokaisella on oma Postgres-tietokanta, ja joillakin on myös Redis. Yhteisiä tietokantoja ei ole. Jos useat palvelut tarvitsevat samoja tietoja, nämä tiedot, kun ne muuttuvat, välitetään jokaiselle näistä palveluista SNS:n (Simple Notification Service) ja SQS:n (Amazon Simple Queue Service) kautta, ja palvelut tallentavat sen omiin erillisiin tietokantoihinsa.

SQS ja SNS

SQS:n avulla voit asettaa viestejä jonoon ja lukea viestejä jonosta HTTPS-protokollan avulla.

Jos useat palvelut lukevat yhtä jonoa, kukin viesti saapuu vain yhdelle niistä. Tämä on hyödyllistä käytettäessä useita saman palvelun esiintymiä kuormituksen jakamiseksi niiden välillä.

Jos haluat, että jokainen viesti toimitetaan useisiin palveluihin, jokaisella vastaanottajalla on oltava oma jononsa, ja SNS tarvitaan viestien monistamiseen useisiin jonoihin.

SNS:ssä luot aiheen ja tilaat sen, esimerkiksi SQS-jonon. Voit lähettää viestejä aiheeseen. Tässä tapauksessa viesti lähetetään jokaiseen tämän aiheen tilaajajonoon. SNS:llä ei ole menetelmää viestien lukemiseen. Jos virheenkorjauksen tai testauksen aikana sinun on selvitettävä, mitä SNS:lle lähetetään, voit luoda SQS-jonon, tilata sen haluttuun aiheeseen ja lukea jonon.

Dockerin mikropalvelujen automaattinen testaus jatkuvaa integrointia varten

API-yhdyskäytävä

Suurin osa palveluista ei ole suoraan saatavilla Internetistä. Pääsy tapahtuu API Gatewayn kautta, joka tarkistaa käyttöoikeudet. Tämä on myös palvelumme, ja sitä varten on myös testejä.

Reaaliaikaiset ilmoitukset

Sovellus käyttää SignaaliRnäyttääksesi käyttäjälle reaaliaikaisia ​​ilmoituksia. Tämä on toteutettu ilmoituspalvelussa. Se on käytettävissä suoraan Internetistä ja toimii itse OAuthin kanssa, koska osoittautui epäkäytännöllisemmäksi rakentaa tuki Web-socketeille Gatewaylle verrattuna OAuthin ja ilmoituspalvelun integrointiin.

Tunnettu testausmenetelmä

Yksikkötesteillä korvataan esimerkiksi tietokanta valeobjekteilla. Jos mikropalvelu esimerkiksi yrittää luoda tietueen taulukkoon vieraalla avaimella, eikä avaimella viitattua tietuetta ole olemassa, pyyntöä ei voida suorittaa loppuun. Yksikkötestit eivät pysty havaitsemaan tätä.

В artikkeli Microsoftilta On ehdotettu käytettäväksi muistissa olevaa tietokantaa ja toteuttaa valeobjekteja.

Muistissa oleva tietokanta on yksi Entity Frameworkin tukemista DBMS-järjestelmistä. Se luotiin erityisesti testausta varten. Tällaisen tietokannan tiedot säilytetään vain siihen asti, kunnes sitä käyttävä prosessi päättyy. Se ei vaadi taulukoiden luomista eikä tarkista tietojen eheyttä.

Valeobjektit mallintavat luokkaa, jota ne korvaavat, vain siinä määrin kuin testin kehittäjä ymmärtää, kuinka se toimii.

Microsoftin artikkelissa ei kerrota, miten Postgres käynnistää ja suorittaa siirrot automaattisesti, kun suoritat testin. Ratkaisuni tekee tämän, eikä myöskään lisää itse mikropalveluun mitään koodia erityisesti testejä varten.

Siirrytään ratkaisuun

Kehitysprosessin aikana kävi selväksi, että yksikkötestit eivät riittäneet löytämään kaikkia ongelmia ajoissa, joten asiaa päätettiin lähestyä toisesta näkökulmasta.

Testiympäristön luominen

Ensimmäinen tehtävä on ottaa käyttöön testiympäristö. Mikropalvelun suorittamiseen vaadittavat vaiheet:

  • Määritä testattava palvelu paikalliseen ympäristöön, määritä tietokantaan ja AWS:ään yhdistämisen tiedot ympäristömuuttujissa;
  • Käynnistä Postgres ja suorita siirto suorittamalla Liquibase.
    Relaatiotietokantajärjestelmissä ennen tietojen kirjoittamista tietokantaan on luotava tietoskeema, toisin sanoen taulukot. Sovellusta päivitettäessä taulukot tulee tuoda uuden version käyttämään muotoon ja mielellään tietoja menettämättä. Tätä kutsutaan migraatioksi. Taulukoiden luominen alun perin tyhjään tietokantaan on siirtymisen erikoistapaus. Siirto voidaan rakentaa itse sovellukseen. Sekä .NET:llä että NodeJS:llä on siirtokehykset. Meidän tapauksessamme mikropalveluilta viedään turvallisuussyistä oikeus muuttaa tietoskeemaa ja siirto suoritetaan Liquibasella.
  • Käynnistä Amazon LocalStack. Tämä on AWS-palveluiden toteutus kotona käytettäväksi. Docker Hubissa LocalStackille on valmis kuva.
  • Suorita komentosarja luodaksesi tarvittavat entiteetit LocalStackissa. Shell-skriptit käyttävät AWS CLI:tä.

Käytetään projektin testaamiseen Postinkantaja. Se oli olemassa aiemmin, mutta se käynnistettiin manuaalisesti ja testattiin osastolla jo käytössä olevaa sovellusta. Tämän työkalun avulla voit tehdä mielivaltaisia ​​HTTP(S)-pyyntöjä ja tarkistaa, vastaavatko vastaukset odotuksia. Kyselyt yhdistetään kokoelmaksi, ja koko kokoelma voidaan suorittaa.

Dockerin mikropalvelujen automaattinen testaus jatkuvaa integrointia varten

Miten automaattinen testi toimii?

Testin aikana kaikki toimii Dockerissa: testattava palvelu, Postgres, migraatiotyökalu ja Postman, tai pikemminkin sen konsoliversio - Newman.

Docker ratkaisee useita ongelmia:

  • Riippumattomuus isäntäkokoonpanosta;
  • Riippuvuuksien asentaminen: Docker lataa kuvat Docker Hubista;
  • Järjestelmän palauttaminen alkuperäiseen tilaan: yksinkertaisesti poistamalla säiliöt.

Docker-säveltäminen yhdistää kontit Internetistä eristettyyn virtuaaliseen verkkoon, jossa säiliöt löytävät toisensa verkkotunnusten perusteella.

Testiä ohjaa shell-skripti. Testin suorittamiseen Windowsissa käytämme git-bashia. Siten yksi komentosarja riittää sekä Windowsille että Linuxille. Kaikki projektin kehittäjät asentavat Gitin ja Dockerin. Kun Git asennetaan Windowsiin, git-bash asennetaan, joten kaikilla on myös se.

Skripti suorittaa seuraavat vaiheet:

  • Docker-kuvien rakentaminen
    docker-compose build
  • Tietokannan ja LocalStackin käynnistäminen
    docker-compose up -d <контейнер>
  • Tietokannan siirto ja LocalStackin valmistelu
    docker-compose run <контейнер>
  • Palvelun käynnistäminen testattavana
    docker-compose up -d <сервис>
  • Testin suorittaminen (Newman)
  • Kaikkien säiliöiden pysäyttäminen
    docker-compose down
  • Tulosten lähettäminen Slackiin
    Meillä on chat, johon menee viestit, joissa on vihreä valintamerkki tai punainen risti ja linkki lokiin.

Seuraavat Docker-kuvat liittyvät näihin vaiheisiin:

  • Testattava palvelu on sama kuva kuin tuotannossa. Testin konfigurointi tapahtuu ympäristömuuttujien kautta.
  • Postgresissa, Redisissä ja LocalStackissa käytetään Docker Hubin valmiita kuvia. Liquibaselle ja Newmanille on myös valmiita kuvia. Rakennamme omamme heidän luurankolleen ja lisäämme tiedostomme sinne.
  • LocalStackin valmistukseen käytetään valmista AWS CLI -kuvaa ja luodaan siihen perustuva komentosarja sisältävä kuva.

Käyttäminen volyymit, sinun ei tarvitse rakentaa Docker-kuvaa vain lisätäksesi tiedostoja säilöön. Volyymit eivät kuitenkaan sovellu ympäristöömme, koska itse Gitlab CI -tehtävät toimivat konteissa. Voit ohjata Dockeria tällaisesta säilöstä, mutta taltiot yhdistävät kansiot vain isäntäjärjestelmästä, eivät toisesta säilystä.

Ongelmia, joita saatat kohdata

Valmiutta odotellessa

Kun palvelua sisältävä säilö on käynnissä, se ei tarkoita, että se on valmis hyväksymään yhteyksiä. Sinun on odotettava yhteyden jatkumista.

Tämä ongelma ratkaistaan ​​joskus komentosarjan avulla odota sitä.sh, joka odottaa mahdollisuutta muodostaa TCP-yhteys. LocalStack saattaa kuitenkin antaa 502 Bad Gateway -virheen. Lisäksi se koostuu monista palveluista, ja jos yksi niistä on valmis, se ei kerro mitään muista.

päätös: LocalStack-hallintakomentosarjat, jotka odottavat 200 vastausta sekä SQS:ltä että SNS:ltä.

Rinnakkaisten tehtävien ristiriidat

Useita testejä voidaan suorittaa samanaikaisesti samalla Docker-isännällä, joten säilön ja verkon nimien on oltava yksilöllisiä. Saman palvelun eri haarojen testit voivat myös toimia samanaikaisesti, joten niiden nimen kirjoittaminen jokaiseen kirjoitustiedostoon ei riitä.

päätös: Skripti asettaa muuttujalle COMPOSE_PROJECT_NAME yksilöllisen arvon.

Windowsin ominaisuudet

Haluan tuoda esiin useita asioita, kun käytän Dockeria Windowsissa, koska nämä kokemukset ovat tärkeitä virheiden syyn ymmärtämiseksi.

  1. Säilön komentotulkkikomentosarjoissa on oltava Linux-rivinpäätteet.
    Shell CR -symboli on syntaksivirhe. Virheilmoituksesta on vaikea päätellä, että näin on. Kun muokkaat tällaisia ​​skriptejä Windowsissa, tarvitset oikean tekstieditorin. Lisäksi versionhallintajärjestelmä on konfiguroitava oikein.

Näin git konfiguroidaan:

git config core.autocrlf input

  1. Git-bash emuloi tavallisia Linux-kansioita ja korvaa absoluuttiset Linux-polut Windows-poluilla kutsuessaan exe-tiedostoa (mukaan lukien docker.exe). Tämä ei kuitenkaan ole järkevää poluille, jotka eivät ole paikallisessa koneessa (tai säilössä oleville poluille). Tätä toimintaa ei voi poistaa käytöstä.

päätös: lisää ylimääräinen kauttaviiva polun alkuun: //bin /bin sijaan. Linux ymmärtää tällaiset polut; sille useat vinoviivat ovat samat kuin yksi. Mutta git-bash ei tunnista tällaisia ​​polkuja eikä yritä muuntaa niitä.

Lokitulostus

Testejä suoritettaessa haluaisin nähdä sekä Newmanin että testattavan palvelun lokit. Koska näiden lokien tapahtumat ovat yhteydessä toisiinsa, niiden yhdistäminen yhteen konsoliin on paljon kätevämpää kuin kaksi erillistä tiedostoa. Newman käynnistyy kautta telakka-kirjoitusajo, joten sen tuloste päätyy konsoliin. Ei jää muuta kuin varmistaa, että palvelun tuotos menee myös sinne.

Alkuperäinen ratkaisu oli tehdä docker-säveltää ylös ei lippua -d, mutta käyttämällä shell-ominaisuuksia, lähetä tämä prosessi taustalle:

docker-compose up <service> &

Tämä toimi, kunnes oli tarpeen lähettää lokit Dockerista kolmannen osapuolen palveluun. docker-säveltää ylös lopetti lokien tulostamisen konsoliin. Ryhmä kuitenkin toimi telakointiasema.

päätös:

docker attach --no-stdin ${COMPOSE_PROJECT_NAME}_<сервис>_1 &

Tunnisteiden ristiriita testiiteraatioiden aikana

Testit suoritetaan useissa iteraatioissa. Tietokantaa ei tyhjennetä. Tietokannan tietueilla on yksilölliset tunnukset. Jos kirjoitamme tiettyjä tunnuksia pyyntöihin, saamme ristiriidan toisessa iteraatiossa.

Sen välttämiseksi joko tunnusten on oltava yksilöllisiä tai kaikki testin luomat objektit on poistettava. Joitakin objekteja ei voida poistaa vaatimusten vuoksi.

päätös: luo GUID-tunnukset Postman-skriptien avulla.

var uuid = require('uuid');
var myid = uuid.v4();
pm.environment.set('myUUID', myid);

Käytä sitten symbolia kyselyssä {{myUUID}}, joka korvataan muuttujan arvolla.

Yhteistyö LocalStackin kautta

Jos testattava palvelu lukee tai kirjoittaa SQS-jonoon, niin tämän varmistamiseksi itse testin on toimittava myös tämän jonon kanssa.

päätös: pyynnöt Postmanilta LocalStackille.

AWS-palveluiden sovellusliittymä on dokumentoitu, mikä mahdollistaa kyselyjen tekemisen ilman SDK:ta.

Jos palvelu kirjoittaa jonoon, luemme sen ja tarkistamme viestin sisällön.

Jos palvelu lähettää viestejä SNS:lle, LocalStack luo valmisteluvaiheessa myös jonon ja tilaa tämän SNS-aiheen. Sitten kaikki riippuu siitä, mitä edellä on kuvattu.

Jos palvelun täytyy lukea viesti jonosta, niin edellisessä testivaiheessa kirjoitamme tämän viestin jonoon.

Testataan testattavasta mikropalvelusta peräisin olevia HTTP-pyyntöjä

Jotkut palvelut toimivat HTTP:n kautta jonkin muun kuin AWS:n kanssa, ja joitain AWS-ominaisuuksia ei ole otettu käyttöön LocalStackissa.

päätös: näissä tapauksissa se voi auttaa MockServer, jossa on valmis kuva Docker-napa. Odotetut pyynnöt ja vastaukset niihin määritetään HTTP-pyynnöllä. API on dokumentoitu, joten teemme pyyntöjä Postmanilta.

Testataan OAuth-todennusta ja valtuutusta

Käytämme OAuthia ja JSON-verkkotunnukset (JWT). Testi vaatii OAuth-palveluntarjoajan, jonka voimme suorittaa paikallisesti.

Kaikki vuorovaikutus palvelun ja OAuth-palveluntarjoajan välillä perustuu kahteen pyyntöön: ensin pyydetään määritystä /.well-known/openid-configuration, ja sitten julkista avainta (JWKS) pyydetään määrityksessä olevaan osoitteeseen. Kaikki tämä on staattista sisältöä.

päätös: OAuth-testitoimittajamme on staattinen sisältöpalvelin ja kaksi tiedostoa siinä. Tunnus luodaan kerran ja sitoutuu Gitiin.

SignalR-testauksen ominaisuudet

Postimies ei toimi websockettien kanssa. SignalR:n testaamiseen luotiin erityinen työkalu.

SignalR-asiakas voi olla muutakin kuin pelkkä selain. Sille on asiakaskirjasto .NET Coren alla. Asiakas, joka on kirjoitettu .NET Coressa, muodostaa yhteyden, todennetaan ja odottaa tiettyä viestisarjaa. Jos odottamaton viesti vastaanotetaan tai yhteys katkeaa, asiakas poistuu koodilla 1. Jos viimeinen odotettu viesti vastaanotetaan, asiakas poistuu koodilla 0.

Newman työskentelee samanaikaisesti asiakkaan kanssa. Useita asiakkaita käynnistetään tarkistamaan, että viestit toimitetaan kaikille niitä tarvitseville.

Dockerin mikropalvelujen automaattinen testaus jatkuvaa integrointia varten

Jos haluat käyttää useita asiakkaita, käytä vaihtoehtoa -- mittakaava docker-compose-komentorivillä.

Ennen suorittamista Postman-skripti odottaa, että kaikki asiakkaat muodostavat yhteydet.
Olemme jo kohdanneet yhteyden odottamisen ongelman. Mutta siellä oli palvelimia, ja tässä on asiakas. Tarvitaan erilainen lähestymistapa.

päätös: säilössä oleva asiakas käyttää mekanismia Terveystarkastusilmoittaaksesi isäntäkoneen skriptille sen tilasta. Asiakas luo tiedoston tiettyyn polkuun, esimerkiksi /healthcheck, heti, kun yhteys on muodostettu. Docker-tiedoston HealthCheck-skripti näyttää tältä:

HEALTHCHECK --interval=3s CMD if [ ! -e /healthcheck ]; then false; fi

Joukkue telakka tarkastaa Näyttää säilön normaalin tilan, terveydentilan ja poistumiskoodin.

Kun Newman on valmis, skripti tarkistaa, että kaikki asiakaskontit ovat päättyneet koodilla 0.

Onnellisuus on olemassa

Kun olimme voittaneet yllä kuvatut vaikeudet, meillä oli joukko vakaita juoksutestejä. Testeissä jokainen palvelu toimii yhtenä yksikkönä, joka on vuorovaikutuksessa tietokannan ja Amazon LocalStackin kanssa.

Nämä testit suojaavat yli 30 kehittäjän tiimiä virheiltä sovelluksessa, jossa on yli 10 mikropalvelun monimutkaista vuorovaikutusta toistuvien käyttöönottojen yhteydessä.

Lähde: will.com

Lisää kommentti