A virtualizáció előnyei

Virtualizáció alatt a legtöbbek gondolatában az “egy vas több rendszer” alapötlet jelenik meg. Nem is járunk messze a valóságtól ezzel, hiszen az egyik fő mozgatórugó a konszolidáció, a szerverek számának csökkentése, optimalizálása. Minden szolgáltatásnak külön rendszert dedikálni sem költség, sem kihasználtság szempontjából nem lenne hatékony megoldás. Ez azonban csak egy kis szelete a valós okoknak. A fejlesztések során a tesztelésekhez alacsony prioritású virtuális gépeket definiálhatunk, így a saját desktop konfiguráció károsításától védve vagyunk a tesztesetek futtatása alatt. Az ilyen és ehhez hasonló problémák áthidalására kezdtek el megjelenni a virtualizációs eljárások. A hatékony megoldások keresése napjaink feladati közé tartozik, noha sohasem mondhatjuk ezt egy eljárásra, hogy használatával minden környezetben a maximális teljesítményt hozhatjuk ki. Célokat kell felállítani, majd megfelelő technikát keresni. Cikksorozatomban egy új, operációs rendszer szintű virtualizációs technika fontosabb tulajdonságait és paramétereit szeretném bemutatni.

Megoldások

A virtualizáció szó alatt két eltérő megvalósításra gondolhatunk. Az egyik a hardver virtualizáció. Ez esetben a virtuális gépben futó operációs rendszer ideális esetben nem is tud arról, hogy nem fizikai hardveren fut, hanem egy virtuális gépben. Annak ellenére, hogy a virtualizációs szoftverek gyártói és a processzorok is számottevő erőfeszítéseket tettek annak érdekében, hogy a teljesítmény minél jobb legyen, egy-egy ilyen virtuális gép még mindig számottevő erőforrást igényel.

Ezzel szemben áll az az ötlet, hogy nincs is szükség teljes virtualizálásra, elegendő az operációs rendszer magjában (kernelében) elkülöníteni a folyamatokat. Ezt hívják konténeres virtualizációnak. Ezen ötlet képviselője az OpenVZ, amely először önálló kiegészítőként készült a Linux kernelhez, mára azonban a funkciók többségét beolvasztották a Linux főágába. (Természetesen vannak hibrid megoldások is, ilyen például a Xen).

A konténeres virtualizáció új lehetőségeket nyitott a virtuális gépek szervezésében. Ebben a konténerek szervezése szolgáltatás alapon történik, minden szolgáltatásnak konténert, saját környezetet definiálunk, amelyek között a célszerűségnek megfelelően linkeket képzünk. Példának okáért lesz egy adatbázis-konténerünk, az alkalmazás futtatásához egy PHP konténerünk, előtte pedig egy webszerver konténerünk.

A konténerek többszörözése szükség esetén könnyen megtehető, így egy adott szolgáltatást pillanatok alatt több példányban futtathatunk. A teljes virtuális gépek ezzel szemben egy kompakt, összetett, robusztus megoldást adnak, számtalan szolgáltatást integrálva. A konténer alapú megoldások úttörője az OpenVZ volt, aki 2005-ben kiadta operációs rendszer szintű virtualizációs megoldását.

Biztonsági szempontból már mérlegelnünk kell a fennálló kockázatot. A különböző virtualizációs módszerek más-más módokon biztosítják az izolációt. Általánosságban elmondható, hogy egy virtuális gépen futó alkalmazás által igénybe vehető erőforrások korlátozhatóak, ám a hoszt gép fájlrendszerére, folyamataira való rálátás különböző mértékben, de minden virtualizációs eljárásban jelen van. Egy ilyen irányú technológia alkalmazása előtt tehát különösen fontos a megtakarítás nagyságának és az adatok értékének a mérlegelése.

A Linux kernel konténerező megoldása

A konténerek támogatása nagyrészt az OpenVZ és a Linux-VServer projektnek köszönhetően került be a Linux kernelbe. A folyamatok szeparálása az alábbi 6 nagy területre bontható szét:

  • mnt: A fájlrendszer különböző „nézeteinek” biztosítása.
  • pid: Folyamatok azonosítása, eltérő környezetben előfordulhat ugyanaz a PID (program azonosító szám), mint a gazda gépen.
  • net: Hálózati kapcsolat szeparálása saját IP cím, forgalomirányítási (routing) táblázat és virtuális hálózati eszközök használatával.
  • ipc: Folyamatok közti kommunikáció.
  • uts: Hosztnevek szeparációja.
  • user: A felhasználó és csoport azonosítók szeparálása.

Magyarán a Linux konténeres megoldása szerinti „virtuális gépek” semmi másból nem állnak, mint megfelelően bekorlátozott, a gazda operációs rendszerből indított folyamatokból. Ennek következtében akár egyetlen programot is elindíthatunk egy „virtuális gépben”.

A Docker

A Docker közvetlen elődjének azonban a 2008-ban megjelent LXC (Linux containers) tekinthető. Az LXC a mai napig tulajdonképpen egy egyszerű parancshalmaz, amellyel ugyan konténer alapú, de teljes virtuális gépeket kezel. Ezzel szemben a Docker komoly erőfeszítéseket tett a konténerformátumok egységesítéséért és a „névtelen”, egyetlen program kedvéért létező konténerek működéséért.

Ez a fajta virtualizáció lehetővé teszi különböző szerepű „virtuális gépek” igény szerinti elindítását vagy leállítását, éppen ezért könnyebb alkalmazkodni a változó terhelésű rendszerek hullámzó kihasználtságához. A forgalmasabb időszakokra virtuális gépeket migrálhatunk, amikor már nincs rájuk szükség lekapcsolhatjuk. Ezzel például webszolgáltatások terén jelentős energiamegtakarítást érhetünk el. Az adatközpontokban a fizikai helykihasználás csökkentése miatt is érdemes a már meglévő szerverek kapacitását minél magasabb arányban kihasználni. Ha kevesebb fizikai gép van használatban, az elvégzendő karbantartási munkák száma is csökken, kevesebb a potenciális hibaforrás, meghibásodás.

Architektúrális felépítés

A virtualizáció során technikai szempontból figyelembe kell venni a használt architektúrát. Tudni érdemes, hogy az x86-os architektúra nem volt könnyen virtualizálható, hiszen 250 utasításából 17 megsérti a klasszikus feltételeket, ezért is tekinthetőek jelenkori vívmánynak a virtualizációs eljárások.

A Docker alapvetően két fő, jól elkülönülő részből áll. A Docker Engine a helyi hoszt gépen, szerveren fut, feladata a konténerek kezelése, futtatása, illetve menedzselése. A Docker Hub egy felhő alapú szolgáltatás, ami képfájlok beszerzését, publikálását teszi lehetővé, GitHub szerű funkcionális palettával rendelkezik.

docker

A fenti ábra azt mutatja, hogy a Docker milyen kapcsolatban áll a Linux kernellel, a fentiekben tárgyalt izolációk elhelyezésének megkönnyítése mellett. Látható, hogy a namespace-k és az erőforrások kiosztásáért, limitációjáért felelős cgroups is a kernel részegysége. A libcontainer a jelenlegi, az LXC driver-t váltó megoldás, gyakorlatilag nem más, mint egy egységes interfész konténerek létrehozására. A libvirt egy API, egy menedzsment eszköz a virtualizációhoz. A systemd-nspawn egy chroot-hoz hasonló megoldás, azonban ez utóbbi teljesen virtualizálja a fájlrendszer hierarchiáját, a folyamatokat, illetve az IPC alrendszereket. Gyakorlatilag minden egyes részegység a minél jobb, nagyobb fokú és biztonságosabb izoláció megvalósítását igyekszik támogatni. Az egyes konténer virtualizációs technikák napjainkban is egymás mellett fejlődnek, illetve vannak használatban.

Egy egyszerű példa

Egy konkrét használati esetet szeretnék bemutatni, statikus weboldalak elérését biztosító kiszolgálót tartalmazó konténer felépítését NGINX alapokon. A példa első ránézésre egyszerű, ám próbáltam a technológia használatához szükséges összes alapismeretet felsorakoztatni és részletezni.

Először létrehozzuk a készülő képfájl könyvtárát, az alapvető nginx.conf és global.conf konfigurációs fájlokat bemásoljuk, majd elkezdjük a Dockerfile, azaz a képfájl generálásáért felelős szkript felépítését. A műveletek sikeres lezajlásához hálózati kapcsolat szükséges.

FROM debian:latest

MAINTAINER Kovacs Akos

RUN apt-get -yqq update

RUN apt-get -yqq update && apt-get -yqq install nginx

RUN apt-get –yqq install mc && apt-get –yqq install htop

RUN mkdir -p /var/www/html/website

ADD nginx/global.conf /etc/nginx/conf.d/

ADD nginx/nginx.conf /etc/nginx/nginx.conf

EXPOSE 80

A fenti Dockerfile letölti a Debian linux legfrissebb kiadását és elkezdi felépíteni belőle a képfájlunkat. Tekintve, hogy a Debian egy hivatalos kódkönyvtárral rendelkezik a Docker Hub-on a művelet semmivel sem hordoz több kockázatot, mint egy mezei Debian telepítése. Ezt követően telepíti az NGINX-et, illetve a későbbi menedzselést megkönnyítő Midnight Commander fájlkezelő és a htop folyamatfigyelő alkalmazást, majd létrehoz egy könyvtárat és hozzáadja a korábban letöltött web szerver konfigurációs fájlokat. A konténer a 80-as porton fog kommunikálni, így ezt a szkript végén látható paranccsal kinyitjuk azt a konténerben. A konténerbeli port természetesen a hoszt gép egy másik nyitott portjának lesz megfeleltetve, amelyet a konténer futtatása során kiválaszthatunk vagy a rendszerre bízva használhatunk egy véletlenszerű, 32000 feletti portot is. A példában ez utóbbi megoldást fogjuk választani. A global.conf fájl beállítja a portot, illetve a gyökérkönyvtárat. Az nginx.conf fájlban a daemon futtatást kell szabályoznunk ahhoz, hogy alkalmas legyen a telepített NGINX egy konténeren belüli használatra is. Az ADD parancs mindkét esetben másolást végez, ám egyik esetben fájlt helyez mappába, míg a másikban egy fájl tartalmát helyezi egy másik fájlba. Az elkészült Dockerfile-ból az alábbi parancs használatával készítünk képfájlt a gazdagépünkön.

docker build -t kovacsa/webkiszolgalo .

A parancs lefutása után, ami optimális esetben 4-5 percet vesz igénybe, a docker history parancs kiadásával tájékozódhatunk a létrejött képfájl létrehozásának lépéseiről, illetve a rétegeiről. Az alábbi ábrán ezeket a rétegeket láthatjuk, a Dockerfile egyes parancsainak eredményeit.

dockerproj1

Ezzel készen is van az első saját képfájlunk, ami számtalan konténer alapjául szolgálhat. Az alábbi GitHub kódkönyvtárban elérhetők a kipróbáláshoz szükséges állományok. A következő részben egy konténer létrehozására is sor fog kerülni.

A következő részekben

A sorozat további részeiben a rendszer részletes bemutatásán át elméleti majd gyakorlati ismeretekkel felvértezve eljutunk konkrét használati esetek tárgyalásáig. Kitérőt teszünk a menedzsment eszközök bemutatásának irányába is, amelyek a hosszabb távon való üzemeltetés sarokkövei lehetnek. Természetesen mint minden rendszer, ez sem egy általános megoldás. A cikksorozat végére igyekszem a hype mögötti valós tartalmat is láthatóvá tenni.