Wirtualizacja zagnieżdżona na VPS: czy zadziała Proxmox?
Większość dostawców VPS blokuje flagę vmx. Sprawdź dostępność wirtualizacji komendą kvm-ok. Dowiedz się, jak rozpoznać błąd KVM i czy Twój serwer obsłuży instancje Proxmox.
Krótka odpowiedź
Wirtualizacja zagnieżdżona to hiperwizor działający wewnątrz maszyny wirtualnej: Twój VPS jest już gościem, a Ty chcesz, aby hostował własne instancje. Rozwiązanie to działa tylko wtedy, gdy hiperwizor dostawcy celowo udostępnia rozszerzenia wirtualizacji procesora dla Twojej instancji. Sprawdź /proc/cpuinfo pod kątem flagi vmx (Intel) lub svm (AMD). Jeśli żadna z nich się nie pojawia, żadna konfiguracja wewnątrz VPS nie rozwiąże problemu.
Najpierw wyjaśnienie oczekiwań: Docker nie potrzebuje żadnego z tych rozwiązań. Kontenery współdzielą jądro systemu Twojego VPS i nigdy nie korzystają z /dev/kvm. Jeśli rzeczywistym celem jest „uruchomienie kilku usług w kontenerach na serwerze”, masz już wszystko, czego potrzebujesz. Zagnieżdżanie jest istotne, gdy potrzebujesz drugiego jądra, laboratorium Proxmox, gościa Windows, mikro-VM Firecracker, emulatora Androida, środowiska testowego Kubernetes opartego na rzeczywistych maszynach wirtualnych lub runnerów CI, które uruchamiają obrazy VM.
Co jest faktycznie zagnieżdżane
Trzy warstwy:
- L0, hiperwizor dostawcy, na fizycznym sprzęcie. Brak dostępu do tej warstwy.
- L1, Twój VPS. Dla L0 jest to tylko gość.
- L2, maszyna wirtualna uruchamiana wewnątrz VPS.
Wirtualizacja sprzętowa to VT-x (flaga vmx) oraz EPT w przypadku procesorów Intel, lub AMD-V / SVM (svm) oraz RVI/NPT w przypadku AMD. Hiperwizor używa tych instrukcji, aby przejść w tryb gościa i umożliwić procesorowi jednoczesną obsługę dwóch tablic stron.
Żadne z tych rozwiązań nie zostało zaprojektowane jako reentrant, więc zagnieżdżanie jest emulowane: gdy L1 wykonuje instrukcję VMX, taką jak VMLAUNCH lub VMRESUME, następuje przechwycenie (trap) do L0, który w imieniu L1 utrzymuje struktury cieniowe (shadow structures) dla L2. Na procesorach z funkcją VMCS shadowing, instrukcje VMREAD i VMWRITE poziomu L1 mogą być obsługiwane bez wyjścia z trybu gościa, co eliminuje znaczną część ruchu, ale nie całość. KVM radzi sobie z tym dobrze, jednak to L0 wykonuje dodatkową pracę przy każdym wyjściu, dlatego dostawca musi wyrazić zgodę na tę funkcjonalność.
Gdy L0 to KVM, aby przyspieszyć działanie L2, muszą zostać spełnione dwa warunki:
- Moduł KVM w L0 jest załadowany z parametrem
nested=1. - L0 udostępnia VPS model procesora, który przenosi odpowiednią flagę:
<cpu mode='host-passthrough'/>w libvirt,cpu: hostw Proxmox,-cpu hostw surowym QEMU. Generyczny emulowany model (qemu64,kvm64) ukrywavmx, nawet jeśli zagnieżdżanie jest włączone globalnie.
Inne hiperwizory posiadają własne przełączniki. Hyper-V na przykład emuluje rozszerzenia wirtualizacji dla zagnieżdżonego hiperwizora wewnątrz swoich maszyn wirtualnych, ale tylko w tych, w których zagnieżdżanie zostało włączone indywidualnie.
Sprawdź swój VPS w jedną minutę
# 1. Are you in a VM, and under what?
systemd-detect-virt # kvm, vmware, xen, microsoft, or "none" on metal
# 2. Does the CPU expose the extensions to you?
grep -o -E 'vmx|svm' /proc/cpuinfo | sort -u
lscpu | grep -i -E 'virtual|hypervisor'
# 3. The definitive check
sudo apt update && sudo apt install -y cpu-checker
kvm-ok
# 4. The device node the whole stack depends on
ls -l /dev/kvmUżyteczna instancja wyświetla vmx lub svm, kvm-ok zwraca KVM acceleration can be used, a /dev/kvm istnieje jako root:kvm w trybie 660. Jeśli flaga jest obecna, ale węzeł urządzenia nie, załaduj moduł ręcznie i odczytaj dziennik jądra:
sudo modprobe kvm_intel # or kvm_amd
sudo dmesg | tail -n 20Jeden plik jest stale cytowany i powszechnie błędnie interpretowany:
cat /sys/module/kvm_intel/parameters/nested # Y or NWewnątrz Twojego VPS jest to ustawienie Twojego modułu KVM i określa ono, czy gość L2 może zagnieździć trzeci poziom. Nie mówi ono nic o tym, czy L0 włączyło zagnieżdżanie dla Ciebie; /proc/cpuinfo oraz kvm-ok odpowiadają na to pytanie. Parametr nested to przełącznik, który ustawiasz na maszynie, której jesteś pełnym właścicielem:
echo 'options kvm_intel nested=1' | sudo tee /etc/modprobe.d/kvm-nested.conf
sudo modprobe -r kvm_intel && sudo modprobe kvm_intelUsunięcie modułu jest odrzucane, gdy działa maszyna wirtualna, dlatego najpierw należy wyłączyć maszyny gościa. Jeśli jest to host Proxmox, włączenie zagnieżdżonej wirtualizacji w Proxmox VE 9 obejmuje tę samą zmianę w modprobe.d oraz ustawienie cpu: host dla każdej maszyny wirtualnej, dzięki któremu flaga jest widoczna wewnątrz maszyny gościa.
Dlaczego większość dostawców VPS wyłącza tę funkcję
- Migracja na żywo. Udostępnienie
vmxoznacza ekspozycję modelu procesora posiadającego tę flagę. Gość zależny od tych funkcji procesora nie może zostać bezpiecznie przeniesiony na maszynę, której procesor ich nie posiada. Host, który opróżnia węzły poprzez migrację klientów, traci tę możliwość w momencie włączenia zagnieżdżonej wirtualizacji. - Powierzchnia ataku. Ścieżki zagnieżdżonego VMX/SVM należą do najbardziej złożonych fragmentów kodu w warstwie wirtualizacji jądra i posiadają odpowiednią historię podatności CVE.
- L0 może nie być KVM. Jeśli
systemd-detect-virtzwracavmware,xenlubmicrosoft, zasady zagnieżdżania są narzucane przez ten stos, a nie przez KVM.
Brak flagi na instancji? Należy skontaktować się z pomocą techniczną (niektórzy dostawcy włączają ją dla poszczególnych maszyn wirtualnych), wybrać plan z udokumentowaną obsługą zagnieżdżania lub przenieść się na serwer dedykowany. Dalsza część poradnika zakłada posiadanie uprawnień root na maszynie, na której flaga jest widoczna.
Uruchamianie gościa L2 przy użyciu libvirt
sudo apt install -y qemu-system-x86 libvirt-daemon-system virtinst ovmf
sudo systemctl enable --now libvirtd
sudo usermod -aG libvirt,kvm "$USER" # log out and back in
virt-install \
--name guest1 \
--memory 2048 \
--vcpus 2 \
--cpu host-passthrough \
--disk path=/var/lib/libvirt/images/guest1.qcow2,size=20,format=qcow2,bus=virtio \
--network network=default,model=virtio \
--os-variant debian13 \
--location https://deb.debian.org/debian/dists/trixie/main/installer-amd64/ \
--graphics none \
--console pty,target_type=serial \
--extra-args 'console=ttyS0,115200n8'Sesja graficzna nie jest wymagana. Instalacja szeregowa trwa pewien czas, dlatego należy ją uruchomić wewnątrz trwałej powłoki: ten sam przepływ pracy w tmux, który utrzymuje sesje Claude Code na VPS pozwala zachować konsolę virt-install po zerwaniu połączenia SSH. Jeśli --os-variant debian13 zostanie odrzucone, oznacza to, że osinfo-db jest starsze niż wydanie; należy uruchomić osinfo-query os i wybrać istniejącą nazwę. --cpu host-passthrough przekazuje vmx do wnętrza L2, co jest wymagane tylko wtedy, gdy L2 musi z kolei pełnić rolę wirtualizatora. Należy zabezpieczyć rozruch gościa za pomocą virsh autostart guest1.
Magistrala virtio dla dysku i karty sieciowej nie jest elementem dekoracyjnym: emulowane urządzenia IDE oraz e1000 wywołują pułapki do hiperwizora znacznie częściej niż kolejki virtio. W przypadku zagnieżdżenia, wyjście (exit), którego L0 nie może obsłużyć samodzielnie, jest przekazywane do L1, gdzie jego obsługa może wywołać kolejne wyjścia.
Sieć: element pomijany w poradnikach
Twój VPS posiada jeden publiczny adres IP i znajduje się za infrastrukturą filtrującą nieznane adresy MAC. Wynikają z tego dwie konsekwencje.
Mostkowanie gości L2 do sieci publicznej zazwyczaj nie działa. Umieszczenie br0 na publicznej karcie sieciowej i nadanie gościowi własnego adresu MAC spowoduje wysłanie zapytań ARP, na które nie otrzymasz odpowiedzi; przełącznik dostawcy odrzuca ramki pochodzące z adresu MAC, którego nie przydzielił. Jeśli to jest Twój objaw, przerwij debugowanie mostka; tak działa ten mechanizm.
Zastosuj sieć NAT. libvirt dostarcza default: virbr0, 192.168.122.0/24, dzierżawy dnsmasq, ruch wychodzący działa natychmiast. W przypadku ruchu przychodzącego należy zakończyć TLS na L1 i przekierować go przez proxy; ścieżki certyfikatów poniżej pochodzą z wydawania certyfikatu Let's Encrypt za pomocą Certbot na Nginx:
server {
listen 443 ssl;
server_name lab.example.com;
ssl_certificate /etc/letsencrypt/live/lab.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/lab.example.com/privkey.pem;
location / {
proxy_pass http://192.168.122.50:8080;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}Najpierw nadaj gościowi statyczną dzierżawę (virsh net-edit default), aby adres w pliku proxy_pass pozostał niezmienny.
Interfejsy zarządzania powinny pozostać niedostępne z Internetu: VNC na porcie 5900 oraz interfejs webowy Proxmox na porcie 8006 powinny działać na interfejsie loopback, osiągalne przez tunel SSH (ssh -N -L 8006:127.0.0.1:8006 you@your-vps) lub poprzez własny serwer WireGuard VPN na VPS, co sprawia, że cała podsieć gości 192.168.122.0/24 znajduje się w zasięgu jednego przeskoku prywatnego. Utrzymuj zaporę sieciową w restrykcyjnej konfiguracji, sudo ufw allow 22,80,443/tcp, nic więcej. Jeśli goście tracą łączność wychodzącą zaraz po włączeniu ufw, typową przyczyną jest DEFAULT_FORWARD_POLICY="DROP" w pliku /etc/default/ufw; ustaw tę wartość na ACCEPT i przeładuj ufw.
Proxmox na VPS
Proxmox VE 9 opiera się na systemie Debian 13, dlatego instalację na VPS z systemem Debian przeprowadza się poprzez dodanie repozytorium pve-no-subscription oraz pakietu proxmox-ve. Należy pobrać linie dotyczące repozytorium oraz klucza z aktualnej dokumentacji Proxmox; adres URL skopiowany ze starego wpisu na blogu spowoduje błąd instalacji. Kwestię zasadności instalacji Proxmox na wynajętym sprzęcie warto rozważyć przed poświęceniem wieczoru na konfigurację sieci, a porównanie kosztów i możliwości serwera Proxmox w domu oraz wynajętego VPS zawiera zestawienie, w którym obliczenia dotyczące zasilania i sprzętu zostały już wykonane.
Instalacja pakietów nie stanowi głównego wyzwania. Proxmox wymaga interfejsu vmbr0 zmostkowanego z fizyczną kartą sieciową, co prowadzi bezpośrednio do problemów z filtrowaniem adresów MAC opisanych powyżej. Rozwiązaniem działającym na VPS jest zastosowanie interfejsu vmbr0 typu NAT lub routowanego, bez przypisanej karty fizycznej, z maszynami wirtualnymi w prywatnej podsieci oraz regułami DNAT lub reverse proxy na hoście dla usług publicznych. W przypadkach, gdy usługi wystawione na zewnątrz są kontenerami, a nie maszynami wirtualnymi, Traefik obsługujący wiele aplikacji z jednego pliku Docker Compose realizuje to samo zadanie routingu z automatyczną obsługą certyfikatów. Przed przystąpieniem do prac należy wykonać snapshot /etc/network/interfaces: błędna definicja mostka może spowodować utratę dostępu do maszyny, do której konsoli użytkownik może nie mieć wglądu.
Wydajność w ujęciu rzeczywistym
Wirtualizacja zagnieżdżona jest wolniejsza niż jednostopniowa, a mechanizm tego zjawiska jest konkretny: koszt obciąża wyjścia z trybu gościa (exits) oraz translację adresów, a nie standardowe instrukcje. Przy aktywnych funkcjach EPT/NPT, L0 scala tablice stron L1 dla L2 oraz własne tablice w jedną tablicę cieniową (shadow table), dzięki czemu trafienie w TLB odbywa się z prędkością sprzętową. Pudło w TLB generuje wyższy koszt: sprzęt przeszukuje jednocześnie tablicę stron gościa oraz tablicę cieniową, a każda zmiana wprowadzona przez L1 w jej własnych tablicach wymusza wyjście, aby L0 mogło zsynchronizować tablicę cieniową. Kosztowne stają się operacje powodujące opuszczenie trybu gościa, takie jak I/O, przerwania zegara, MMIO oraz przerwania międzyprocesorowe, ponieważ wyjście z L2 jest obsługiwane przez L0 i może być przekazywane z powrotem przez L1. Zadania obciążające CPU z małym zbiorem roboczym działają niemal z natywną prędkością; duże zbiory robocze w pamięci odczuwają skutki pudeł w TLB, a operacje zdominowane przez syscall, pakiety sieciowe i dyskowe I/O odczuwają wpływ warstw wirtualizacji.
Zalecenie: stosować urządzenia virtio wszędzie, gdzie to możliwe. Plik qcow2 znajduje się na dysku już zwirtualizowanym przez dostawcę, co tworzy dwie nałożone na siebie warstwy thin-provisioningu, gdzie cache=none na dysku gościa zapobiega przechowywaniu tych samych bloków w dwóch pamięciach podręcznych stron jednocześnie. W tym miejscu nie podano wyników benchmarków: należy zmierzyć wydajność własnego obciążenia na własnej instancji.
Tryby awarii i komunikaty błędów
INFO: /dev/kvm does not exist / KVM acceleration can NOT be used z kvm-ok. Moduł nie jest załadowany lub flaga nie jest udostępniona. W pierwszej kolejności sprawdź /proc/cpuinfo.
kvm: disabled by bios w dmesg. Na serwerze fizycznym należy przełączyć opcję VT-x/SVM w oprogramowaniu układowym (firmware). Wewnątrz VPS oznacza to, że L0 nie przekazuje rozszerzeń i żadna konfiguracja wewnątrz systemu gościa tego nie zmieni.
modprobe: ERROR: could not insert 'kvm_intel': Operation not supported. Procesor widziany przez jądro nie posiada vmx, co również wynika z decyzji podjętej na poziomie L0.
Could not access KVM kernel module: Permission denied. Problem z uprawnieniami, nie ze sprzętem. ls -l /dev/kvm powinno wskazywać grupę kvm oraz tryb 660; dodaj użytkownika do tej grupy i uruchom nową powłokę logowania, ponieważ przynależność do grupy nie aktualizuje się dla już uruchomionej sesji.
kvm: Device or resource busy podczas uruchamiania QEMU. Inny moduł hiperwizora zajmuje procesor: uruchom lsmod, wyszukaj vboxdrv lub moduły VMware obok kvm_intel i wyładuj ten, który nie jest wymagany.
/var/run/libvirt/libvirt-sock: No such file or directory z virsh. Demon nie działa: sudo systemctl enable --now libvirtd.
Proxmox: KVM virtualisation configured, but not available. Gość ma włączoną akcelerację KVM na hoście, który jej nie zapewnia. Napraw zagnieżdżanie (nesting) lub wyłącz tę opcję i zaakceptuj emulację programową.
Emulator Android: x86_64 emulation currently requires hardware acceleration! Ponownie /dev/kvm, zazwyczaj problem z uprawnieniami grupy.
Brak błędów, ale wydajność jest bardzo niska. QEMU bez flagi akceleratora przełącza się na TCG, czyli emulację programową. Działa poprawnie, ale wolno; czas rozruchu liczony w sekundach zmienia się w minuty. Przekaż jawnie -accel kvm, aby QEMU zakończyło działanie z błędem zamiast cichej emulacji.
Gość znika w trakcie pracy. Sprawdź dmesg pod kątem Out of memory: Killed process ... qemu-system-x86_64. Gość L2 jest procesem na poziomie L1, więc mechanizm OOM killer traktuje go jak każdy inny proces. Pamięć RAM dla L2 pochodzi ze sztywnej alokacji L1, bez możliwości pobierania zasobów z hosta.
Obsługa: kopie zapasowe, aktualizacje, limity
Kopie zapasowe. Kopiowanie pliku qcow2 działającego gościa grozi uzyskaniem niespójnego obrazu, ponieważ gość kontynuuje zapisy w trakcie odczytu. Należy albo uruchomić virsh shutdown guest1, poczekać aż virsh domstate guest1 zgłosi shut off (polecenie wyłączenia może zwrócić kod zakończenia, zanim gość faktycznie się zatrzyma), a następnie wykonać kopię; albo utworzyć zewnętrzny snapshot (virsh snapshot-create-as guest1 snap1 --disk-only --atomic), dzięki czemu zapisy zostaną przekierowane do pliku nakładki (overlay) na czas kopiowania statycznego obrazu bazowego, a następnie scalić go za pomocą virsh blockcommit guest1 vda --active --pivot. Kopie należy przesyłać poza VPS; snapshot na tym samym dysku nie zapewnia żadnej ochrony.
Aktualizacje. apt full-upgrade instaluje nowe moduły kvm_intel/kvm_amd, ale działające jądro korzysta ze starych do momentu restartu. Należy zachować poprzednią wersję jądra i uruchamiać ponownie kvm-ok po każdej zmianie jądra: host, który po restarcie nie ładuje vmx, jest dzięki temu o jeden wpis w menu rozruchowym od przywrócenia sprawności.
Granice skalowalności. Jeden publiczny adres IP oznacza, że każda usługa L2 dociera do świata zewnętrznego poprzez proxy lub regułę DNAT na poziomie L1. Migracja na żywo nie jest dostępna. W warunkach rywalizacji o zasoby CPU, ścieżka wyjścia z wirtualizacji (nested exit) odczuwa to jako pierwsza. Hypervisor z kilkoma gośćmi to maszyna, której pamięć RAM została już przydzielona; zagnieżdżone maszyny wirtualne nie mogą stosować overcommit w ramach sztywnej alokacji. Gdy laboratorium przerasta te możliwości, rozwiązaniem nie jest rozbudowa zagnieżdżonego stosu, lecz dedykowana maszyna, na której użytkownik jest poziomem L0 i powyższe ograniczenia nie mają zastosowania.
FAQ
Czy do uruchomienia Docker na VPS wymagana jest wirtualizacja zagnieżdżona?
Nie. Kontenery współdzielą jądro systemu operacyjnego VPS i nigdy nie otwierają /dev/kvm, więc standardowa instancja bez flagi vmx lub svm poprawnie obsługuje Docker oraz Docker Compose. Wirtualizacja zagnieżdżona jest istotna tylko w przypadku potrzeby uruchomienia drugiego jądra: laboratorium Proxmox, gościa Windows, mikro-maszyn Firecracker, emulatora Androida lub runnerów CI, które uruchamiają obrazy maszyn wirtualnych.
Jak sprawdzić, czy VPS obsługuje wirtualizację zagnieżdżoną?
Uruchom grep -o -E 'vmx|svm' /proc/cpuinfo | sort -u, a następnie kvm-ok z pakietu cpu-checker. Użyteczna instancja wyświetla vmx (Intel) lub svm (AMD), kvm-ok raportuje KVM acceleration can be used, a /dev/kvm istnieje z grupą kvm i uprawnieniami 660. W kontekście tego pytania należy zignorować /sys/module/kvm_intel/parameters/nested, ponieważ ten plik opisuje własny moduł KVM, a nie to, co hypervisor dostawcy udostępnił instancji.
Dlaczego większość dostawców VPS wyłącza wirtualizację zagnieżdżoną?
Udostępnienie vmx oznacza przekazanie gościowi modelu procesora z tą flagą. Gość zależny od tych funkcji procesora nie może zostać poddany migracji na żywo na maszynę, której procesor ich nie posiada. Dostawca, który opróżnia węzły poprzez przenoszenie klientów, rezygnuje z tej możliwości. Ścieżki kodu zagnieżdżonego VMX/SVM posiadają również długą historię podatności CVE. Niektórzy dostawcy włączają tę funkcję dla poszczególnych maszyn na żądanie, a inni oferują ją jako element konkretnego planu.
Moja zagnieżdżona maszyna wirtualna nie ma sieci na publicznym moście. Co jest przyczyną?
Przełącznik dostawcy odrzuca ramki z adresu MAC, który nie został przydzielony, więc gość L2 zmostkowany do publicznej karty sieciowej wysyła zapytania ARP i nie otrzymuje odpowiedzi. Należy zaprzestać debugowania br0, użyć sieci NAT default w libvirt (virbr0, 192.168.122.0/24), nadać gościowi statyczną dzierżawę i publikować usługi przez reverse proxy lub regułę DNAT na samym VPS.
O ile wolniejsza jest zagnieżdżona maszyna wirtualna?
Koszt wydajnościowy dotyczy wyjść z maszyny wirtualnej (VM exits) oraz translacji adresów. Przy aktywnym EPT/NPT instrukcje i trafienia TLB wewnątrz L2 działają z prędkością sprzętową, jednak chybienie TLB wymusza przejście przez dodatkowe tablice stron. Operacje I/O, przerwania czasowe, MMIO oraz IPI są obsługiwane przez L0 i mogą być przekazywane z powrotem przez L1. Praca obciążająca procesor przy małym zbiorze danych jest zbliżona do natywnej; duże zbiory danych w pamięci oraz obciążenia intensywnie korzystające z wywołań systemowych, pakietów i dysku odczuwają każdą warstwę. Należy stosować urządzenia virtio oraz cache=none dla dysków gościa, a następnie przeprowadzić pomiary dla własnego obciążenia.