% !TeX root = ../thesis.tex
%----------------------------------------------------------------------------
\chapter{Teszt környezet kialakítása}
%----------------------------------------------------------------------------

A munkám során elkészített és módosított szoftverek helyes működésének demonstrálása egy teljes peremhálózati és felhő számítástechnikai rendszer kiépítését igénylik. Mivel az ilyen környezetek sokszor nem állnak rendelkezésünkre, ezért szükség van egy olyan megoldásra, amely jól modellezi az ilyen rendszerek működését, így képesek vagyunk az alkalmazásainkat telepíteni benne.

Vannak szituációk amikor egy teljesen kontrollált tesztkörnyezet alkalmazását kívánja meg a teszt szcenárió. Egy ilyen környezetben a rendszerben elvárás, hogy minden lényeges paramétere szabadon módosítható és precízen megfigyelhető legyen. 

Ebben a fejezetben egy ilyen tesztkörnyezet fejlesztését és kialakítását mutatom be. A munkám során később ebben a rendszerben tudom tesztelni az elkészült szoftver rendszereket.

\section{Célkitűzések}

A tesztkörnyezet egy modellje a valódi környezetnek, amelyben a tesztelni kívánt alkalmazások futnak. A modell lényege, hogy a valóságnak egy egyszerűsített mását adja. A mérések szempontjából fontos tulajdonságokat megtartsa, ideális esetben konfigurálhatóvá tegye. A mérés szempontjából nem lényeges vagy nem befolyásoló tényezőket elhagyhatjuk a modellből, ezzel egyszerűsítve annak működését, hogy a funkcionalitásra tudjunk koncentrálni.

A tesztkörnyezet megtervezése előtt összefoglaltam, hogy mik azok a tulajdonságok, amiket át kell emelni a modellbe és mik azok, amelyekkel nem kell foglalkozni. Ezek megfogalmazásánál figyelembe vettem azt, hogy az előző fejezetekben ismeretet munkám eredményei jól demonstrálhatóak legyenek. Azok a tulajdonságok, amelyeket a modellnek meg kell valósítania, a következők:
\begin{itemize}
	\item A választott futtatási környezet minden tulajdonságát egy-az-egyben meg kell valósítania.
	\item Legalább egy perem és egy felhő infrastruktúra környezet legyen modellezve.
	\item A felhő, perem infrastruktúra és kliens közötti hálózati tulajdonságok konfigurálhatóak legyenek.
\end{itemize}

További követelmény a tesztkörnyezet felé, hogy telepítése egyszerű legyen és hordozható. Igény esetén akár egy fejlesztő vagy tesztelő képes legyen a saját számítógépén is elindítani és használni. A benne futtatott teszteknek reprodukálhatónak kell lennie, azaz két teszt között a tesztet befolyásoló tényezők ne változzanak.

Azok mellett a követelmények mellett, amelyeket a modellnek teljesítenie kell, érdemes megemlíteni néhány tulajdonságát a rendszernek, amelyet az egyszerűsítés kedvéért érdemes elhanyagolni. Ilyenek a kliens eszközök konkrét fizikai környezete. Mivel a munkám elsősorban a felhő alkalmazások átalakítására, implementálására és a köztük lévő hálózati kapcsolat vizsgálatára irányult, ezért a konkrét kliensek fizikai környezete és megvalósítása nem játszik szerepet. 

Mivel mindkét szoftver, amellyel a korábbi fejezetekben foglalkoztam tartalmaz olyan komponenst, amely a környezetéről gyűjt információt (Hangrögzítés), vagy éppen abba avatkozik bele (Robotkarok tárgyakat mozgatnak), ezeket a funkcionalitásokat érdemes emulálni. Szükség esetén érdemes fenntartani a lehetőséget, hogy valódi eszközöket csatlakoztassunk a tesztkörnyezethez.

\section{Magas szintű tervezés}

A kijelölt célok megvalósítására egy teljesen virtuális környezetet terveztem meg. Az egyes szerepeket virtuális gépek, vagy azok egy csoportja látja el.

A teszt infrastruktúrát két szempontból bontottam fel: az egyik az előbb említett szerepek és azok kapcsolata, a másik pedig a szoftverek telepítésének rétegei, mivel ezek a rétegek egymásra épülnek. Minden komponens konfigurációja egységes, egyedi konfigurációk változtatása a telepítés során adja ki a végleges infrastruktúrát. A két felbontást két dimenzión ábrázolva \aref{fig:birbemu_layers}.\ ábra részletezi. A függőleges felbontás az egyes szerepeket, míg a vízszintes felbontás a telepítés rétegeit ábrázolja.


\begin{figure}[h!]
	\centering
	\includegraphics[width=0.35\textwidth]{figures/birbemu_layers}
	\caption{Virtuális környezet tervezésének felbontása két dimenzió mentén}
	\label{fig:birbemu_layers}
\end{figure}


\subsection{Szerepek szerinti felbontás}

\subsubsection{Futtató környezet}

A környezetben szükség van a választott alkalmazás futtató keretrendszer (esetünkben \textit{KubeFed}) futtatására. A \textit{KubeFed} lényegében több \textit{Kubernetes} klaszter fölé húzott közös vezérlési réteg. Ennek megfelelően virtuális gépeket csoportokra bontottam, adott csoportok egy-egy \textit{Kubernetes} klasztert valósítanak meg.

Az egyes \textit{Kubernetes} klaszterek esetünkben az egyes adatközpontokat szimbolizálják. Egy ilyen klaszter jelöli a felhő adatközpontot, a többi klaszter pedig jelölheti a peremhálózati adatközpontokat vagy akár további felhőket is. A tesztelendő alkalmazások szempontjából, nincs számottevő különbség egy felhő vagy egy peremhálózati adatközpont belső működésében, ezért itt főképp csak az elnevezésükben térnek el.

Az önálló \textit{Kubernetes} klaszterek fölé már lehet \textit{KubeFed} környezetet telepíteni. A telepített \textit{KubeFed} szoftver megfelelően modellezi a valós környezetben használt futtató környezetet, hiszen ugyanaz a szoftver. Telepítése és üzemeltetése között nincs különbség a valós és teszt környezetben.

\subsubsection{Kliens}

A peremhálózati rendszerek három rétegű architektúrájában legalul foglal helyet maga a kliens eszköz. A klienseket ebben a környezetben egy vagy több önálló virtuális gép valósítja meg. Egy virtuális gép egy vagy több klienst is megvalósíthat, függően a kliensek erőforrás és hálózati konfiguráció igényeitől.


\subsubsection{Hálózat}

A célok között fontos szerepet képviselt az egyes \enquote{adatközpontokat} illetve adatközpontokat kliensekkel összekötő hálózat, és azok sajátosságainak megfelelő modellezése. Ez magában foglalja a különböző hálózati anomáliák és kedvezőtlen paraméterek szimulálását is.

Ehhez az egy \enquote{adatközponthoz} tartozó virtuális gépeket közös adatkapcsolati rétegbe szerveztem. A hálózat fizikai és adatkapcsolati rétegeit a virtualizációs környezet biztosítja. Az egyes elszeparált alhálózati rétegek mindegyikét saját alhálózatukba rendeztem. A kliens eszközök önmaguk is egy vagy több elszeparált alhálózatba kerülhetnek.

Az alhálózatok között az útválasztást egy külön virtuális gép végzi, amely olyan szoftvert futtat ami képes különböző egyedileg konfigurálható hálózati paramétereket emulálni. Ezek a paraméterek elsősorban késleltetés, sávszélesség, csomagvesztés stb.


\subsection{Telepítés rétegei szerinti felbontás}

A környezet felépítését rétegekre osztottam. Ennek az a célja, hogy az egyes rétegek telepítése önállóan jól definiálható és tervezhető legyen. További előnye ennek a felosztásnak, hogy az egyes rétegek szükség esetén cserélhetőek más megoldásokra, ezzel elérve, hogy a tesztkörnyezet könnyen testreszabható legyen.

Az egyes rétegek egymásra épülésének sorrendje a következő:
\begin{enumerate}
	\item \textbf{Virtualizációs környezet:} Platform, amely a virtualizált infrastruktúra futtatását megvalósítja.
	\item \textbf{(Virtuális) infrastruktúra:} A konkrét virtuális gépek és a virtuális hálózat konfigurációja.
	\item \textbf{Operációs rendszer konfiguráció:} A használt operációs rendszer és a környezetben való működéséhez szükséges konfiguráció.
	\item \textbf{Futtatókörnyezet:} Alkalmazás futtató környezet, amely felel a tesztelni kívánt alkalmazás futtatásáért. Egyben megfelel a valós környezetben használt futtató környezettel. 
	\item \textbf{Alkalmazás:} A futtatókörnyezetbe telepített egyéni alkalmazások, amelyek tesztelését végezzük.
\end{enumerate}

Az egyes rétegeinek telepítésére önálló automatizációs megoldásokat terveztem használni. A rétegek megfelelő szeparálása ezeknek az eszközöknek a kiválasztását, beállítását és alkalmazását is megkönnyíti. Lehetőségünk van olyan eszközöket használni, amelyek az egyes rétegeken belüli feladatcsoportok végrehajtására specializáltak.

\section{Megvalósítás}

A munka során a terveim alapján konkrétan megvalósított környezetem három \textit{Kubernetes} klaszterből áll. Ebből egy jelképezi a felhőt (\texttt{cloud}), a másik kettő a peremhálózati rendszert (\texttt{edge-1}, \texttt{edge-2}). Az útválasztást egy külön virtuális gép végzi. Kliens eszköz modellezéséhez egy külön virtuális gép fut. A környezet felépítését és az egyes virtuális gépek viszonyát \aref{fig:birb_edgemu_architecture}.\ ábra szemlélteti. 

\begin{figure}[h!]
	\centering
	\includegraphics[width=0.8\textwidth]{figures/birb_edgemu_architecture-less network}
	\caption{Teszt környezet architekturális vázlata}
	\label{fig:birb_edgemu_architecture}
\end{figure}

A \textit{KubeFed} federáció tagjai a \texttt{cloud}, \texttt{edge-1} és \texttt{edge-2} nevű klaszterek. Ezek közül a \texttt{cloud} nevű klaszter a federációt vezérlő klaszter.

A klasztereknek és klienseknek természetesen nem csak egymással kell tudniuk kommunikálni. Előfordulhat, hogy szükségük van arra, hogy elérjék a publikus internetet is (például szoftverfrissítés letöltésére). Az ilyen típusú forgalom nem kívánatos a virtuális útválasztón. Mivel a környezetben csak a klaszterek és a kliensek közötti forgalom paramétereit szeretnénk befolyásolni, ezért felesleges a nem arra irányuló forgalom átvezetése. Emellett az extra forgalom bizonyos szélsőséges helyzetekben befolyásolhatja a mérési eredményeket is. Ennek megoldására minden alhálózatban két átjáró van, az egyik a virtuális útválasztó a másik a virtuális környezet által biztosított átjáró amelyen keresztül el lehet érni a publikus internetet.

\subsection{Virtuális gépek és hálózat}

A környezetet alkotó virtuális gépek futtatása nem függ egy konkrét virtualizációs platform implementációtól. Az egyetlen elvárás, hogy képes legyen virtuális gépeket és virtuális hálózatokat létrehozni és futtatni. 

A virtuális gépek futtatásához \textit{libvirt}\footnote{\url{https://libvirt.org/}} környezetet használtam. 

A \textit{libvirt} számára \acrshort{xml} formátumban lehet definiálni a virtuális gépeket és virtuális hálózatokat \cite{libvirt_xml}. A felépítés ezen lépésének automatizálására írtam egy egyszerű \gls{python} szkriptet, ami ilyen \acrshort{xml} definíciókat generál. Ezek \textit{libvirt}be importálásával a virtuális gépek és a hálózati infrastruktúra készen állt.

Négy virtuális hálózatot hoztam létre, ezeket \texttt{cloud}, \texttt{edge-1}, \texttt{edge-2} és \texttt{client}-nek neveztem el, attól függően, hogy melyik virtuális gépeket szolgálják ki. Az útválasztó kivételével minden virtuális gépnek egy interfésze van, amely az adott hálózatra van csatlakoztatva. Az útválasztónak mind a négy hálózatban van interfésze. A hoszt által biztosított átjáró minden hálózatban jelen van. Az ide irányuló forgalom hálózati címfordítás segítségével a gazdagép címére fordul, így a virtuális gépek elérik az internetet is.

\subsection{Operációs rendszer konfigurációja}


Mivel a környezet 11 virtuális gépből áll, ezért ezeknek egyenként \enquote{kézzel} való telepítése időigényes lenne és könnyen lehetne hibát ejteni benne, aminek a megkeresése és javítása további időt igényelne. 

Ezért a virtuális gépek telepítésére és alapvető konfigurációjának elvégzésére is automatizációs eszközöket használtam.

Az operációs rendszer telepítése helyett inkább egy előre elkészített képfájlból dolgoztam. Az általam használt képfájl \textit{Ubuntu} \gls{linux} disztribúciót tartalmaz. A képfájlon előre fel van telepítve a \textit{Cloud Init}\footnote{\url{https://cloud-init.io/}} nevű eszköz, ami rendszer indulás közben elvégzi az operációs rendszer alapvető konfigurációját. Ilyen a gép hosztneve, (egyszerűsített) hálózati konfigurációja, és az \acrfull{ssh} kapcsolaton való bejelentkezéshez szükséges publikus kulcsok telepítése. 

A \textit{Cloud Init} az egyedi konfigurációt egy második lemez képfájlról tölti be. A lemez képfájlok elkészítésére írtam egy egyszerű \gls{python} szkriptet.

Mivel a \textit{Cloud Init} csak az alapvető rendszer konfigurációt hajtja végre, ezért a komplexebb/specifikus konfigurációk elvégzésére egy másik eszközt használtam. A \textit{Cloud Init} egy olyan működő konfiguráció állít be a virtuális gépen, amely lehetővé teszi, hogy be tudjunk arra jelentkezni \acrshort{ssh} kapcsolaton keresztül. Az \acrshort{ssh} kapcsolat alkalmas arra, hogy \textit{Ansible}\footnote{\url{https://www.ansible.com/}} konfiguráció menedzsment eszközt használjunk.

Az \textit{Ansible} egy deklaratív konfiguráció kezelő eszköz \cite{ansible_docs}, vagyis az elvárt állapotot írjuk le, amelyhez az \textit{Ansible} automatikusan igazítani fogja a konfigurációs beállításokat az operációs rendszeren. Futás közben \acrshort{ssh} protokollon keresztül csatlakozik a konfigurálni kívánt hosztokra, majd ellenőrzi, hogy minden beállítás egyezik-e az általunk elvárt állapottal. Ha valamelyik konfiguráció eltér, akkor azt automatikusan beállítja az elvárt állapotra.


\textit{Ansible} segítségével letöröltem a felesleges szoftver komponenseket, feltelepítettem a szükségeseket és beállítottam a végleges hálózati konfigurációt. 

Annak érdekében, hogy a virtuális gépek az alhálózatok közti forgalmat a virtuális útválasztón keresztül küldjék, a többi forgalmat pedig a gazdagép átjáróján keresztül, statikus útválasztó tábla bejegyzéseket vettem fel minden gépen. A bejegyzések alapján minden gépen a többi alhálózathoz az átjáró a virtuális útválasztó, az alapértelmezett pedig a gazdagép átjárója. 


\subsection{\textit{Kubernetes} telepítése}

A \textit{KubeFed} használatához először szükség van arra, hogy legyenek működő \textit{Kubernetes} klasztereink, amelyeket federálni tudunk \cite{installing_kubefed}. 

Egy \textit{Kubernetes} klaszter telepítésére több lehetőségünk is van. Rendelkezésünkre állnak disztribúciók, amelyek minimális konfigurációval egy teljes értékű klasztert képesek telepíteni. A telepítéshez a \textit{Kubespary}\footnote{\url{https://kubespray.io/}} disztribúciót használtam.

A \textit{Kubespray} alapvető konfigurációjában csak keveset módosítottam. Úgy állítottam be, hogy a három virtuális gépből egyet jelöljön ki \texttt{master} szerepre, kettőt pedig \texttt{worker} szerepre. A Kubernetes telepítését egyenként végeztem el mindhárom klaszterre. 

Sikeres telepítés után néhány alapvető komponenst szintén kézzel, \textit{Helm}\footnote{\url{https://helm.sh/}} segítségével telepítettem:
\begin{itemize}
	\item A perzisztens tárhely kezeléshez \textit{Longhorn}\footnote{\url{https://longhorn.io/}} \textit{Storage Class}-t telepítettem. A \textit{Longhorn} nem igényli külső adat tároló szerverek használatát, a \textit{Kubernetes} klasztert alkotó gépek saját tárhelyét használja.
	\item A beérkező \acrshort{http} kérések fogadására, kezelésére és megfelelő mikroszolgáltatásokhoz irányítására \textit{Nginx}\footnote{\url{https://kubernetes.github.io/ingress-nginx/}} \textit{Ingress Controller}-t telepítettem. Ennek segítségével mikroszolgáltatások halmazával megvalósított szolgáltatás egy egységes \acrshort{http} interfészen érhető el.
\end{itemize}


\subsection{\textit{KubeFed} telepítése}

A \textit{KubeFed} telepítéséhez követtem annak dokumentációját. A telepítés csak pár lépésből állt. 

Első lépésként a \textit{Helm} segítségével telepítettem a \textit{KubeFed} vezérlését megvalósító komponenseket a \texttt{cloud} nevű klaszterbe. Ezek után a letöltöttem a \texttt{kubefedctl} nevű parancssoros alkalmazást, amely segítségével beléptettem mindhárom klasztert a federációba\footnote{A vezérlő klasztert is be kell léptetni annak érdekében, hogy a \textit{KubeFed} oda is ütemezzen alkalmazás komponenseket}. Ezek után lekérdeztem a klaszterek állapotát reprezentáló \acrshort{api} objektumot a \textit{Kubernetes} \acrshort{api} interfészén, ez megerősítette, hogy a federáció vezérlő mindhárom \textit{Kubernetes} klasztert eléri és tudja kezelni.

Ezek után lehetőségem volt egyenként ki és be kapcsolni a \textit{KubeFed} által federált objektumok használatát, mint a federált névterek, federált konfigurációk vagy éppen federált \textit{deployment}-ek.

\section{Erőforrás igények}

Bár a rendszer erőforrás igénye nagyban függ a telepített alkalmazásoktól, maga a környezet telepítése és futtatása is igényel valamennyi erőforrást. 

\textit{Kubernetes} futtatásához minden virtuális gépnek legalább 2 Gigabyte rendszer memória szükséges és két processzor mag \cite{kubernetes_docs}. Tapasztalataim viszont azt mutatják, hogy ez néha túl kevés tud lenni és különböző teljesítménybeli problémákba tudunk ütközni, ezért a \textit{Kubernetes}-t futtató virtuális gépeknek ajánlott legalább 4 Gigabyte memória allokálása. 

Az útválasztó gépnek nincs szüksége sok memóriára a csomagok továbbítására, amíg nem használjuk másra, addig 512 Megabyte memória megfelel neki. 

Elmondható ezek alapján, hogy a tesztkörnyezet futtatásához legalább 36.5 Gigabyte memóriára van szükség, ha a klienseket nem számoljuk.

A kliensek száma és erőforrás igénye teljesen a használt alkalmazástól függ. Itt ezért kezdetben 2 Gigabyte memóriát allokáltam, majd később kibővítettem, amikor szükség volt rá.

Processzor tekintetében nem fedeztem fel különösen nagy elvárásokat. Tapasztalataim szerint a rendszer stabilan működött egy 2011-ben gyártott négymagos \textit{Intel}\textregistered \textit{Core}\texttrademark i7-3770 processzoron. 

A lemez elérések teljesítménye viszont jelentős tényező volt a rendszer teljesítménye szempontjából. A környezet önmagában stabilan üzemelt egy \acrshort{raid}5 tömbre telepítve, amelyet 8 darab 15.000 percenkénti fordulatú hagyományos mechanikus diszk alkotott. Viszont amint feltelepítettem a tesztelésre szánt alkalmazásokat, a tárhely elérési késleltetés jelentősen megnőtt olyan mértékekig, ami az alkalmazás instabil működését és átmeneti összeomlását okozták. Ezért mindenképpen ajánlott ilyen rendszert \acrshort{ssd} lemezekből álló tárhely tömbre telepíteni.


\section{Környezet alkalmazása}

A tesztkörnyezetnek egyik fontos célja, hogy különböző hálózati paramétereket tudjon szimulálni. Ennek megvalósításáért a virtuális útválasztó felel. 

A szükséges hálózati funkciókat implementálja a \gls{linux} kernel, ezért a virtuális gépen is ugyanolyan \textit{Ubuntu} operációs rendszer fut, mint a többin a környezetben. A virtuális gépen bekonfigurálásra kerültek a megfelelő útválasztó táblák és engedélyezve lett rajta az útválasztó funkcionalitás. Ennyi elég ahhoz, hogy működő kapcsolatot létesítsen az egyes alhálózatok között. 

A hálózati kondíciók szimulálásához a kernel \textit{Traffic Control} képessége tökéletesen használható. A \textit{Traffic Control} a következő részekből áll \cite{man_tc}:
\begin{itemize}
	\item \textbf{Shaping} (formálás): Interfészről kimenő csomagok rátájának szabályozása. Nem csak sávszélesség szabályozásra alkalmas. Használható például az egyenetlen adatforgalom simítására is.
	\item \textbf{Scheduling} (ütemezés): A csomagok küldésének idejét ütemezhetjük vele, alkalmas arra, hogy például késleltetést szimuláljunk. Csak kimenő csomagokra alkalmazható.
	\item \textbf{Policing} (szabályozás): Hasonló a formáláshoz, viszont a kimenő csomagok helyett a beérkezőkre vonatkozik.
	\item \textbf{Dropping} (eldobás): Bizonyos szabályok alapján eldobhatunk csomagokat amelyek meghaladnak sávszélességi korlátokat. Ez mind a bejövő mind a kimenő forgalomra alkalmazható.
\end{itemize}

A kernelben lévő \textit{Traffic Control} konfigurálásához a \texttt{tc} nevű felhasználói módú eszközt tudjuk használni. A használatára egy példát mutat be \aref{ex:tc}.\ kódrészlet.

\begin{lstlisting}[float=!ht,caption={10ms késleltetés konfigurálása egy interfészre \texttt{tc} használatával},label=ex:tc]
	tc qdisc add dev enp1s0f2 root netem delay 10ms
\end{lstlisting}
