Aŭtomatigita testado de mikroservoj en Docker por kontinua integriĝo

En projektoj rilataj al la evoluo de mikroserva arkitekturo, CI/CD moviĝas de la kategorio de agrabla ŝanco al la kategorio de urĝa neceso. Aŭtomatigita testado estas integra parto de kontinua integriĝo, kompetenta aliro al kiu povas doni al la teamo multajn agrablajn vesperojn kun familio kaj amikoj. Alie, la projekto riskas neniam esti finita.

Vi povas kovri la tutan mikroservan kodon per unutestoj per imitaj objektoj, sed ĉi tio nur parte solvas la problemon kaj lasas multajn demandojn kaj malfacilaĵojn, precipe dum testado de laboro kun datumoj. Kiel ĉiam, la plej urĝaj testas datuman konsistencon en interrilata datumbazo, testas laboron kun nubaj servoj kaj faras malĝustajn supozojn dum verkado de mokaj objektoj.

Ĉio ĉi kaj iom pli povas esti solvitaj provante la tutan mikroservon en Docker-ujo. Nedubebla avantaĝo por certigi la validecon de testoj estas, ke la samaj Docker-bildoj, kiuj eniras en produktadon, estas testitaj.

Aŭtomatigo de ĉi tiu aliro prezentas kelkajn problemojn, kies solvo estos priskribita malsupre:

  • konfliktoj de paralelaj taskoj en la sama docker gastiganto;
  • identigilkonfliktoj en la datumbazo dum provaj ripetoj;
  • atendante ke mikroservoj estos pretaj;
  • kunfandi kaj eligi protokolojn al eksteraj sistemoj;
  • testado de eksiĝintaj HTTP-petoj;
  • testado de interreta ingo (uzante SignalR);
  • provante aŭtentikigon kaj rajtigon de OAuth.

Ĉi tiu artikolo baziĝas sur mia parolo ĉe SECR 2019. Do por tiuj, kiuj estas tro mallaboremaj por legi, jen registrado de la parolado.

Aŭtomatigita testado de mikroservoj en Docker por kontinua integriĝo

En ĉi tiu artikolo mi rakontos al vi kiel uzi skripton por ruli la servon sub testo, datumbazon kaj Amazon AWS-servojn en Docker, poste provoj sur Postman kaj, post kiam ili finiĝos, haltigi kaj forigi la kreitajn ujojn. Testoj estas efektivigitaj ĉiufoje kiam la kodo ŝanĝiĝas. Tiel ni certigas, ke ĉiu versio funkcias ĝuste kun la datumbazo kaj servoj de AWS.

La sama skripto estas rulata kaj de la programistoj mem sur siaj Vindozaj labortabloj kaj de la Gitlab CI-servilo sub Linukso.

Por esti pravigita, enkonduko de novaj testoj ne devus postuli la instaladon de pliaj iloj aŭ sur la komputilo de la programisto aŭ sur la servilo kie la testoj estas rulitaj sur kommit. Docker solvas ĉi tiun problemon.

La testo devas ruliĝi sur loka servilo pro la sekvaj kialoj:

  • La reto neniam estas tute fidinda. El mil petoj, oni povas malsukcesi;
    En ĉi tiu kazo, la aŭtomata testo ne funkcios, la laboro ĉesos, kaj vi devos serĉi la kialon en la protokoloj;
  • Tro oftaj petoj ne estas permesitaj de iuj triaj servoj.

Krome, estas nedezirinda uzi la standon ĉar:

  • Stando povas esti rompita ne nur per malbona kodo kuranta sur ĝi, sed ankaŭ per datumoj, kiujn la ĝusta kodo ne povas prilabori;
  • Kiom ajn ni klopodas revenigi ĉiujn ŝanĝojn faritajn de la testo dum la testo mem, io povas misfunkcii (alie, kial testi?).

Pri la projekto kaj proceza organizo

Nia firmao evoluigis mikroservan TTT-aplikaĵon funkciantan en Docker en la Amazon AWS-nubo. Unuotestoj jam estis uzitaj en la projekto, sed eraroj ofte okazis ke la unuotestoj ne detektis. Necesis testi tutan mikroservon kune kun la datumbazo kaj Amazon-servoj.

La projekto uzas norman kontinuan integrigan procezon, kiu inkluzivas testi la mikroservon kun ĉiu kompromiso. Post atribuado de tasko, la programisto faras ŝanĝojn al la mikroservo, testas ĝin permane kaj funkcias ĉiujn disponeblajn aŭtomatigitajn testojn. Se necese, la programisto ŝanĝas la testojn. Se neniuj problemoj estas trovitaj, kompromiso estas farita al la branĉo de ĉi tiu afero. Post ĉiu transdono, testoj aŭtomate ruliĝas sur la servilo. Kunfandado en komunan branĉon kaj lanĉado de aŭtomataj testoj sur ĝi okazas post sukcesa revizio. Se la testoj sur la komuna branĉo pasas, la servo aŭtomate ĝisdatiĝas en la testa medio ĉe Amazon Elastic Container Service (benko). La stando estas necesa por ĉiuj programistoj kaj testantoj, kaj ne estas konsilinde rompi ĝin. Testistoj en ĉi tiu medio kontrolas solvon aŭ novan funkcion per manaj testoj.

Projekta arkitekturo

Aŭtomatigita testado de mikroservoj en Docker por kontinua integriĝo

La aplikaĵo konsistas el pli ol dek servoj. Kelkaj el ili estas skribitaj en .NET Core kaj kelkaj en NodeJs. Ĉiu servo funkcias en Docker-ujo en la Amazon Elastic Container Service. Ĉiu havas sian propran Postgres-datumbazon, kaj kelkaj ankaŭ havas Redis. Ne ekzistas komunaj datumbazoj. Se pluraj servoj bezonas la samajn datumojn, tiam ĉi tiuj datumoj, kiam ĝi ŝanĝiĝas, estas transdonitaj al ĉiu el ĉi tiuj servoj per SNS (Simple Notification Service) kaj SQS (Amazon Simple Queue Service), kaj la servoj konservas ĝin en siaj propraj apartaj datumbazoj.

SQS kaj SNS

SQS permesas vin meti mesaĝojn en atendovico kaj legi mesaĝojn el la atendovico per la HTTPS-protokolo.

Se pluraj servoj legas unu voston, tiam ĉiu mesaĝo alvenas nur al unu el ili. Ĉi tio estas utila kiam oni rulas plurajn okazojn de la sama servo por distribui la ŝarĝon inter ili.

Se vi volas, ke ĉiu mesaĝo estu liverita al pluraj servoj, ĉiu ricevanto devas havi sian propran atendovicon, kaj SNS estas necesa por duobligi mesaĝojn en plurajn vicojn.

En SNS vi kreas temon kaj abonas ĝin, ekzemple, SQS-vico. Vi povas sendi mesaĝojn al temo. En ĉi tiu kazo, la mesaĝo estas sendita al ĉiu vosto abonita al ĉi tiu temo. SNS ne havas metodon por legi mesaĝojn. Se dum senararigado aŭ testado vi bezonas ekscii, kio estas sendita al SNS, vi povas krei SQS-vicon, aboni ĝin al la dezirata temo kaj legi la voston.

Aŭtomatigita testado de mikroservoj en Docker por kontinua integriĝo

API Enirejo

Plej multaj servoj ne estas rekte alireblaj de la Interreto. Aliro estas per API Gateway, kiu kontrolas alirrajtojn. Ĉi tio ankaŭ estas nia servo, kaj ankaŭ ekzistas testoj por ĝi.

Realtempaj sciigoj

La aplikaĵo uzas SignaloRpor montri realtempajn sciigojn al la uzanto. Ĉi tio estas efektivigita en la sciiga servo. Ĝi estas alirebla rekte de la Interreto kaj mem funkcias kun OAuth, ĉar montriĝis nepraktike konstrui subtenon por Retaj ingoj en Gateway, kompare kun integri OAuth kaj la sciigan servon.

Konata Testa Aliro

Unutestoj anstataŭigas aferojn kiel la datumbazon per imitaj objektoj. Se mikroservo, ekzemple, provas krei rekordon en tabelo kun fremda ŝlosilo, kaj la rekordo referencita de tiu ŝlosilo ne ekzistas, tiam la peto ne povas esti kompletigita. Unuaj testoj ne povas detekti ĉi tion.

В artikolo de Microsoft Estas proponite uzi en-memoran datumbazon kaj efektivigi imitajn objektojn.

En-memora datumbazo estas unu el la DBMS subtenataj de la Enta Kadro. Ĝi estis kreita specife por testado. Datenoj en tia datumbazo estas stokitaj nur ĝis la procezo uzanta ĝin finiĝas. Ĝi ne postulas krei tabelojn kaj ne kontrolas datumintegrecon.

Imititaj objektoj modeligas la klason, kiun ili anstataŭigas, nur laŭ la mezuro, ke la testprogramisto komprenas kiel ĝi funkcias.

Kiel igi Postgres aŭtomate komenci kaj plenumi migradojn kiam vi kuras teston, ne estas specifita en la Mikrosofta artikolo. Mia solvo faras tion kaj, krome, ne aldonas kodon specife por testoj al la mikroservo mem.

Ni transiru al la solvo

Dum la disvolva procezo evidentiĝis, ke unuopaj provoj ne sufiĉas por trovi ĉiujn problemojn ĝustatempe, do oni decidis trakti ĉi tiun aferon de malsama angulo.

Agordi testan medion

La unua tasko estas deploji testan medion. Paŝoj necesaj por funkciigi mikroservon:

  • Agordu la servon sub testo por la loka medio, specifu la detalojn por konekti al la datumbazo kaj AWS en la mediaj variabloj;
  • Komencu Postgres kaj faru la migradon rulante Liquibase.
    En interrilataj DBMS-oj, antaŭ ol skribi datumojn en la datumbazon, vi devas krei datumskemon, alivorte, tabelojn. Ĝisdatigante aplikaĵon, tabeloj devas esti alportitaj al la formo uzata de la nova versio, kaj, prefere, sen perdi datumojn. Ĉi tio nomiĝas migrado. Krei tabelojn en komence malplena datumbazo estas speciala kazo de migrado. Migrado povas esti konstruita en la aplikaĵon mem. Kaj .NET kaj NodeJS havas migradkadrojn. En nia kazo, pro sekurecaj kialoj, mikroservoj estas senigitaj de la rajto ŝanĝi la datuman skemon, kaj la migrado estas farita per Liquibase.
  • Lanĉu Amazon LocalStack. Ĉi tio estas efektivigo de AWS-servoj por funkcii hejme. Estas preta bildo por LocalStack sur Docker Hub.
  • Rulu la skripton por krei la necesajn entojn en LocalStack. Ŝelaj skriptoj uzas la AWS CLI.

Uzita por testado pri la projekto Poŝtisto. Ĝi ekzistis antaŭe, sed ĝi estis lanĉita permane kaj testita aplikaĵo jam deplojita ĉe la stando. Ĉi tiu ilo permesas vin fari arbitrajn HTTP(S) petojn kaj kontroli ĉu la respondoj kongruas kun atendoj. Demandoj estas kombinitaj en kolekton, kaj la tuta kolekto povas esti rulita.

Aŭtomatigita testado de mikroservoj en Docker por kontinua integriĝo

Kiel funkcias la aŭtomata testo?

Dum la testo, ĉio funkcias en Docker: la servo sub testo, Postgres, la migra ilo, kaj Postman, aŭ pli ĝuste ĝia konzola versio - Newman.

Docker solvas kelkajn problemojn:

  • Sendependeco de gastiga agordo;
  • Instalado de dependecoj: Docker elŝutas bildojn de Docker Hub;
  • Revenigi la sistemon al ĝia originala stato: simple forigi la ujojn.

Docker-komponi kunigas ujojn en virtualan reton, izolita de la Interreto, en kiu ujoj trovas unu la alian per domajnaj nomoj.

La testo estas kontrolita per ŝela skripto. Por ruli la teston en Vindozo ni uzas git-bash. Tiel, unu skripto sufiĉas kaj por Vindozo kaj Linukso. Git kaj Docker estas instalitaj de ĉiuj programistoj en la projekto. Kiam oni instalas Git sur Vindozo, git-bash estas instalita, do ankaŭ ĉiuj havas tion.

La skripto plenumas la sekvajn paŝojn:

  • Konstruado de docker bildoj
    docker-compose build
  • Lanĉante la datumbazon kaj LocalStack
    docker-compose up -d <контейнер>
  • Datumbaza migrado kaj preparado de LocalStack
    docker-compose run <контейнер>
  • Lanĉante la servon sub testo
    docker-compose up -d <сервис>
  • Kurante la teston (Newman)
  • Ĉesigante ĉiujn ujojn
    docker-compose down
  • Afiŝado de rezultoj en Slack
    Ni havas babilejon kie mesaĝoj kun verda marko aŭ ruĝa kruco kaj ligilo al la protokolo iras.

La sekvaj Docker-bildoj estas implikitaj en ĉi tiuj paŝoj:

  • La servo testata estas la sama bildo kiel por produktado. La agordo por la testo estas tra mediovariabloj.
  • Por Postgres, Redis kaj LocalStack oni uzas pretajn bildojn de Docker Hub. Estas ankaŭ pretaj bildoj por Liquibase kaj Newman. Ni konstruas la nian sur ilia skeleto, aldonante niajn dosierojn tie.
  • Por prepari LocalStack, vi uzas pretan AWS CLI-bildon kaj kreas bildon enhavantan skripton bazitan sur ĝi.

Uzante volumoj, vi ne devas konstrui Docker-bildon nur por aldoni dosierojn al la ujo. Tamen, volumoj ne taŭgas por nia medio ĉar Gitlab CI-taskoj mem funkcias en ujoj. Vi povas kontroli Docker de tia ujo, sed volumoj nur muntas dosierujojn de la gastiga sistemo, kaj ne de alia ujo.

Problemoj, kiujn vi povas renkonti

Atendante pretecon

Kiam ujo kun servo funkcias, tio ne signifas, ke ĝi estas preta akcepti konektojn. Vi devas atendi la konekton daŭri.

Ĉi tiu problemo foje estas solvita per skripto atendu-por-ĝi.sh, kiu atendas okazon por establi TCP-konekton. Tamen, LocalStack povas ĵeti eraron 502 Bad Gateway. Krome, ĝi konsistas el multaj servoj, kaj se unu el ili estas preta, ĉi tio nenion diras pri la aliaj.

decido: LocalStack provizantaj skriptoj kiuj atendas 200 respondon de kaj SQS kaj SNS.

Paralelaj Taskaj Konfliktoj

Multoblaj testoj povas ruliĝi samtempe sur la sama Docker-gastiganto, do ujo- kaj retnomoj devas esti unikaj. Krome, testoj de malsamaj branĉoj de la sama servo ankaŭ povas ruliĝi samtempe, do ne sufiĉas skribi iliajn nomojn en ĉiu kompona dosiero.

decido: La skripto metas la variablon COMPOSE_PROJECT_NAME al unika valoro.

Vindozaj Trajtoj

Estas kelkaj aferoj, kiujn mi volas atentigi kiam vi uzas Docker en Vindozo, ĉar ĉi tiuj spertoj estas gravaj por kompreni kial okazas eraroj.

  1. Ŝelaj skriptoj en ujo devas havi Linuksajn liniofinojn.
    La ŝela CR-simbolo estas sintaksa eraro. Estas malfacile diri el la erarmesaĝo, ke tio estas la kazo. Kiam vi redaktas tiajn skriptojn en Vindozo, vi bezonas taŭgan tekstredaktilon. Krome, la versio-kontrolsistemo devas esti agordita ĝuste.

Jen kiel git estas agordita:

git config core.autocrlf input

  1. Git-bash kopias normajn Linuksajn dosierujojn kaj, kiam oni vokas exe-dosieron (inkluzive de docker.exe), anstataŭigas absolutajn Linuksajn vojojn per Vindozaj vojoj. Tamen tio ne havas sencon por vojoj ne sur la loka maŝino (aŭ vojoj en ujo). Ĉi tiu konduto ne povas esti malŝaltita.

decido: aldonu plian oblikvon al la komenco de la vojo: //bin anstataŭ /bin. Linukso komprenas tiajn vojojn; por ĝi, pluraj oblikvoj estas la sama kiel unu. Sed git-bash ne rekonas tiajn vojojn kaj ne provas konverti ilin.

Ensalutu eligo

Dum rulado de testoj, mi ŝatus vidi protokolojn de kaj Newman kaj la servo testata. Ĉar la eventoj de ĉi tiuj protokoloj estas interligitaj, kombini ilin en unu konzolo estas multe pli oportuna ol du apartaj dosieroj. Newman lanĉas tra docker-compose run, kaj do ĝia eligo finiĝas en la konzolo. Restas nur certigi, ke la eligo de la servo ankaŭ iras tien.

La originala solvo estis fari docker-compose up neniu flago -d, sed uzante la ŝelajn kapablojn, sendu ĉi tiun procezon al la fono:

docker-compose up <service> &

Ĉi tio funkciis ĝis estis necese sendi protokolojn de Docker al triaparta servo. docker-compose up ĉesis eligi protokolojn al la konzolo. Tamen, la teamo laboris docker kunsendas.

decido:

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

Identigilkonflikto dum testaj ripetoj

Testoj estas rulitaj en pluraj ripetoj. La datumbazo ne estas forigita. Rekordoj en la datumbazo havas unikajn identigilojn. Se ni notas specifajn identigilojn en petoj, ni ricevos konflikton ĉe la dua ripeto.

Por eviti ĝin, aŭ la identigiloj devas esti unikaj, aŭ ĉiuj objektoj kreitaj de la testo devas esti forigitaj. Iuj objektoj ne povas esti forigitaj pro postuloj.

decido: generi GUID-ojn per Postman-skriptoj.

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

Poste uzu la simbolon en la demando {{myUUID}}, kiu estos anstataŭigita per la valoro de la variablo.

Kunlaboro per LocalStack

Se la servo testata legas aŭ skribas al SQS-vico, tiam por kontroli tion, la testo mem ankaŭ devas funkcii kun ĉi tiu vosto.

decido: petoj de Poŝtisto al LocalStack.

La AWS-servo API estas dokumentita, permesante demandojn esti faritaj sen SDK.

Se servo skribas al vosto, tiam ni legas ĝin kaj kontrolas la enhavon de la mesaĝo.

Se la servo sendas mesaĝojn al SNS, en la prepara stadio LocalStack ankaŭ kreas atendovicon kaj abonas ĉi tiun SNS-temon. Tiam ĉio venas al tio, kio estis priskribita supre.

Se la servo bezonas legi mesaĝon el la atendovico, tiam en la antaŭa prova paŝo ni skribas ĉi tiun mesaĝon al la atendovico.

Testado de HTTP-petoj devenantaj de la mikroservo sub testo

Iuj servoj funkcias per HTTP kun io alia ol AWS, kaj iuj AWS-funkcioj ne estas efektivigitaj en LocalStack.

decido: en ĉi tiuj kazoj ĝi povas helpi MockServer, kiu havas pretan bildon en Docker-nabo. Atenditaj petoj kaj respondoj al ili estas agorditaj per HTTP-peto. La API estas dokumentita, do ni faras petojn de Postman.

Testado de Aŭtentikigo kaj Rajtigo de OAuth

Ni uzas OAuth kaj JSON-Retaj Tokenoj (JWT). La testo postulas OAuth-provizanton, kiun ni povas funkcii loke.

Ĉiu interago inter la servo kaj la provizanto de OAuth estas du petoj: unue, la agordo estas petita. /.konata/openid-agordo, kaj tiam la publika ŝlosilo (JWKS) estas petita ĉe la adreso de la agordo. Ĉio ĉi estas senmova enhavo.

decido: Nia prova OAuth-provizanto estas senmova enhavservilo kaj du dosieroj sur ĝi. La ĵetono estas generita unufoje kaj farita al Git.

Trajtoj de SignalR-testado

Leterportisto ne funkcias kun retejsokoj. Speciala ilo estis kreita por testi SignalR.

SignalR-kliento povas esti pli ol nur retumilo. Estas klienta biblioteko por ĝi sub .NET Core. La kliento, skribita en .NET Core, establas konekton, estas aŭtentikigita kaj atendas specifan sinsekvon de mesaĝoj. Se neatendita mesaĝo estas ricevita aŭ la konekto estas perdita, la kliento eliras kun kodo de 1. Se la lasta atendata mesaĝo estas ricevita, la kliento eliras kun kodo de 0.

Newman laboras samtempe kun la kliento. Pluraj klientoj estas lanĉitaj por kontroli, ke mesaĝoj estas liveritaj al ĉiuj, kiuj bezonas ilin.

Aŭtomatigita testado de mikroservoj en Docker por kontinua integriĝo

Por funkciigi plurajn klientojn uzu la opcion --skalo sur la docker-compose komandlinio.

Antaŭ ol funkcii, la Postman-skripto atendas ke ĉiuj klientoj establos ligojn.
Ni jam renkontis la problemon atendi konekton. Sed estis serviloj, kaj jen la kliento. Necesas malsama aliro.

decido: la kliento en la ujo uzas la mekanismon Sankontrolopor informi la skripton de la gastiganto pri ĝia stato. La kliento kreas dosieron ĉe specifa vojo, diru /healthcheck, tuj kiam la konekto estas establita. La HealthCheck-skripto en la docker-dosiero aspektas jene:

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

teamo docker inspekti Montras la normalan staton, sanan staton kaj elirkodon por la ujo.

Post kiam Newman finiĝas, la skripto kontrolas, ke ĉiuj ujoj kun la kliento finiĝis, kun kodo 0.

Feliĉo ekzistas

Post kiam ni venkis la malfacilaĵojn priskribitajn supre, ni havis aron da stabilaj kurantaj testoj. En testoj, ĉiu servo funkcias kiel unuopa unuo, interagante kun la datumbazo kaj Amazon LocalStack.

Ĉi tiuj provoj protektas teamon de pli ol 30 programistoj kontraŭ eraroj en aplikaĵo kun kompleksa interago de pli ol 10 mikroservoj kun oftaj deplojoj.

fonto: www.habr.com

Aldoni komenton