Prosty lab do testowania netboota na Linuksie

Zapewne każdemu z Was zdarzyło się zetknąć z systemami uruchamianymi z innego nośnika niż dysk twardy komputera. Prawdopodobnie większości z Was zdarzyło się uruchomić komputer z płyty CD/DVD lub pendrive. W tym wpisie jednak chciałbym poświęcić uwagę systemom uruchamianym z sieci lokalnej, bo to one z punktu widzenia administracji średnią i większą siecią komputerową mają największy potencjał do wykorzystania.

O tym, jak taki system dokładnie się uruchamia, można poczytać w internecie. W dużym skrócie, z pomocą przychodzi tutaj PXE (Preboot eXecution Environment). Zazwyczaj taki system uruchamia się w taki sposób, że komputer:

  1. otrzymuje adres IP z serwera DHCP,
  2. razem z IP dostaje informację skąd (adres IP serwera TFTP) i jaki plik wykonywalny powinien pobrać.
  3. Tym plikiem będzie bootloader taki jak np. pxelinux.
  4. Bootloader pobierze i załaduje kernela oraz initrd.
  5. Kernel zacznie się wykonywać i… dalej już wszystko idzie podobnie jak przy starcie z dysku. 😉

W czasie przygotowywania „produkcyjnego” netboota będziemy musieli go wiele razy przetestować. Być może będziemy wykonywać takie manipulacje z jądrem tego systemu, że kernel będzie panikować, a jedynym sposobem na restart maszyny pozostanie fizyczne podejście do niej. A i tu robi się coraz dłużej, bo marnuje się kolejne sekundy przez brak przycisku reset z przodu coraz nowszych komputerów.

Wobec tego jak przetestować taki netboot – najlepiej bez odchodzenia od normalnego stanowiska pracy? Sposobów jest kilka. Ja w tym wpisie przedstawię dwa. Pierwszy – prosty i uniwersalny – z wykorzystaniem programu VirtualBox. Drugi – będzie nieco bardziej skomplikowany, ale za to w pełni konsolowy – z pomocą programu qemu. Cechą wspólną tych programów jest to, że oba służą do wirtualizacji i tak zostaną wykorzystane.

Sposób 1 – VirtualBox

Wyklikać nową maszynę wirtualną typu Linux w wersji najbardziej zbliżonej do docelowo uruchamianego systemu. Można nie tworzyć wirtualnego dysku twardego, choć – dla zachowania zgodności z rzeczywistymi przypadkami użycia – można się pokusić o jego utworzenie. Zwłaszcza, że zajmuje on symboliczną ilość miejsca, dopóki nie zostały na nim zapisane żadne dane. Po zakończeniu pracy kreatora, trzeba zmienić jeszcze kilka ustawień. Po pierwsze – należy wejść w menu „sieć”.

Ustawienia sieci w programie VirtualBox

Tutaj najważniejszym ustawieniem jest, aby karta sieciowa była mostkowana (bridge) z właściwym interfacem sieciowym. W tym konkretnym przypadku, podsieć do testów (z dostępnym serwerem DHCP, TFTP itd.) znajduje się na interface eth0.1414. Nie ma przeszkód, aby była to ta sama karta sieciowa, przez którą jesteś obecnie podłączony do sieci lokalnej. W przypadku wirtualnych kart sieciowych (takich jak tutaj – wynikających z użycia VLANów) interface w systemie gospodarza (Twoim systemie, na którym to klikasz) nie musi mieć przypisanego żadnego adresu IP – wystarczy, że będzie podniesiony link. W drugim kroku należy przejść do ustawień w części „system”.Ustawienia system maszyny wirtualnej w programie VirtualBoxTutaj najważniejszym ustawieniem jest kolejność bootowania. Ponieważ chcemy system uruchamiać z sieci, karta sieciowa (lub „sieć” – zależnie od tłumaczenia) powinna znaleźć się na samej górze tej listy. Jeśli z jakiegoś niezrozumiałego powodu na tej liście nie będzie sieci, można wspomóc się obrazem ISO płyty iPXE. Wtedy w tym oknie jako pierwsza powinna znaleźć się płyta (napęd optyczny), a na karcie „pamięć” trzeba wskazać odpowiedni plik ISO.Ustawienia "pamięć" maszyny wirtualnej w programie VirtualBoxCałość powinna wyglądać jak na powyższym zrzucie ekranu. Jeśli dokonaliśmy już wszystkich ustawień, należy je zatwierdzić przyciskiem „OK”. Wtedy program VirtualBox powinien pokazać nam takie informacje:Okno główne aplikacji VirtualBoxW tym momencie nie pozostaje nic innego jak tylko sprawdzić, czy dobrze przygotowaliśmy sobie lab/stanowisko pracy. Klikamy więc „uruchom”, po czym spodziewamy się, że maszyna wirtualna z poziomu BIOSu (lub iPXE) będzie próbowała pobrać IP od serwera DHCP. Powinno wyglądać to tak jak na poniższym zrzucie ekranu.Startująca maszyna wirtualna uruchamiana z sieci w programie VirtualBoxJeśli się to uda, a zaraz potem zobaczymy znany sieciowy bootloader, to jesteśmy w domu. 🙂

Sposób 2 – QEMU

Do operacji z qemu proponuję przygotować sobie specjalny folder, w którym będzie się trzymać wszystkie pliki związanie z uruchamianiem danej maszyny wirtualnej. Pierwszą rzeczą, która się w nim znajdzie, jest skrypt przygotowujący specjalny interface sieciowy typu TAP.

$ cat create-tap 
#!/bin/bash

# should be run as root

BR_IFACE=br-netboot
TAP_IFACE=netboot-tap
LAN_IFACE=eth0.1414
USER=mdyzio

ip tuntap add dev $TAP_IFACE mode tap user $USER
brctl addbr $BR_IFACE
brctl addif $BR_IFACE $LAN_IFACE
brctl addif $BR_IFACE $TAP_IFACE
ip link set $BR_IFACE up
ip link set $LAN_IFACE up
ip link set $TAP_IFACE up

Skrypt ten tworzy bridge o nazwie zapisanej w zmiennej BR_IFACE oraz urządzenie TAP dostępne dla użytkownika USER o nazwie zapisanej w TAP_IFACE (obie te nazwy są zupełnie nowymi nazwami, których nie powinno być jeszcze w systemie), a na koniec podnosi wszystkie interface’y pośredniczące w ruchu sieciowym od maszyny wirtualnej do świata (czyli również LAN_IFACE, jeśli jeszcze nie był podniesiony). Skrypt wystarczy wykonać tylko raz po każdym uruchomieniu systemu, a przed startem pierwszej maszyny wirtualnej, którą chcemy uruchamiać z sieci.

Drugą rzeczą, która przyda nam się w tym folderze, to – oczywiście – skrypt uruchamiający qemu z odpowiednimi parametrami. Nic nie stoi na przeszkodzie, aby qemu za każdym razem uruchamiać pisząc to polecenie od zera (jak i konfigurować sieć jw.), ale jest to dużo wygodniejsze nie musieć pamiętać o wszystkich przełącznikach w poleceniach i zastanawiać się, czemu tym razem nie działa, a np. wczoraj/tydzień wcześniej działało (żeby na końcu się przekonać, że jednak czegoś zapomniało się wykonać).

$ cat qemu
#!/bin/bash

qemu-system-x86_64 \
   -m 512 -boot n \
   -net nic -net tap,ifname=netboot-tap,script=no,downscript=no \
   -enable-kvm

Nic zaskakującego – uruchamiamy qemu do emulacji x86_64 z 512 MB RAM dla maszyny wirtualnej, mówimy maszynie, aby się uruchamiała tylko z sieci (-boot n). W drugiej linijce flag dodajemy interface sieciowy, który będzie podłączony do stworzonego wcześniej urządzenia typu TAP (ifname=netboot-tap), oraz tenże interface nie spowoduje wykonania żadnych skryptów ani przy włączaniu wirtualki (script=no), ani przy jej wyłączaniu (downscript=no). Domyślnie qemu przy włączaniu i wyłączaniu maszyny wykonałoby skrypty odpowiednio /etc/qemu-ifup i /etc/qemu-ifdown. Ostatnia linijka włącza akcelerację sprzętową dla wirtualizacji (z pomocą KVM). Jeśli z jakiegoś powodu nie działa u Ciebie KVM, możesz usunąć tę linijkę i backslash kończący poprzednią – niestety, brak wsparcia sprzętowego mocno odbije się na wydajności całej maszyny wirtualnej.

Po wykonaniu powyższych kroków, mamy już wszystko przygotowane, aby uruchomić nasz skrypt qemu. Spodziewanym efektem jest pojawienie się okienka jak na poniższym zrzucie ekranu, w którym widać będzie maszynę wirtualną próbującą przez iPXE pobrać IP z DHCP, a następnie uruchomić dzięki temu system operacyjny.QEMU - uruchamiająca się maszyna wirtualna netboot

Sposób 2.1 – QEMU bez okienek

Bardzo specyficzny use case, który w moim przypadku był połączeniem kilku okoliczności:

  • praca zdalna – forwardowanie Xów (okienek) ze zdalnej maszyny roboczej mocno obciąża łącze,
  • częste zmiany w okolicach kernela i initrd – potrzebowałem przetestować zachowanie skompilowanego na boku jądra z opcjami innymi niż te domyślne dystrybucji, a także przetestować działanie systemu na rozszytym (co – nawiasem mówiąc – w nowych Debianach stało się trudniejsze niż było wcześniej), edytowanym i zszytym ponownie initrd dostarczanym z dystrybucją. W dodatku te operacje na kernelu lub initrd wykonywane były na tym samym sprzęcie, na którym uruchamiany był VirtualBox lub QEMU, więc poszukiwane było wygodniejsze rozwiązanie – takie, które nie będzie wymagało ciągłego kopiowania w/w plików, a jednocześnie pozwoli przetestować zachowanie systemu – zwłaszcza we wczesnych fazach jego uruchamiania.
$ cat qemu
#!/bin/bash

qemu-system-x86_64 \
   -m 512 -boot n \
   -net nic -net tap,ifname=netboot-tap,script=no,downscript=no \
   -enable-kvm \
   -nographic \
   -kernel bzImage \
   -initrd initrd.img-4.9.0-4-amd64 \
   -append "ip=dhcp root=/dev/nfs nfsroot=10.0.0.1:/vol/nfsboot/rootfs aufs=tmpfs console=ttyS0"

Co się zmieniło? Dopisałem flagę -nographic, następnie podałem plik z kernelem, którego chciałbym uruchomić, initrd i z jakimi parametrami ma zostać ten kernel uruchomiony. Najciekawszy jest ostatni, który powoduje, że kernel uruchamia konsolę ttyS0, czyli konsolę szeregową. Można dokonywać interakcji z nią przez standardowe wejście i wyjście QEMU. Jeśli z jakiegoś powodu zajdzie potrzeba szybkiego terminowania pracy wirtualki, można zrobić to w tej samej konsoli – wystarczy dostać się do monitora QEMU przez skrót klawiaturowy ctrl+a, a potem c. Następnie wystarczy wpisać polecenie quit. Można też krócej: ctrl+a x – od razu terminuje QEMU. Przestrzegam tylko użytkowników screena, iż w celu wysłania ctrl+a do programu, muszą oni wcisnąć ctrl+a a.

VirtualBox i QEMU to potężne narzędzia i – jak zobaczyliśmy przed chwilą – mogą być przydatne przy pracach nad systemami uruchamianymi z sieci. Oczywiście, nie jest to nawet ćwierć ich możliwości, więc bardzo zachęcam do zgłębiania dokumentacji i stawiania sobie coraz większych wyzwań do realizacji z ich pomocą. Zwłaszcza, że wirtualizacja jest czymś, czego się intensywnie używa na świecie i nie zanosi się na to, żeby nastał moment, w którym świat miałby się od niej odwrócić.

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *