Mikroszolgáltatások automatikus tesztelése a Dockerben a folyamatos integráció érdekében

A mikroszolgáltatási architektúra fejlesztésével kapcsolatos projektekben a CI/CD a kellemes lehetőség kategóriájából a sürgős szükség kategóriájába kerül. Az automatizált tesztelés a folyamatos integráció szerves része, amelynek hozzáértő megközelítése sok kellemes estét biztosít a csapatnak a családdal és a barátokkal. Ellenkező esetben fennáll annak a veszélye, hogy a projekt soha nem fejeződik be.

Lehetőség van a teljes mikroszolgáltatási kód lefedésére álobjektumokkal végzett egységtesztekkel, de ez csak részben oldja meg a problémát, és sok kérdést és nehézséget hagy maga után, különösen az adatokkal végzett munka tesztelésekor. Mint mindig, a legsürgetőbbek az adatok konzisztenciájának tesztelése egy relációs adatbázisban, a felhőszolgáltatásokkal végzett munka tesztelése, valamint a hibás feltételezések álobjektumok írásakor.

Mindezt és még egy kicsit meg lehet oldani, ha a teljes mikroszolgáltatást egy Docker konténerben teszteljük. A tesztek érvényességének biztosításának kétségtelen előnye, hogy ugyanazokat a Docker-képeket tesztelik, amelyek gyártásba kerülnek.

Ennek a megközelítésnek az automatizálása számos problémát vet fel, amelyek megoldását az alábbiakban ismertetjük:

  • párhuzamos feladatok ütközései ugyanazon docker gazdagépen;
  • azonosító ütközések az adatbázisban a tesztiterációk során;
  • várja a mikroszolgáltatások elkészültét;
  • naplók egyesítése és kiadása külső rendszerekbe;
  • kimenő HTTP kérések tesztelése;
  • web socket tesztelés (SignalR használatával);
  • az OAuth hitelesítés és engedélyezés tesztelése.

Ez a cikk a a beszédem a SECR 2019-ben. Tehát azoknak, akik lusták olvasni, itt egy felvétel a beszédről.

Mikroszolgáltatások automatikus tesztelése a Dockerben a folyamatos integráció érdekében

Ebben a cikkben elmondom, hogyan lehet parancsfájlt használni a tesztelés alatt álló szolgáltatás, az adatbázis és az Amazon AWS-szolgáltatások Dockerben való futtatásához, majd a Postman-tesztek elvégzéséhez, és ezek befejezése után leállíthatja és törölheti a létrehozott tárolókat. A tesztek végrehajtása minden alkalommal, amikor a kód megváltozik. Így biztosítjuk, hogy minden verzió megfelelően működjön az AWS adatbázissal és szolgáltatásokkal.

Ugyanezt a szkriptet maguk a fejlesztők futtatják a Windows asztali számítógépükön és a Gitlab CI szerver Linux alatt.

Indokolt, hogy új tesztek bevezetése nem igényel további eszközök telepítését sem a fejlesztő számítógépén, sem azon a szerveren, ahol a tesztek véglegesítéssel futnak, a Docker megoldja ezt a problémát.

A tesztnek helyi szerveren kell futnia a következő okok miatt:

  • A hálózat soha nem teljesen megbízható. Ezer kérésből egy meghiúsulhat;
    Ebben az esetben az automatikus teszt nem működik, a munka leáll, és az okot a naplókban kell keresnie;
  • Néhány harmadik fél szolgáltatása nem engedélyezi a túl gyakori kéréseket.

Ezenkívül nem kívánatos az állvány használata, mert:

  • Egy állványt nem csak a rajta futó rossz kód törheti meg, hanem olyan adatok is, amelyeket a megfelelő kód nem tud feldolgozni;
  • Bármennyire is igyekszünk visszaállítani a teszt által a teszt során végrehajtott összes változtatást, valami elromolhat (egyébként minek tesztelni?).

A projektről és a folyamatszervezésről

Cégünk egy Dockerben futó mikroszolgáltatási webalkalmazást fejlesztett ki az Amazon AWS felhőben. A projektben már használtak egységteszteket, de gyakran előfordultak olyan hibák, amelyeket az egységtesztek nem észleltek. Egy teljes mikroszolgáltatást kellett tesztelni az adatbázissal és az Amazon szolgáltatásokkal együtt.

A projekt egy szabványos folyamatos integrációs folyamatot használ, amely magában foglalja a mikroszolgáltatás tesztelését minden véglegesítéskor. A feladat hozzárendelése után a fejlesztő módosítja a mikroszolgáltatást, manuálisan teszteli, és lefuttat minden elérhető automatizált tesztet. Ha szükséges, a fejlesztő módosítja a teszteket. Ha nem talál problémát, akkor kötelezettséget kell tenni ennek a kérdésnek az ágára. Minden véglegesítés után a tesztek automatikusan lefutnak a szerveren. A közös ágba való beolvadás és az azon való automatikus tesztek indítása sikeres felülvizsgálat után történik. Ha a teszt a megosztott ágon halad, a szolgáltatás automatikusan frissül az Amazon Elastic Container Service (bench) tesztkörnyezetében. Az állvány minden fejlesztőnek és tesztelőnek szükséges, nem tanácsos eltörni. A tesztelők ebben a környezetben kézi tesztek végrehajtásával ellenőrzik a javításokat vagy az új funkciókat.

Projekt architektúra

Mikroszolgáltatások automatikus tesztelése a Dockerben a folyamatos integráció érdekében

Az alkalmazás több mint tíz szolgáltatásból áll. Ezek egy része .NET Core-ban, néhány pedig NodeJ-ben íródott. Minden szolgáltatás az Amazon Elastic Container Service Docker-tárolójában fut. Mindegyiknek saját Postgres adatbázisa van, és néhánynak Redis is van. Nincsenek közös adatbázisok. Ha több szolgáltatásnak ugyanazokra az adatokra van szüksége, akkor ezek az adatok, amikor azok megváltoznak, az SNS-en (Simple Notification Service) és az SQS-en (Amazon Simple Queue Service) keresztül eljutnak ezekhez a szolgáltatásokhoz, és a szolgáltatások saját külön adatbázisukban mentik el.

SQS és SNS

Az SQS lehetővé teszi az üzenetek sorba helyezését és a várólista üzenetek olvasását a HTTPS protokoll használatával.

Ha több szolgáltatás olvas egy sort, akkor minden üzenet csak az egyikhez érkezik. Ez akkor hasznos, ha ugyanannak a szolgáltatásnak több példányát futtatja a terhelés elosztása érdekében.

Ha azt szeretné, hogy minden üzenetet több szolgáltatáshoz kézbesítsen, minden címzettnek saját sorral kell rendelkeznie, és SNS-re van szükség ahhoz, hogy az üzeneteket több sorba duplikálják.

Az SNS-ben létrehoz egy témát, és feliratkozik rá, például egy SQS-sorra. Üzeneteket küldhet a témának. Ebben az esetben az üzenet minden egyes, a témára feliratkozott sorhoz elküldésre kerül. Az SNS nem rendelkezik üzenetolvasási módszerrel. Ha a hibakeresés vagy a tesztelés során meg kell találnia, hogy mi kerül elküldésre az SNS-nek, létrehozhat egy SQS-sort, feliratkozhat rá a kívánt témára, és elolvashatja a sort.

Mikroszolgáltatások automatikus tesztelése a Dockerben a folyamatos integráció érdekében

API-átjáró

A legtöbb szolgáltatás nem érhető el közvetlenül az internetről. A hozzáférés API-átjárón keresztül történik, amely ellenőrzi a hozzáférési jogokat. Ez is a mi szolgáltatásunk, és erre is vannak tesztek.

Valós idejű értesítések

Az alkalmazás használja SignalRvalós idejű értesítések megjelenítéséhez a felhasználó számára. Ez az értesítési szolgáltatásban valósul meg. Közvetlenül az internetről érhető el, és maga is működik az OAuth-tal, mert az OAuth és az értesítési szolgáltatás integrálásához képest nem volt praktikus a Web socket-ek támogatása a Gateway-be.

Jól ismert tesztelési módszer

Az egységtesztek olyan dolgokat helyettesítenek, mint az adatbázis, hamis objektumokkal. Ha például egy mikroszolgáltatás megpróbál rekordot létrehozni egy táblában idegen kulccsal, és az adott kulccsal hivatkozott rekord nem létezik, akkor a kérés nem teljesíthető. Az egységtesztek ezt nem tudják kimutatni.

В cikk a Microsofttól Javasoljuk a memórián belüli adatbázis használatát és az álobjektumok megvalósítását.

A memórián belüli adatbázis az Entity Framework által támogatott DBMS-ek egyike. Kifejezetten tesztelésre készült. Az ilyen adatbázisban lévő adatok csak addig tárolódnak, amíg az ezeket használó folyamat le nem fejeződik. Nem igényel táblákat, és nem ellenőrzi az adatok integritását.

Az álobjektumok csak olyan mértékben modellezik az osztályt, amelyet lecserélnek, ameddig a teszt fejlesztője érti a működését.

A Microsoft-cikk nem írja le, hogyan lehet elérni, hogy a Postgres teszt futtatásakor automatikusan elindítsa és hajtsa végre az áttelepítést. Az én megoldásom ezt teszi, ráadásul nem ad hozzá semmilyen kódot kifejezetten tesztekhez magához a mikroszolgáltatáshoz.

Térjünk át a megoldásra

A fejlesztés során világossá vált, hogy az egységtesztek nem elegendőek az összes probléma időben történő megtalálásához, ezért úgy döntöttek, hogy a kérdést más oldalról közelítik meg.

Tesztkörnyezet beállítása

Az első feladat egy tesztkörnyezet üzembe helyezése. A mikroszolgáltatás futtatásához szükséges lépések:

  • Konfigurálja a tesztelés alatt álló szolgáltatást a helyi környezethez, adja meg az adatbázishoz és az AWS-hez való csatlakozás részleteit a környezeti változókban;
  • Indítsa el a Postgres programot, és hajtsa végre az áttelepítést a Liquibase futtatásával.
    A relációs DBMS-ekben, mielőtt adatokat írnánk az adatbázisba, létre kell hozni egy adatsémát, más szóval táblákat. Egy alkalmazás frissítésekor a táblázatokat az új verzió által használt formára kell vinni, lehetőleg adatvesztés nélkül. Ezt hívják migrációnak. Táblázatok létrehozása egy kezdetben üres adatbázisban az átállás speciális esete. A migráció beépíthető magába az alkalmazásba. A .NET és a NodeJS is rendelkezik migrációs keretrendszerrel. Esetünkben biztonsági okokból a mikroszolgáltatásokat megfosztják az adatséma változtatási jogától, a migráció a Liquibase segítségével történik.
  • Indítsa el az Amazon LocalStack alkalmazást. Ez az AWS-szolgáltatások otthoni futtatása. Van egy kész kép a LocalStack számára a Docker Hubon.
  • Futtassa a szkriptet a szükséges entitások létrehozásához a LocalStackben. A shell-szkriptek az AWS parancssori felületet használják.

A projekt tesztelésére szolgál Postás. Korábban is létezett, de manuálisan indították el, és a standon már telepített alkalmazást teszteltek. Ez az eszköz lehetővé teszi tetszőleges HTTP(S) kérések lebonyolítását, és annak ellenőrzését, hogy a válaszok megfelelnek-e az elvárásoknak. A lekérdezések egy gyűjteménybe kerülnek, és a teljes gyűjtemény futtatható.

Mikroszolgáltatások automatikus tesztelése a Dockerben a folyamatos integráció érdekében

Hogyan működik az automatikus teszt?

A teszt során minden működik a Dockerben: a tesztelés alatt álló szolgáltatás, a Postgres, a migrációs eszköz és a Postman, vagy inkább konzolos verziója - Newman.

A Docker számos problémát megold:

  • Függetlenség a gazdagép konfigurációjától;
  • Függőségek telepítése: A Docker képeket tölt le a Docker Hubról;
  • A rendszer visszaállítása az eredeti állapotba: egyszerűen távolítsa el a tárolókat.

dokkoló-komponálni a konténereket az internettől elszigetelt virtuális hálózatba egyesíti, amelyben a konténerek domain nevek alapján találják meg egymást.

A tesztet egy shell szkript vezérli. A teszt futtatásához Windows rendszeren a git-bash-t használjuk. Így Windowsra és Linuxra is elég egy szkript. A Git és a Dockert a projekt összes fejlesztője telepítette. A Git Windows rendszerre történő telepítésekor a git-bash telepítve van, így mindenkinek megvan az is.

A szkript a következő lépéseket hajtja végre:

  • Docker képek építése
    docker-compose build
  • Az adatbázis és a LocalStack indítása
    docker-compose up -d <контейнер>
  • Adatbázis migráció és a LocalStack előkészítése
    docker-compose run <контейнер>
  • Teszt alatt lévő szolgáltatás indítása
    docker-compose up -d <сервис>
  • A teszt futtatása (Newman)
  • Minden tartály leállítása
    docker-compose down
  • Eredmények közzététele a Slackben
    Van egy chat, ahová a zöld pipával vagy piros kereszttel és a naplóra mutató hivatkozással ellátott üzenetek mennek.

A következő Docker-képek vesznek részt ezekben a lépésekben:

  • A tesztelt szolgáltatás ugyanaz a kép, mint az éles verzióé. A teszt konfigurációja környezeti változókon keresztül történik.
  • A Postgres, a Redis és a LocalStack esetében a Docker Hub kész képei használatosak. Vannak kész képek is a Liquibase-hez és a Newmanhez. A miénket az ő csontvázukra építjük, és hozzáadjuk a fájljainkat.
  • A LocalStack előkészítéséhez egy kész AWS CLI-képet kell használnia, és az alapján hozzon létre egy szkriptet tartalmazó képet.

Használata kötetek, nem kell Docker-képet készítenie csak ahhoz, hogy fájlokat adjon a tárolóhoz. A kötetek azonban nem megfelelőek a környezetünkben, mert maguk a Gitlab CI-feladatok konténerekben futnak. A Dockert egy ilyen tárolóból is vezérelheti, de a kötetek csak a gazdagép rendszerről csatolják a mappákat, egy másik tárolóból nem.

Problémák, amelyekkel találkozhat

Készenlétre várva

Ha egy szolgáltatást tartalmazó tároló fut, ez nem jelenti azt, hogy készen áll a kapcsolatok fogadására. Meg kell várnia, amíg a kapcsolat folytatódik.

Ezt a problémát néha szkript segítségével oldják meg várj rá.sh, amely lehetőséget vár a TCP-kapcsolat létrehozására. A LocalStack azonban 502 Bad Gateway hibát jelezhet. Ezen kívül sok szolgáltatásból áll, és ha az egyik készen áll, az nem mond semmit a többiről.

döntés: LocalStack kiépítési szkriptek, amelyek 200-as válaszra várnak mind az SQS-től, mind az SNS-től.

Párhuzamos feladat-konfliktusok

Egyszerre több teszt is futhat ugyanazon a Docker-gazdagépen, ezért a tároló- és a hálózatneveknek egyedinek kell lenniük. Sőt, ugyanannak a szolgáltatásnak a különböző ágaiból származó tesztek egyidejűleg is futhatnak, így nem elég a nevüket beírni minden egyes compose fájlba.

döntés: A szkript a COMPOSE_PROJECT_NAME változót egyedi értékre állítja be.

Ablakok jellemzői

Számos dologra szeretnék rámutatni, amikor a Dockert Windows rendszeren használja, mivel ezek a tapasztalatok fontosak a hibák előfordulásának megértéséhez.

  1. A tárolóban lévő shell-szkripteknek Linux-sorvéggel kell rendelkezniük.
    A shell CR szimbólum szintaktikai hiba. A hibaüzenetből nehéz megállapítani, hogy ez a helyzet. Amikor ilyen szkripteket szerkeszt Windows rendszeren, megfelelő szövegszerkesztőre van szüksége. Ezenkívül a verziókezelő rendszert megfelelően konfigurálni kell.

A git így van beállítva:

git config core.autocrlf input

  1. A Git-bash emulálja a szabványos Linux-mappákat, és egy exe-fájl (beleértve a docker.exe-t) meghívásakor lecseréli az abszolút Linux-útvonalakat Windows-útvonalakra. Ennek azonban nincs értelme a nem a helyi gépen lévő elérési utak (vagy egy tárolóban lévő útvonalak) esetén. Ez a viselkedés nem tiltható le.

döntés: adjon meg egy további perjelet az elérési út elejéhez: //bin a /bin helyett. A Linux megérti az ilyen utakat; számára több perjel ugyanaz, mint egy. De a git-bash nem ismeri fel az ilyen útvonalakat, és nem próbálja meg átalakítani őket.

Napló kimenet

A tesztek futtatásakor szeretném látni a Newman és a tesztelt szolgáltatás naplóit. Mivel ezeknek a naplóknak az eseményei összekapcsolódnak, sokkal kényelmesebb egy konzolban egyesíteni őket, mint két külön fájl. Newman ezen keresztül indul dokkoló-kompozíció futtatása, és így a kimenete a konzolba kerül. Csak annyit kell tenni, hogy a szolgáltatás kimenete is oda kerüljön.

Az eredeti megoldás az volt dokkoló-összeállít nincs zászló -d, de a shell képességeit használva küldje el ezt a folyamatot a háttérbe:

docker-compose up <service> &

Ez addig működött, amíg el kellett küldeni a naplókat a Dockertől egy harmadik féltől származó szolgáltatáshoz. dokkoló-összeállít leállította a naplók kiadását a konzolra. A csapat azonban működött docker attach.

döntés:

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

Azonosító ütközés a tesztiterációk során

A tesztek több iterációban futnak. Az adatbázis nincs törölve. Az adatbázisban lévő rekordok egyedi azonosítókkal rendelkeznek. Ha konkrét azonosítókat írunk fel a kérésekbe, akkor a második iterációnál ütközést kapunk.

Ennek elkerülése érdekében vagy az azonosítóknak egyedinek kell lenniük, vagy a teszt által létrehozott összes objektumot törölni kell. Egyes objektumok a követelmények miatt nem törölhetők.

döntés: GUID-ket generál Postman szkriptek segítségével.

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

Ezután használja a szimbólumot a lekérdezésben {{myUUID}}, amelyet a változó értékére cserélünk.

Együttműködés a LocalStack segítségével

Ha a tesztelt szolgáltatás SQS-sort olvas vagy ír, akkor ennek ellenőrzéséhez magának a tesztnek is működnie kell ezzel a sorral.

döntés: kérések a Postmantól a LocalStack felé.

Az AWS-szolgáltatások API dokumentált, így SDK nélkül is lekérdezhetők.

Ha egy szolgáltatás egy sorba ír, akkor azt elolvassuk és ellenőrizzük az üzenet tartalmát.

Ha a szolgáltatás üzeneteket küld az SNS-nek, az előkészítési szakaszban a LocalStack is létrehoz egy sort, és előfizet erre az SNS-témára. Aztán minden a fent leírtakon múlik.

Ha a szolgáltatásnak be kell olvasnia egy üzenetet a sorból, akkor az előző tesztlépésben ezt az üzenetet írjuk a sorba.

A tesztelés alatt álló mikroszolgáltatásból származó HTTP kérések tesztelése

Egyes szolgáltatások HTTP-n keresztül mással is működnek, mint az AWS, és egyes AWS-szolgáltatások nincsenek implementálva a LocalStackben.

döntés: ezekben az esetekben segíthet MockServer, amiben van egy kész kép Docker hub. A várt kéréseket és az azokra adott válaszokat egy HTTP-kérés konfigurálja. Az API dokumentált, ezért kéréseket küldünk a Postmantól.

Az OAuth hitelesítés és engedélyezés tesztelése

OAuth-ot használunk és JSON webes tokenek (JWT). A teszthez egy OAuth-szolgáltatóra van szükség, amelyet helyben tudunk futtatni.

A szolgáltatás és az OAuth-szolgáltató közötti minden interakció két kérésre vezethető vissza: először a konfigurációt kell kérni /.well-known/openid-configuration, majd a nyilvános kulcsot (JWKS) kéri a konfigurációs címre. Mindez statikus tartalom.

döntés: Teszt OAuth-szolgáltatónk egy statikus tartalomszerver és két fájl rajta. A tokent egyszer generálják, és a Githez kötik.

A SignalR tesztelés jellemzői

A Postman nem működik websocketekkel. Egy speciális eszköz készült a SignalR tesztelésére.

A SignalR kliens nem csak egy böngésző lehet. Van hozzá egy klienskönyvtár a .NET Core alatt. A .NET Core-ban írt kliens kapcsolatot létesít, hitelesítésre kerül, és egy meghatározott üzenetsorozatra vár. Ha váratlan üzenet érkezik, vagy a kapcsolat megszakad, a kliens 1-es kóddal lép ki. Ha az utolsó várt üzenet érkezik, a kliens 0 kóddal lép ki.

Newman egyszerre dolgozik az ügyféllel. Számos kliens indul annak ellenőrzésére, hogy az üzenetek eljutnak-e mindenkihez, akinek szüksége van rájuk.

Mikroszolgáltatások automatikus tesztelése a Dockerben a folyamatos integráció érdekében

Több ügyfél futtatásához használja a lehetőséget --skála a docker-compose parancssorban.

Futtatás előtt a Postman szkript megvárja, amíg az összes kliens kapcsolatot létesít.
Már találkoztunk a kapcsolatra várás problémájával. De voltak szerverek, és itt a kliens. Más megközelítésre van szükség.

döntés: a tárolóban lévő kliens használja a mechanizmust Állapotfelméréshogy tájékoztassa a szkriptet a gazdagépen annak állapotáról. Az ügyfél létrehoz egy fájlt egy adott útvonalon, mondjuk a /healthcheck, amint a kapcsolat létrejött. A HealthCheck szkript a docker fájlban így néz ki:

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

Csapat dokkoló vizsgálja meg Megmutatja a tároló normál állapotát, állapotát és kilépési kódját.

A Newman befejezése után a szkript ellenőrzi, hogy az ügyféllel rendelkező összes tároló leállt-e, 0 kóddal.

A boldogság létezik

Miután leküzdöttük a fent leírt nehézségeket, egy sor stabil futási tesztet kaptunk. A tesztek során minden szolgáltatás egyetlen egységként működik, interakcióban az adatbázissal és az Amazon LocalStack-kel.

Ezek a tesztek egy több mint 30 fejlesztőből álló csapatot védenek meg a hibáktól egy olyan alkalmazásban, amely több mint 10 mikroszolgáltatást és gyakori telepítéseket tartalmaz.

Forrás: will.com

Hozzászólás