Mikroteenuste automaatne testimine Dockeris pidevaks integreerimiseks

Mikroteenuste arhitektuuri arendamisega seotud projektides liigub CI/CD meeldiva võimaluse kategooriast kiireloomulise vajaduse kategooriasse. Automaattestimine on pideva integratsiooni lahutamatu osa, mille pädev lähenemine võib anda meeskonnale palju meeldivaid õhtuid pere ja sõpradega. Vastasel juhul on oht, et projekt ei jõua kunagi lõpule.

Pildiobjektidega ühiktestidega on võimalik katta kogu mikroteenuse kood, kuid see lahendab probleemi vaid osaliselt ning jätab palju küsimusi ja raskusi, eriti andmetega töö testimisel. Nagu ikka, on kõige pakilisemad relatsiooniandmebaasis andmete järjepidevuse testimine, pilveteenustega töö testimine ja valede eelduste tegemine näidisobjektide kirjutamisel.

Seda kõike ja natuke muudki saab lahendada kogu mikroteenust Dockeri konteineris testides. Vaieldamatu eelis testide kehtivuse tagamisel on see, et testitakse samu Dockeri pilte, mis lähevad tootmisse.

Selle lähenemisviisi automatiseerimine toob kaasa mitmeid probleeme, mille lahendust kirjeldatakse allpool:

  • paralleelsete ülesannete konfliktid samas dokkimismasinas;
  • identifikaatorite konfliktid andmebaasis testiteratsioonide ajal;
  • mikroteenuste valmimise ootamine;
  • logide ühendamine ja väljastamine välistesse süsteemidesse;
  • väljuvate HTTP päringute testimine;
  • veebipesa testimine (kasutades SignalR);
  • OAuthi autentimise ja autoriseerimise testimine.

See artikkel põhineb minu kõne SECR 2019. Neile, kes on lugemiseks liiga laisad, siin on kõne salvestis.

Mikroteenuste automaatne testimine Dockeris pidevaks integreerimiseks

Selles artiklis räägin teile, kuidas kasutada skripti testitava teenuse, andmebaasi ja Amazon AWS-i teenuste käivitamiseks Dockeris, seejärel Postmani testid ja pärast nende lõpetamist loodud konteinerid peatada ja kustutada. Testid teostatakse iga kord, kui kood muutub. Nii tagame, et iga versioon töötab õigesti AWS-i andmebaasi ja teenustega.

Sama skripti käitavad nii arendajad ise oma Windowsi töölaudadel kui ka Gitlab CI server Linuxi all.

Põhjendatuna ei tohiks uute testide juurutamine nõuda täiendavate tööriistade installimist ei arendaja arvutisse ega serverisse, kus testid läbi viivad commit.Docker lahendab selle probleemi.

Test peab käima kohalikus serveris järgmistel põhjustel.

  • Võrk pole kunagi täiesti usaldusväärne. Tuhandest taotlusest võib üks ebaõnnestuda;
    Sel juhul automaattest ei tööta, töö peatub ja põhjust tuleb logidest otsida;
  • Mõned kolmanda osapoole teenused ei luba liiga sagedasi päringuid.

Lisaks on aluse kasutamine ebasoovitav, kuna:

  • Stendi võib lõhkuda mitte ainult sellel töötav halb kood, vaid ka andmed, mida õige kood ei suuda töödelda;
  • Ükskõik kui palju me proovime testi käigus tehtud muudatusi tagasi saata, võib midagi valesti minna (muidu miks testida?).

Projekti ja protsessi korraldusest

Meie ettevõte arendas Amazon AWS-i pilves Dockeris töötava mikroteenuse veebirakenduse. Projektis kasutati juba ühikuteste, kuid sageli esines vigu, mida ühiktestid ei tuvastanud. Testida oli vaja tervet mikroteenust koos andmebaasi ja Amazoni teenustega.

Projekt kasutab standardset pidevat integreerimisprotsessi, mis hõlmab mikroteenuse testimist iga kohustusega. Pärast ülesande määramist teeb arendaja mikroteenuses muudatused, testib seda käsitsi ja käivitab kõik saadaolevad automatiseeritud testid. Vajadusel muudab arendaja teste. Kui probleeme ei leita, pühendutakse selle probleemi harule. Pärast iga kinnitamist käivitatakse testid serveris automaatselt. Ühiseks haruks ühinemine ja sellel automaatsete testide käivitamine toimub pärast edukat ülevaatamist. Kui testid jagatud harus läbivad, värskendatakse teenust automaatselt Amazon Elastic Container Service'i (pingi) testkeskkonnas. Stend on vajalik kõikidele arendajatele ja testijatele ning seda ei ole soovitav lõhkuda. Selle keskkonna testijad kontrollivad parandust või uut funktsiooni käsitsi testide abil.

Projekti arhitektuur

Mikroteenuste automaatne testimine Dockeris pidevaks integreerimiseks

Rakendus koosneb enam kui kümnest teenusest. Mõned neist on kirjutatud .NET Core'is ja mõned NodeJs. Iga teenus töötab Amazon Elastic Container Service Dockeri konteineris. Igal neist on oma Postgresi andmebaas ja mõnel on ka Redis. Ühised andmebaasid puuduvad. Kui mitu teenust vajavad samu andmeid, edastatakse need andmed nende muutumisel SNS-i (Simple Notification Service) ja SQS-i (Amazon Simple Queue Service) kaudu kõikidesse nendesse teenustesse ning teenused salvestavad need oma eraldi andmebaasidesse.

SQS ja SNS

SQS võimaldab teil HTTPS-protokolli kasutades sõnumeid järjekorda panna ja järjekorrast sõnumeid lugeda.

Kui mitu teenust loeb ühte järjekorda, siis saabub iga teade ainult ühte neist. See on kasulik, kui käitate sama teenuse mitut eksemplari, et jagada nende vahel koormust.

Kui soovite, et iga sõnum edastataks mitmele teenusele, peab igal adressaadil olema oma järjekord ja SNS-i on vaja sõnumite paljundamiseks mitmesse järjekorda.

SNS-is loote teema ja tellite selle, näiteks SQS-i järjekorra. Teemale saab saata sõnumeid. Sel juhul saadetakse teade igasse selle teemaga liitunud järjekorda. SNS-il pole sõnumite lugemise meetodit. Kui teil on vaja silumise või testimise ajal teada saada, mis SNS-ile saadetakse, saate luua SQS-i järjekorra, tellida selle soovitud teemaga ja lugeda järjekorda.

Mikroteenuste automaatne testimine Dockeris pidevaks integreerimiseks

API lüüs

Enamikule teenustest pole Internetist otse juurdepääs. Juurdepääs toimub API Gateway kaudu, mis kontrollib juurdepääsuõigusi. See on ka meie teenus ja selle jaoks on ka testid.

Reaalajas teatised

Rakendus kasutab SignaalRkasutajale reaalajas märguannete kuvamiseks. Seda rakendatakse teavitusteenuses. See on ligipääsetav otse Internetist ja ise töötab OAuthiga, kuna veebipesade toe ehitamine Gatewaysse osutus OAuthi ja teavitusteenuse integreerimisega võrreldes ebapraktiliseks.

Hästi tuntud testimisviis

Ühiktestid asendavad sellised asjad nagu andmebaas näidisobjektidega. Kui näiteks mikroteenus üritab võõrvõtmega tabelisse kirjet luua ja selle võtmega viidatud kirjet pole olemas, ei saa päringut lõpule viia. Ühiktestid ei suuda seda tuvastada.

В artikkel Microsoftilt Tehakse ettepanek kasutada mälusisest andmebaasi ja realiseerida näidisobjekte.

Mälusisene andmebaas on üks DBMS-idest, mida Entity Framework toetab. See loodi spetsiaalselt testimiseks. Sellises andmebaasis olevaid andmeid säilitatakse ainult seni, kuni neid kasutav protsess lõpeb. See ei nõua tabelite loomist ega kontrolli andmete terviklikkust.

Näidisobjektid modelleerivad klassi, mida nad asendavad, ainult niivõrd, kuivõrd testi arendaja mõistab selle toimimist.

Microsofti artiklis pole täpsustatud, kuidas panna Postgres testi käivitamisel migratsiooni automaatselt käivitama ja teostama. Minu lahendus teeb seda ja lisaks ei lisa mikroteenusele endale spetsiaalselt testide jaoks mõeldud koodi.

Liigume edasi lahenduse juurde

Arendusprotsessi käigus selgus, et kõigi probleemide õigeaegseks leidmiseks ei piisa ühikutestidest, mistõttu otsustati sellele küsimusele läheneda teise nurga alt.

Testikeskkonna seadistamine

Esimene ülesanne on juurutada testkeskkond. Mikroteenuse käitamiseks vajalikud sammud:

  • Seadistage testitav teenus kohaliku keskkonna jaoks, määrake keskkonnamuutujates andmebaasi ja AWS-iga ühenduse loomise üksikasjad;
  • Käivitage Postgres ja viige üleviimine läbi, käivitades Liquibase.
    Relatsioonilistes DBMS-ides tuleb enne andmete andmebaasi kirjutamist luua andmeskeem ehk teisisõnu tabelid. Rakenduse uuendamisel tuleb tabelid viia uues versioonis kasutatavale vormile ja soovitavalt ilma andmeid kaotamata. Seda nimetatakse migratsiooniks. Tabelite loomine algselt tühjas andmebaasis on migratsiooni erijuhtum. Migratsiooni saab sisse ehitada rakenduse enda sisse. Nii .NET-il kui ka NodeJS-il on migratsiooniraamistikud. Meie puhul võetakse mikroteenustelt turvakaalutlustel andmeskeemi muutmise õigus ning migreerimine toimub Liquibase’i abil.
  • Käivitage Amazon LocalStack. See on AWS-i teenuste rakendamine kodus kasutamiseks. Docker Hubis on LocalStacki jaoks valmis pilt.
  • Käivitage skript, et luua LocalStackis vajalikud olemid. Shelliskriptid kasutavad AWS-i CLI-d.

Kasutatakse projekti testimiseks Kirjakandja. See oli varem olemas, kuid see käivitati käsitsi ja testiti stendil juba juurutatud rakendust. See tööriist võimaldab teil teha suvalisi HTTP(S) päringuid ja kontrollida, kas vastused vastavad ootustele. Päringud ühendatakse koguks ja kogu kogu saab käitada.

Mikroteenuste automaatne testimine Dockeris pidevaks integreerimiseks

Kuidas automaatne test töötab?

Testi ajal töötab Dockeris kõik: testitav teenus, Postgres, migratsioonitööriist ja Postman, õigemini selle konsooliversioon - Newman.

Docker lahendab mitmeid probleeme:

  • Sõltumatus hosti konfiguratsioonist;
  • Sõltuvuste installimine: Docker laadib pildid alla Docker Hubist;
  • Süsteemi taastamine algsesse olekusse: lihtsalt konteinerite eemaldamine.

dokkija-komponeeri ühendab konteinerid Internetist eraldatud virtuaalseks võrguks, milles konteinerid leiavad üksteist domeeninimede järgi.

Testi juhib shelliskript. Testi käitamiseks Windowsis kasutame git-bashi. Seega piisab ühest skriptist nii Windowsi kui Linuxi jaoks. Giti ja Dockeri installivad kõik projekti arendajad. Giti installimisel Windowsi installitakse git-bash, seega on see ka kõigil.

Skript teostab järgmised sammud:

  • Dockeri piltide ehitamine
    docker-compose build
  • Andmebaasi ja LocalStacki käivitamine
    docker-compose up -d <контейнер>
  • Andmebaasi migratsioon ja LocalStacki ettevalmistamine
    docker-compose run <контейнер>
  • Testitava teenuse käivitamine
    docker-compose up -d <сервис>
  • Testi läbiviimine (Newman)
  • Kõigi konteinerite peatamine
    docker-compose down
  • Tulemuste postitamine Slackis
    Meil on vestlus, kuhu lähevad rohelise linnukese või punase ristiga kirjad ja logi link.

Nendes etappides on kaasatud järgmised Dockeri pildid:

  • Testitav teenus on sama pilt, mis tootmisel. Testi konfigureerimine toimub keskkonnamuutujate kaudu.
  • Postgresi, Redise ja LocalStacki puhul kasutatakse Docker Hubi valmiskujutisi. Liquibase'i ja Newmani jaoks on ka valmiskujutised. Me ehitame oma oma nende skeletile, lisades sinna oma failid.
  • LocalStacki ettevalmistamiseks kasutate valmis AWS CLI pilti ja loote selle põhjal skripti sisaldava pildi.

Kasutamine mahud, ei pea te Dockeri pilti looma pelgalt failide konteinerisse lisamiseks. Mahud aga meie keskkonda ei sobi, sest Gitlab CI ülesanded ise jooksevad konteinerites. Saate Dockerit juhtida sellisest konteinerist, kuid köited ühendavad kaustu ainult hostsüsteemist, mitte teisest konteinerist.

Probleemid, mis võivad tekkida

Ootab valmisolekut

Kui teenusega konteiner töötab, ei tähenda see, et see on ühenduste vastuvõtmiseks valmis. Peate ootama, kuni ühendus jätkub.

Mõnikord lahendatakse see probleem skripti abil oodake.sh, mis ootab võimalust TCP-ühenduse loomiseks. Siiski võib LocalStack anda vea 502 Bad Gateway. Lisaks koosneb see paljudest teenustest ja kui üks neist on valmis, ei ütle see teiste kohta midagi.

otsus: LocalStacki ettevalmistusskriptid, mis ootavad 200 vastust nii SQS-ilt kui ka SNS-ilt.

Paralleelsete ülesannete konfliktid

Samas Dockeri hostis saab samaaegselt käitada mitu testi, seega peavad konteineri ja võrgu nimed olema kordumatud. Veelgi enam, sama teenuse erinevatest harudest pärit testid võivad käia ka samaaegselt, seega ei piisa nende nimede kirjutamisest igasse koostamisfaili.

otsus: skript määrab muutujale COMPOSE_PROJECT_NAME kordumatu väärtuse.

Windowsi funktsioonid

Dockeri kasutamisel Windowsis tahan tähelepanu juhtida mitmele asjale, kuna need kogemused on vigade ilmnemise mõistmiseks olulised.

  1. Konteineris olevatel shelliskriptidel peavad olema Linuxi realõpud.
    Shelli CR-sümbol on süntaksiviga. Veateate järgi on raske öelda, et see nii on. Selliste skriptide redigeerimisel Windowsis on vaja korralikku tekstiredaktorit. Lisaks peab versioonikontrollisüsteem olema korralikult konfigureeritud.

Git on konfigureeritud järgmiselt:

git config core.autocrlf input

  1. Git-bash emuleerib standardseid Linuxi kaustu ja exe-faili (sh docker.exe) kutsumisel asendab absoluutsed Linuxi teed Windowsi teedega. See ei ole aga mõistlik teede puhul, mis pole kohalikus masinas (või konteineris olevad teed). Seda käitumist ei saa keelata.

otsus: lisage tee algusesse täiendav kaldkriips: //bin asemel /bin. Linux mõistab selliseid teid, selle jaoks on mitu kaldkriipsu sama, mis üks. Kuid git-bash ei tunne selliseid teid ära ega püüa neid teisendada.

Logi väljund

Testide käitamisel sooviksin näha nii Newmani kui ka testitava teenuse logisid. Kuna nende logide sündmused on omavahel seotud, on nende ühendamine ühes konsoolis palju mugavam kui kaks eraldi faili. Newman käivitub kaudu dokkija-koostamise jooksja nii jõuab selle väljund konsooli. Jääb üle vaid veenduda, et ka teenuse väljund sinna läheks.

Algne lahendus oli teha docker - koostama üles lippu pole -d, kuid kasutades kesta võimalusi, saatke see protsess taustale:

docker-compose up <service> &

See toimis seni, kuni oli vaja Dockerist logid saata kolmanda osapoole teenusele. docker - koostama üles lõpetas logide väljastamise konsooli. Meeskond töötas siiski kinnita dokk.

otsus:

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

Identifikaatori konflikt testiteratsioonide ajal

Teste tehakse mitmes iteratsioonis. Andmebaasi ei tühjendata. Andmebaasi kirjetel on kordumatud ID-d. Kui kirjutame päringutesse üles konkreetsed ID-d, tekib teisel iteratsioonil konflikt.

Selle vältimiseks peavad ID-d olema kordumatud või kõik testiga loodud objektid tuleb kustutada. Mõnda objekti ei saa nõuete tõttu kustutada.

otsus: genereerige GUID-id, kasutades Postmani skripte.

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

Seejärel kasutage päringus sümbolit {{myUUID}}, mis asendatakse muutuja väärtusega.

Koostöö LocalStacki kaudu

Kui testitav teenus loeb või kirjutab SQS-i järjekorda, siis selle kontrollimiseks peab ka test ise selle järjekorraga töötama.

otsus: taotlused Postmanilt LocalStackile.

AWS-i teenuste API on dokumenteeritud, mis võimaldab päringuid teha ilma SDK-ta.

Kui teenus kirjutab järjekorda, siis loeme selle läbi ja kontrollime kirja sisu.

Kui teenus saadab SNS-ile sõnumeid, loob LocalStack ettevalmistusetapis ka järjekorra ja tellib selle SNS-i teema. Siis taandub kõik ülalkirjeldatule.

Kui teenus peab järjekorrast kirja lugema, siis eelmises testietapis kirjutame selle teate järjekorda.

Testitavast mikroteenusest pärit HTTP-päringute testimine

Mõned teenused töötavad HTTP kaudu millegi muuga peale AWS-i ja mõned AWS-i funktsioonid pole LocalStackis rakendatud.

otsus: sellistel juhtudel võib see aidata MockServer, millel on valmis pilt sees Dockeri jaotur. Oodatavad päringud ja vastused neile on konfigureeritud HTTP-päringu abil. API on dokumenteeritud, seega teeme taotlusi Postimehelt.

OAuthi autentimise ja autoriseerimise testimine

Kasutame OAuthi ja JSON-i veebimärgid (JWT). Test nõuab OAuthi pakkujat, mida saame kohapeal käitada.

Kogu suhtlus teenuse ja OAuthi pakkuja vahel taandub kahele päringule: esiteks küsitakse konfiguratsiooni /.well-known/openid-configuration, ja seejärel küsitakse konfiguratsioonis olevale aadressile avalikku võtit (JWKS). Kõik see on staatiline sisu.

otsus: meie test OAuthi pakkuja on staatiline sisuserver ja sellel kaks faili. Token genereeritakse üks kord ja antakse Gitile.

SignalR testimise omadused

Postimees ei tööta veebipesadega. SignalR testimiseks loodi spetsiaalne tööriist.

SignalR-i klient võib olla midagi enamat kui lihtsalt brauser. Selle jaoks on .NET Core'i all klienditeek. NET Core'is kirjutatud klient loob ühenduse, autentitakse ja ootab kindlat sõnumijada. Kui saabub ootamatu teade või ühendus katkeb, väljub klient koodiga 1. Kui saabub viimane oodatud sõnum, väljub klient koodiga 0.

Newman töötab samaaegselt kliendiga. Käivitatakse mitu klienti, et kontrollida sõnumite edastamist kõigile, kes neid vajavad.

Mikroteenuste automaatne testimine Dockeris pidevaks integreerimiseks

Mitme kliendi käitamiseks kasutage valikut --kaal käsureal docker-compose.

Enne käivitamist ootab Postmani skript, kuni kõik kliendid ühenduse loovad.
Oleme juba kokku puutunud ühenduse ootamise probleemiga. Kuid seal olid serverid ja siin on klient. Vaja on teistsugust lähenemist.

otsus: konteineris olev klient kasutab mehhanismi Tervise kontrollet teavitada hosti skripti selle olekust. Klient loob faili kindlal teel, näiteks /healthcheck, kohe pärast ühenduse loomist. Dockeri faili HealthChecki skript näeb välja selline:

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

Meeskond dokk kontrollib Näitab konteineri tavalist olekut, tervislikku seisundit ja väljumiskoodi.

Kui Newman on lõpetanud, kontrollib skript koodiga 0, et kõik kliendiga konteinerid on lõpetatud.

Õnn on olemas

Pärast ülalkirjeldatud raskuste ületamist ootas meid ees komplekt stabiilseid jooksuteste. Testides töötab iga teenus ühe üksusena, suheldes andmebaasi ja Amazon LocalStackiga.

Need testid kaitsevad 30+ arendajast koosnevat meeskonda vigade eest rakenduses, mis sisaldab 10+ mikroteenust koos sagedase juurutamisega.

Allikas: www.habr.com

Lisa kommentaar