W wielu firmach i innych miejscach (np. na Uniwersytetach) zyskały ostatnio na popularności karty GPU (np. Nvidia V100). Karta taka może być wykorzystana na wiele sposobów, do obliczeń z wykorzystaniem CUDA ale i do wirtualizacji (NVIDIA RTX Virtual Workstation). Dzięki wsparciu dla vGPU, możemy taką kartę podzielić zgodnie z pożądanym profilem (o czym później) i uruchomić do 32 wirtualnych maszyn (per fizyczna karta) gdzie każda będzie miała możliwość działania z własnym procesorem GPU. W tym artykule chciałbym dokładnie omówić dwa aspekty, pierwszym jest fizyczne przekazanie karty (jednej lub wielu) do VM (GPU passthrough) a drugim wykorzystanie vGPU. W obu przypadkach odbiorcą końcowym będzie VM uruchomiona w CloudStack, aczkolwiek pewne techniki tu opisane można użyć w dowolnym IaaS (np. Proxmox, Openstack, vSphere i inne).
Pierwszym krokiem jest przygotowanie serwera, kroki opisane niże są takie same dla PCI passthrough jak i dla vGPU. Zaczynamy od włączenia IOMMU, jest to kluczowa faza, bez wsparcia dla IOMMU nie będziemy mogli wyizolować karty PCI w celu jej przekierowania do VM. Generalnie w BIOS lub UEFI różnych producentów jest to różnie opisane, mamy przeważnie dwie funkcje, pierwszą jest włączenie wirtualizacji a drugą włączenie IOMMU. W Supermicro dla przykładu te dwie opcją nazywają się Intel Virtualization Technology i Intel VT for Directed I/O (VT i VT-d):
Po restarcie wydajemy polecenie cat /var/log/messages* | grep –E “DMAR|IOMMU” lub dmesg | grep –E “DMAR|IOMMU”, spodziewany efekt to komunikat IOMMU Enabled:
W kolejnym kroku musimy wyłączyć natywny sterownik Nvidia Nouveau który jest częścią kernela. Robimy to w dwóch miejscach, jednym jest utworzenie pliku /etc/modprobe.d/nvidia.conf z zawartością:
Podobną zawartość dodajemy do /etc/default/grub :
Następnie musimy wygenerować nowe obrazy initrd, warto to zrobić po wcześniejszym zaktualizowaniu systemu i restarcie, wydajemy następujące polecenia:
Następnie wykonujemy restart systemu. W tym momencie mamy przygotowany serwer do dalszych kroków, możemy sobie dla pewności zweryfikować obecność karty lub kart NVIDIA w systemie:
W tym konkretnym przypadku mamy cztery karty Nvidia Tesla V100 spięte SLI, więc jest to bardzo poważna koparka bitcoin, tfu oczywiście serwer do poważnych obliczeń naukowych
Zacznijmy od PCI passthrought (GPU jest niczym innym jak kartą PCI) za pomocą VFIO. Całość konfiguracji będzie dotyczyła CentOS 7 ale generalnie w całości jest bardzo podobna na pozostałych systemach Linux. Tutaj dodatkowo musimy przekazać karty pod zarządzanie sterownikiem VFIO, na rysunku powyżej widać parametry Vendor-ID i Device-ID (druga kolumna od prawej), te dane musimy wpisać do pliku /etc/modprobe.d/vfio.conf :
W przypadku pojedynczej karty wpisujemy to raz, w przypadku większej ilości kart tyle razy ile ich mamy (nawet jeśli te ID są takie same). Restartujemy serwer i szukamy wpisów o vfio w /var/log/messages po restarcie. Możemy teraz przejść do CloudStack i generalnie do KVM. Wirtualna maszyna jest w całości opisana plikiem XML, przekazanie jej urządzenia typu GPU jest niczym innym jak uzupełnieniem jej konfiguracji o definicję takiego urządzenia. Dla moich czterech kart Tesla wygląda to tak:
Nie jest to skomplikowane, bus=0x61 odpowiada adresowi z lspci (rysunek powyżej, pierwsza kolumna, pierwszy wiersz), alias i address to definicja PCI wewnątrz VM. Dla czterech kart definicję musiałem rozbić na dwie części ze względu na ograniczenie pola do wprowadzania danych w CloudStack. Przekazanie tej konfiguracji w VM w CloudStack wymaga użycia opcji extraconfig dla istniejącej VM. Możemy to zrobić standardowo używając CloudMonkey (CMK):
Ten dziki ciąg znaków to wyżej wymieniona definicja urządzeń przekonwertowana do url encode (API działa przez http, informacja musi być zgodna ze standardem). W wersji CloudstaCk 4.15 i wyżej, za pomocą nowego UI Primate możemy to samo dodać do VM w prostszy sposób, dodając opcję extraconfig-1 w ustawieniach VM. W przypadku pojedynczej karty GPU wystarczy extraconfig-1, ja musiałem cztery karty rozbić na dwa wpisy:
Dalej instalujemy w VM sterowniki zgodnie z dokumentacją Nvidia, instalator sam dodaje odpowiednie wpisy blokujące sterownik Nouveau. Spodziewany efekt to poprawnie działające polecenie nvidia-smi w VM:
I to w zasadzie tyle, możemy kopać, tfu, prowadzić ciężkie obliczenia
Wyżej opisana konfiguracja dotyczy najprostszej formy przekazania GPU do VM, teraz zajmiemy się tą ciekawszą, Nvidia umożliwia podzielenie takiej karty na vGPU. Oczywiście mam na myśli karty które to umożliwiają, takie jak Tesla V100. Ta funkcja jest niestety licencjonowana, licencje są bardzo tanie (Nvidia RTX Virtual Workstation kosztuje $400), można też wygenerować sobie czasową licencję na 90 dni. Dodatkowo musimy też zainstalować serwer licencji, oprogramowanie jak i licencje pobieramy z Portalu Licencji Nvidia. Na serwerze (z właczonym iommu i zablokowanym sterownikiem nouveau) instalujemy sterowniki Nvidia, spodziewany efekt po restarcie to działające polecenie nvidia-smi jak na rysunku powyżej. Dodatkowo czy prawidłowo jest uruchomiony sterownik Nvidia VFIO:
Teraz musimy zdecydować jakiego profilu GPU chcemy użyć, jest to o tyle istotne, że na raz może być użyty tylko jeden. Na rysunku powyżej nvidia-* oznacza właśnie dostępne profile, do każdego katalogu można wejść i przeczytać plik description gdzie dokładnie są opisane właściwości danego profilu. My użyjemy nvidia-358 (profil o oznaczeniu 8Q ):
Profil ten jest o tyle istotny, że wspiera CUDA. Proces generowania vGPU jest prosty:
Przygotowanie XML z urządzeniem też jest bardzo podobne (i co ważne, możemy użyć wielu vGPU w jednej VM na tej samej zasadzie, jak ja czterech kart fizycznych):
W CloudStack postępujemy dokładnie tak jak zostało to opisane wyżej, w VM instalujemy sterowniki oraz CUDA, spodziewany efekt to oczywiście wszystko działające poprawnie:
Na koniec jeszcze słowo na temat konsoli. VM generalnie startuje z emulowaną kartą grafiki QLX i ta karta startuje jako pierwsza. Aby wyłączyć QLX, musimy odpowiednio spreparować plik urządzenia GPU, musimy tylko pamiętać, aby zainstalować wcześniej sterowniki Nvidia, bez tego na konsoli będziemy mieli komunikat o braku zainicjalizowanych sterowników dla karty graficznej. Plik XML wygląda tak:
I to w zasadzie tyle, jeśli macie pytania w tym temacie to proszę o komentarze.
Tym artykułem chciałbym zaanonsować swój powrót do pisania na blogu, przerwa była długa ale ostatnimi czasy jestem bardzo zajęty przy kolejnych projektach.