Virtuális GNU/Linux tesztrendszer (QEMU-val)

Rövid ismertető

Linux kernellel kapcsolatos fejelsztéseknél fontos, hogy a változatásainkat gyorsan tudjuk tesztelni. A saját, fejlesztői gépünkön (host) való tesztelés lassú:

  • Letöltünk egy új kernel verziót, vagy módosítjuk a kódot
  • Fordítjuk a kernelt
  • Telepítjük a kernelt (felülírjuk az előzőt vagy szimbolikus linket átállítjuk az új kernel imagere)
  • Újraindítjuk a gépünket
  • Ha a módosítás nem rontja el a kernelt (kernel panic, bootloop, stb.), megvárjuk ameddig betölt
  • Újrakezdjük/új módosítást csinálunk a kódban

Ezek közül a lépések közül időigényes a kernel fordítás, ha csak egy részét módosítjuk, akkor gyorsabb mert nem kell a teljes forrást újrafordítania mindig. Viszont az kernel image-t monden esetben meg kell, hogy csinálja, ez eltart egy rövid ideig. Sajnos ezen nem lehet spórolni. Sajnos az újraindítás géptől függően sok ideig eltarthat. Legrosszabb esetben valamilyen hiba miatt nem tud majd az új kernellel bebootolni a számítógép. Ekkor diszribúciótól függően elképzelhető, hogy manuálisan kell kiválasztani egy korábbi, még működő kernel verziót, ha ez lehetséges. Még ha siekresen betölt és lefuttatjuk a teszteket amivel ellenőrizzük, jók-e a módosításaink, akkor is időbe telik eljutni idáig. Ha a módosításaink a kódban rosszak és javítanunk kell, akkor megint sok idő, mire újra eljutunk az ellenőrző lépésig.

Ez a rövid leírás lépésről lépésre végigvezet egy olyan tesztkörnyezet elkészítésén, amivel virtuális gépen tudjuk tesztelni a kernelen végzett módosításainkat.

A leírásban használt fejlesztői gépen Ubuntu 18.04-es verzió futott. A leírt módszer más gépeken is működhet, viszont a felhasznált csomagok neve, verziója, hibaüzenetek, a parancsok paraméterezése, stb. eltérhet.

Ez a leírás csak iránymutatásul szolgál, elképzelhető, hogy a leírtaknál léteznek kényelmesebb, könnyebben konfigurálható megoldások is. A leírásban ismertetett módszer nem túl egyszerű, de jól követhető és maximálisan konfigurálható.


A leírásban használt fogalmak ismertetése

  • Host: host rendszer, host gép. A gazda gépet/operációsrendszert fogjuk így hivatkozni. Ez a gép, amin a fejlesztés folyik. A leírás elkészítéséhez egy 4 magos (8 szálas) processzorral, 16Gb RAM-al felszerelt gép volt felhasználva, Ubuntu 18.04 operációsrendszerrel.

  • Guest: guest rendszer, vendég operációsrendszer. Röviden így fogjuk hivatkozni a teszteléshez használt gépet/operációsrendszert. Ezt a rendszert virtualizációs eljárással futtatjuk a host gépen, egyszerre több guest rendszert is futtathatunk.

  • QEMU: virtualizációs szoftver, ami képes gépeket emulálni (többféle architektúra támogatott). Ez a virtuális gép a kernel és a szoftverek számára úgy fog tűnni, mintha valós hardver lenne. A QEMU weboldala: https://www.qemu.org/

Függőségek beszerzése

A kernel fordításhoz szükség van néhány csomagra. Mindegyk elérhető az Ubuntu hivatalos tárolóiban.

sudo apt install git fakeroot build-essential ncurses-dev xz-utils libssl-dev bc bison flex libelf-dev

A QEMU és a függőségeinek a telepítése

sudo apt install qemu-kvm libvirt-clients libvirt-daemon-system bridge-utils virt-manager cloud-utils

Kernel kód beszerzése

Több lehetőség is van, a hivatalos oldal a https://www.kernel.org/ innen elérhető több verzió is betömörített formában. Ha egy fix verzióval akarunk dolgozni, ez elég. Lehet olyan is, hogy egy dolgot több kernel verzióval is ki szeretnénk próbálni, ilyenkor jobban megéri git-el letölteni az adott verziót, mert utána egyszerűen lehet váltani más verziókra egy paranccsal.

git clone -b v4.20 https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git

Ez letölti a kernel 4.20-as verziójának a forráskódját. Ha később váltani akarunk 5.0-ra elég kiadni a következő parancsot:

git checkout -b v5.0

Operációs rendszer beszerzése

Rengeteg lehetőség van, mert bármelyik GNU/Linux disztribúció futtatható QEMU virtuális gépként. Lehet Ubuntu-t telepíteni, de már előre elkészített lemezfájlok is betölthetőek. Szerver környezethez szánt Ubuntu 18.04 lemezek érhetőek el itt: https://cloud-images.ubuntu.com/bionic/current/

A leírásban a https://cloud-images.ubuntu.com/bionic/current/bionic-server-cloudimg-amd64.img lemezképet fogjuk használni. Ez egy minimális, csak a legszükségesebb könyvtárakat és programokat tartalmazó szerverekre szánt Ubuntu verzió, telepítést nem igényel, minden fontosabb beállítást cloud-init szolgáltatással állítunk majd be.

A cloud-init egy szolgáltatás, ami megtalálható a legtöbb szerverre szánt disztribúcióban. A virtuális gép indulásakor egy init fájl alapján minden beállítást elvégez. Például van a lemezkép egy működő Ubuntuval, amin nincsenek felhasználók, de a cloud-init létrehoz rajta a megadott bejelentkezési adatokkal felhasználót, így később be tudunk rá jelentkezni (jelszóval vagy pritvát kulccsal).

cloud-init lemezkép létrehozása

Készítsünk egy fájlt, ami tartalmazza a bejelentkezéshez szükséges adatokat, más konfigurációs beállításokat. A neve bármi lehet, ebben a leírásban az init.conf. A tartalma legyen a következő:

#cloud-config
hostname: ubu 
users:
  - name: myusername
    ssh-authorized-keys:
      - ssh-rsa AAAAB3Nz[...]34twdf/ myusername@pc 
    sudo: ['ALL=(ALL) NOPASSWD:ALL']
    groups: sudo
    shell: /bin/bash

Az ssh-rsa a publikus kulcsunk (a példában pár karakter kimaradt), ezt hozzáadja a .ssh/authorized_hosts fájlhoz a virtuális gépben így be lehet ssh-val jelentkezni. Ha nincs a host gépen kulcspárunk, akkor ssh-keygen-el tudunk generálni, és a publikus kulcs az ~/.ssh/id_rsa.pub fájlban lesz ha mást nem mondunk.


Az init fájlból készítenünk kell egyet init lemezképet. Ezt majd a virtuális gépnek fogjuk megadni.

cloud-localds init.img init.conf

A virtuális gép indításakor a letöltött Ubuntu lemezképre új adatok lesznek írva. Ha nem szeretnénk az eredeti lemezképet felülírni érdemes egy új lemezképet csinálni a letöltött “tetején” (snapshot image). A továbbiakban ide lesz írva minden módosításunk és az új fájlok is.

qemu-img create -f qcow2 -b bionic-server-cloudimg-amd64.img ubuntu.img

Próbáljuk ki, hogy feláll-e a rendszer:

sudo qemu-system-x86_64 \
-hda ubuntu.img \
-hdb init.img \
-m 2048 \
--nographic \
--enable-kvm \
-netdev user,id=net0,hostfwd=tcp::2222-:22 -device e1000,netdev=net0

Ennek hatására be kell töltsön a gép. Bejelentkezni ssh-val lehet:

ssh myusername@127.0.0.1 -p 2222

Saját kernel használata

A gép elindul, be lehet jelentkezni de az alap, Ubuntu lemezképbe csomagult kernel verziót használja. QEMU-ban lehetőség van saját kernel megadására is. Ezt a host gépen fordítjuk és adjuk meg a guest gépnek.

Fordítsuk le a kernel kódot.

cd linux/
make x86_64_defconfig
make kvmconfig
make -j `nproc --all`

Ha lefordult, a kernel lemezkép a arch/x86/boot/bzImage helyen lesz. Most indíthatjuk a gépet úgy, hogy ezt a lemezképet használja (a példa parancsban teljes elérési úttal szerepel).

sudo qemu-system-x86_64 \
-kernel /home/myusername/linux/arch/x86/boot/bzImage \
-append "root=/dev/sda1 single console=ttyS0 systemd.unit=graphical.target" \
-hda ubuntu.img \
-hdb init.img \
-m 2048 \
--nographic \
--enable-kvm \
-netdev user,id=net0,hostfwd=tcp::2222-:22 -device e1000,netdev=net0

A virtuális gépre belépve ellenőrizzük a kernel verziót:

uname -r

QEMU 2.12 és újabb verzióknál lehetőség van rövidíteni a hálózati kártya paramétert. A -netdev user,id=net0,hostfwd=tcp::2222-:22 -device e1000,netdev=net0 helyett elég a -nic user,hostfwd=tcp::2222-:22