Przejdź do treści
Automatyzacja i DevOps·~13 min czytania

Lab na osobnym hoście: od czystego Debiana 13 do jedenastu maszyn z Terraform

Tym samym kodem postawiliśmy na nowym laptopie jedenaście maszyn. Co trzeba doinstalować, o czym Terraform powie dopiero błędem i dlaczego nie uruchamiamy go ze stacji roboczej.

Autor: Zespół LinuxLab

W LinuxLab nie testujemy zmian na serwerach klientów. Zanim playbook, aktualizacja systemu albo nowa konfiguracja usługi trafi na produkcję, przechodzi przez lab. Ten artykuł opisuje nasz lab i to, co się w nim wydarzyło - z liczbami z pomiarów, a nie z dokumentacji producentów.

W tym artykule stawiamy pełny lab - jedenaście maszyn w trzech warstwach - na świeżo zainstalowanym Debianie 13. Opisujemy pakiety, których Terraform nie zainstaluje, zmianę klucza repozytorium HashiCorp, przygotowanie libvirt, przeniesienie kodu i obrazów, budowę warstw oraz pułapki, które wyszły dopiero przy sprawdzaniu maszyn od środka. Nazwy kont, ścieżki i nazwa hosta są w przykładach ogólne.

Spis treści

  1. Zakres testu: co sprawdziliśmy na świeżym Debianie 13, a czego nie
  2. Dlaczego lab KVM przenieśliśmy ze stacji roboczej na osobny host
  3. Jedenaście maszyn wirtualnych i trzecia warstwa Terraform: infra
  4. Gdzie uruchamiać Terraform: na hoście libvirt, a nie na stacji roboczej
  5. Budowa labu KVM na Debianie 13 krok po kroku
  6. Pułapki, na które trafiliśmy przy budowie labu
  7. Zużycie energii hosta KVM po budowie labu
  8. Checklista budowy labu KVM na osobnym hoście z Debianem 13

Zakres testu: co sprawdziliśmy na świeżym Debianie 13, a czego nie

Ten tekst uzupełnia artykuł Lab do testów na Terraform i OpenTofu. Tamten opisuje sam kod: warstwę bazową, cztery maszyny testowe, pułapkę formatu dysku i operacje dnia drugiego. Ten opisuje, co się stało, gdy ten sam kod trafił na świeżo zainstalowany, osobny komputer i miał postawić wszystkie jedenaście maszyn naszego labu. Wszystko poniżej wykonaliśmy 17 września 2026 roku.

Tabela jest zapisem tego testu, nie panelem bieżącego stanu labu. Przed powtórzeniem sprawdź lokalnie virsh list --all, virsh net-list --all, virsh pool-list --all i wersje narzędzi; stan maszyn oraz użycie pamięci zmieniają się wraz z obciążeniem.

ElementStan
HostThinkPad T490, Intel Core i7-8665U (4 rdzenie, 8 wątków), 38 GiB pamięci, dysk NVMe 512 GB, sieć wyłącznie po Wi-Fi
SystemDebian 13.7 z instalatora sieciowego, bez środowiska graficznego
WirtualizacjaKVM (od angielskiego Kernel-based Virtual Machine, czyli wirtualizacja wbudowana w jądro), QEMU 10.0.13 (emulator uruchamiający maszyny), libvirt 11.3.0, OVMF 2025.02 (od angielskiego Open Virtual Machine Firmware, czyli firmware dla maszyn wirtualnych) - wersje z repozytorium Debiana
NarzędzieTerraform 1.16.3 z repozytorium HashiCorp, provider dmacvicar/libvirt 0.8.3
Wynik11 maszyn zdefiniowanych, 10 uruchomionych zgodnie z kodem, usługi sprawdzone w środku

Czego nie sprawdzaliśmy: przenoszenia dysków istniejących maszyn (budowaliśmy je od nowa z kodu, bo na starym hoście nie trzymały danych, których nie da się odtworzyć), uruchamiania Terraform przez sieć na zdalnym libvirt oraz OpenTofu na tym hoście. Nazwy kont, ścieżki i nazwa hosta są w przykładach ogólne.

Dlaczego lab KVM przenieśliśmy ze stacji roboczej na osobny host

Do tej pory lab działał na naszej stacji roboczej. To wygodne, dopóki maszyny włącza się na godzinę testów. Gdy mają działać stale - serwer kopii zapasowych, AWX z harmonogramami, host Dockera - stacja robocza przestaje być dobrym miejscem: każdy restart laptopa to przerwa w labie, a lab zjada pamięć potrzebną do pracy.

Nowy host to używany ThinkPad z 38 GiB pamięci. Laptop jako serwer ma dwie zalety, które w labie liczą się bardziej niż wydajność: wbudowany zasilacz awaryjny w postaci baterii i mały pobór mocy. Ile dokładnie pobiera i co go obniżyło, opisaliśmy osobno w artykule Laptop jako host KVM: jak obniżyliśmy zużycie energii o 40 procent.

Jedenaście maszyn wirtualnych i trzecia warstwa Terraform: infra

Poprzedni artykuł opisywał dwie warstwy: bazową (obrazy i sieć) i maszyny testowe. Pełny lab ma trzecią, infra, z maszynami usługowymi. Wszystkie trzy mają osobne stany, a maszyny obu warstw tworzy ten sam moduł. Różnią się profilem, czyli szablonem konfiguracji startowej cloud-init. Maszyny testowe pracują w osobnej sieci NAT lab, usługowe w domyślnej sieci libvirt default. Cały ten kod, z trzema warstwami, wspólnym modułem i szablonami cloud-init, opublikowaliśmy w katalogu terraform/ repozytorium sysgroup/linuxlab (stan z 22 września 2026, commit eba6d62):

MaszynaWarstwaProfilSystemvCPUPamięćDyskDziała
deb11, deb12, deb13testboxesbaseDebian 11, 12, 1322 GiB10 GiBtak
ubu2204, ubu2404, ubu2604testboxesbaseUbuntu 22.04, 24.04, 26.0422 GiB10 GiBtak
kdevinfradesktopUbuntu 24.0448 GiB20 GiBtak
pbsinfrapbsDebian 1224 GiB10 + 4×50 GiBtak
awxinfrak3sUbuntu 24.0448 GiB40 GiBtak, autostart
dockerinfradockerDebian 1324 GiB20 GiBtak
moninfradockerDebian 1346 GiB30 GiBnie

Profil base zakłada konto z kluczem, agenta QEMU i Pythona - to cel dla playbooków. desktop instaluje pulpit KDE, pbs - Proxmox Backup Server z repozytorium bez subskrypcji, k3s - jednowęzłowy Kubernetes pod AWX (opisany w artykule AWX na k3s: instalacja, pierwszy job i bezpieczna eksploatacja), a docker - silnik Docker z wtyczką compose. Dyski danych pbs zostają puste: magazyn kopii zakłada się ręcznie, żeby Terraform nigdy go nie skasował przy zmianie.

Pamięć wygląda groźnie tylko na papierze. Uruchomione maszyny mają zadeklarowane razem 36 GiB, a host ma 38 GiB. W tej konkretnej konfiguracji, bez prealokacji pamięci, cztery godziny po restarcie hosta procesy QEMU zajmowały razem około 8,9 GiB, a free pokazywało 9,6 GiB zajętej pamięci. Nie gwarantuje to jednak, że maszynom można bezpiecznie przydzielić więcej pamięci, niż host ma fizycznie: pamięć faktycznie zajmowana przez procesy QEMU (RSS, od angielskiego Resident Set Size) zależy między innymi od sposobu przydziału pamięci gościom, od mechanizmu balonu pamięci, od pamięci podręcznej systemów gości i od obciążenia. Tuż po pierwszym starcie, w trakcie instalowania pakietów przez wszystkie maszyny naraz, zajęte było około 21 GiB. Z czasem pamięć podręczna gości będzie ten zapas zjadać, więc obserwujemy dostępną pamięć, wskaźniki presji pamięci (PSI, od angielskiego Pressure Stall Information) i komunikaty o jej braku (OOM, od angielskiego Out Of Memory).

Gdzie uruchamiać Terraform: na hoście libvirt, a nie na stacji roboczej

Provider libvirt umie łączyć się ze zdalnym hostem, więc naturalny pomysł to zostawić kod i stan na stacji roboczej i tylko zmienić adres połączenia. Nie zrobiliśmy tego z powodu jednego zdania w dokumentacji zasobu wolumenu: source może wskazywać obraz lokalny, przy czym ścieżka jest względna wobec maszyny, na której działa Terraform, a obraz jest wysyłany do puli libvirt.

W naszym kodzie source to lokalne obrazy bazowe, a w trybie kopiowania także dysk każdej maszyny. Przy Terraform na stacji roboczej oznaczałoby to wysyłanie przez Wi-Fi pełnych obrazów: sześciu bazowych i po 10 GiB (kopia obrazu bazowego) na każdą z jedenastu maszyn. Tego wariantu nie testowaliśmy - to wniosek z dokumentacji, a nie pomiar - ale wystarczył, żeby wybrać prostszą drogę. Terraform działa na hoście, łączy się lokalnie przez qemu:///system, a polecenia virsh w provisionerach modułu też działają lokalnie.

Koszt tej decyzji: stan labu leży na hoście labu, więc kopia zapasowa stanu jest częścią kopii tego hosta, a nie stacji roboczej.

Budowa labu KVM na Debianie 13 krok po kroku

Kroki od 1 do 3 robi się raz na hoście. Każdy ma sprawdzenie, a przy krokach, które u nas się wyłożyły, podajemy dokładny komunikat błędu - żeby dało się go wyszukać.

Krok 1. Pakiety wirtualizacji bez pakietów zalecanych

Debian instaluje domyślnie także pakiety zalecane (opcja APT::Install-Recommends, opisana w podręczniku apt.conf). Symulacja apt-get install -s dla samych pięciu pakietów wirtualizacji (qemu-system-x86, qemu-utils, ovmf, libvirt-daemon-system, libvirt-clients) z pakietami zalecanymi pokazała 363 pakiety do instalacji, w tym GTK, GStreamer i sterowniki Mesa. Na serwerze bez ekranu to zbędny balast i zbędne aktualizacje. Nasza pierwsza instalacja, z szerszą listą i narzędziami, ale jeszcze bez genisoimage i xsltproc, objęła 123 pakiety. Pełna lista wygląda tak:

sudo apt-get install --no-install-recommends \
  qemu-system-x86 qemu-utils ovmf qemu-system-modules-spice \
  libvirt-daemon-system libvirt-clients dnsmasq-base nftables \
  genisoimage xsltproc make jq git rsync curl gnupg

Dwa pakiety z tej listy dopisaliśmy dopiero po błędach, bo Terraform sprawdza ich obecność dopiero w trakcie apply:

  • genisoimage dostarcza mkisofs, którym provider buduje dysk z konfiguracją startową. Bez niego: error while starting the creation of CloudInit's ISO image: exec: "mkisofs": executable file not found in $PATH.
  • xsltproc jest wołany, gdy domena ma blok xml { xslt = ... }. Bez niego: error applying XSLT stylesheet: exec: "xsltproc": executable file not found in $PATH. Poprzedni artykuł go nie wymieniał, bo cztery maszyny testowe nie używały wtedy arkusza XSLT (od angielskiego XSL Transformations, czyli przekształceń dokumentów XML). Dziś używa go każda maszyna - powód jest w artykule o zużyciu energii.

Moduł wyświetlania SPICE (od angielskiego Simple Protocol for Independent Computing Environments, czyli systemu zdalnego ekranu dla maszyn wirtualnych) jest w Debianie 13 osobnym pakietem, qemu-system-modules-spice. Dodajemy go jawnie, bo maszyna z pulpitem korzysta ze SPICE, a przy --no-install-recommends sam by nie przyszedł.

Na koniec zostają uprawnienia. Po ponownym zalogowaniu virsh -c qemu:///system list ma działać bez sudo:

sudo usermod -aG libvirt,kvm "$USER"

Krok 2. Instalacja Terraform i nowy klucz repozytorium HashiCorp

Terraform instalujemy z repozytorium HashiCorp, które ma gałąź dla Debiana 13 (trixie). Tu czekała niespodzianka. Pobrany klucz miał inny odcisk niż ten, który mieliśmy na starym hoście, i datę utworzenia 9 września 2026. Sprawdziliśmy to trzema sposobami:

  • podpis pliku InRelease zweryfikowany narzędziem gpgv - repozytorium podpisuje już wyłącznie nowym kluczem, a stary zgłasza „brak klucza publicznego”, i to zarówno dla trixie, jak i dla noble,
  • nowy klucz nie jest podpisany starym, więc łańcucha zaufania nie da się odtworzyć samym GnuPG,
  • nowy odcisk podaje oficjalny przewodnik po pakietach HashiCorp, a zmianę klucza z 10 września ogłasza biuletyn HCSEC-2026-33.

Aktualny odcisk to D55C 0D1A C78A 8D81 26CB 631C FC9C A96A CA02 6560. Poprzedni, 798A EC65 4E5C 1542 8C8E 42EE AA16 FCBC A621 E701, już nie wystarcza - na hostach, które go mają, apt update dla tego repozytorium przestanie przechodzić. Kolejność ma znaczenie: najpierw porównanie odcisku, potem repozytorium. U nas oba kroki stały w jednym poleceniu i odcisk sprawdzaliśmy już po instalacji. Tym razem klucz okazał się prawdziwy, ale lepiej rozdzielić te kroki:

curl -fsSL https://apt.releases.hashicorp.com/gpg -o /tmp/hashicorp.asc
gpg --show-keys --with-fingerprint /tmp/hashicorp.asc
# STOP: porównaj odcisk z oficjalną stroną, dopiero potem dalej

sudo gpg --dearmor -o /usr/share/keyrings/hashicorp-archive-keyring.gpg /tmp/hashicorp.asc
echo "deb [arch=amd64 signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] https://apt.releases.hashicorp.com trixie main" \
  | sudo tee /etc/apt/sources.list.d/hashicorp.list
sudo apt-get update
sudo apt-get install terraform
terraform version        # Terraform v1.16.3

Krok 3. libvirt na Debianie 13: nieaktywna sieć default i brak puli na dyski

Po instalacji Debian uruchamia libvirt, ale zostawia go pustym. Sieć default jest zdefiniowana, lecz nieaktywna i bez autostartu, a puli na dyski nie ma żadnej. Warstwa bazowa tworzy własną pulę na obrazy i sieć lab, natomiast pula images na dyski maszyn i sieć default dla maszyn usługowych są warunkami wstępnymi:

virsh -c qemu:///system net-list --all      # default: inactive, autostart: no
sudo virsh net-autostart default
sudo virsh net-start default

sudo virsh pool-define-as images dir --target /var/lib/libvirt/images
sudo virsh pool-build images
sudo virsh pool-start images
sudo virsh pool-autostart images

Przy okazji jedna rzecz, która na pierwszy rzut oka wygląda źle. Gniazdo /run/libvirt/libvirt-sock ma prawa 0666, czyli może się do niego podłączyć każdy lokalny użytkownik. Uprawnienia pilnuje jednak polkit, a nie prawa pliku. Obce konto dostaje odmowę:

$ sudo -u nobody virsh -c qemu:///system list
error: failed to connect to the hypervisor
error: authentication unavailable: no polkit agent available to authenticate action 'org.libvirt.unix.manage'

Sprawdzenie całego kroku: virsh net-list pokazuje aktywną sieć default z autostartem, a virsh pool-list aktywną pulę images.

Krok 4. Kod Terraform, obrazy bazowe i pliki zmiennych na hoście

Zgodnie z decyzją z sekcji Gdzie uruchamiać Terraform, Terraform działa na samym hoście. Na host trafiają więc kod, obrazy bazowe i lokalne pliki zmiennych. Stanów ze starego hosta nie kopiujemy - opisują maszyny, które istnieją gdzie indziej.

Kod przenieśliśmy paczką git bundle. Tu pierwsza wpadka: --all spakowało także referencję pozostawioną w repozytorium przez inne narzędzie, a przez nią stare obrazy dysków, których nie ma w żadnej gałęzi. Paczka miała 2 GB. Przerwaliśmy kopiowanie i spakowaliśmy same gałęzie - wyszło 143 KB:

# na starym hoście
git -C ~/lab for-each-ref --format='%(refname)'     # zobacz, co spakujesz
git -C ~/lab bundle create /tmp/lab.bundle --branches
scp /tmp/lab.bundle lab-host:/tmp/

# na nowym hoście
git clone /tmp/lab.bundle ~/lab

Obrazy bazowe mają po 2-3,5 GB pozornego rozmiaru, ale są plikami rzadkimi. Z opcją -S rsync zachowuje dziury po stronie docelowej. Po drugiej stronie sześć obrazów zajęło 8,1 GiB. Sumy kontrolne porównaliśmy po obu stronach - były identyczne, więc maszyny na obu hostach powstają z tych samych, sprawdzonych obrazów:

rsync -aS --info=progress2 ~/lab-golden/ lab-host:lab-golden/
sha256sum ~/lab-golden/*.raw
ssh lab-host 'sha256sum ~/lab-golden/*.raw'

Zostały dwie rzeczy. Konfiguracja startowa wstawia do maszyn klucz publiczny, więc na host kopiujemy tylko klucz publiczny. Prywatny zostaje na stacji roboczej, a do maszyn logujemy się przez przeskok (krok 8). Pliki *.auto.tfvars z lokalnymi ścieżkami do obrazów są w .gitignore, więc trzeba je utworzyć na nowo - z katalogiem domowym nowego hosta, bo ścieżki są bezwzględne.

Krok 5. Budowa warstwy bazowej: pula, sieć i obrazy

cd ~/lab/base
terraform init
terraform plan -out=base.tfplan     # Plan: 14 to add
terraform apply base.tfplan

Plan obejmował czternaście zasobów: pulę, sieć, sześć obrazów i sześć powiększeń obrazów do 10 GiB. Każdy obraz powstał w 4-24 sekundy. Plan zapisany do pliku ma tę zaletę, że apply wykona dokładnie to, co przeczytaliśmy.

Krok 6. Budowa maszyn testowych i błąd braku mkisofs

Pierwsze apply przerwał brak mkisofs - stąd genisoimage w kroku 1. Po doinstalowaniu kolejny plan pokazał już tylko 12 z 24 zasobów: to, co powstało za pierwszym razem, było zapisane w stanie. Terraform nie zaczyna od zera, tylko dokańcza.

cd ~/lab/testboxes
terraform init
terraform plan -out=tb.tfplan
terraform apply tb.tfplan
virsh -c qemu:///system list        # sześć maszyn: running

Krok 7. Budowa maszyn usługowych i błąd braku xsltproc

Tu wyłożył się brak xsltproc, ale tylko na pbs - jedynej maszynie, która miała wtedy arkusz XSLT. Cztery pozostałe powstały od razu. Po doinstalowaniu plan pokazał jedną maszynę do utworzenia i cztery do zmiany w miejscu. Ta zmiana w miejscu ma skutek uboczny opisany w pułapkach: włączyła maszynę mon, która według kodu ma być wyłączona.

cd ~/lab/infra
terraform init
terraform plan -out=infra.tfplan
terraform apply infra.tfplan
virsh -c qemu:///system list --all  # mon ma być: shut off

Krok 8. Sprawdzenie maszyn przez SSH z przeskokiem przez host

Maszyny dostają adresy z sieci NAT hosta, a te same podsieci mieliśmy na starym hoście. Bezpośredni routing ze stacji roboczej byłby więc niejednoznaczny. Logujemy się przez przeskok (opcja -J w podręczniku ssh), a klucz prywatny nie opuszcza stacji roboczej:

virsh -c qemu:///system net-dhcp-leases lab
ssh -J lab-host -i ~/.ssh/lab_key admin@192.168.123.67 'cloud-init status'

Tak wyglądało to u nas po zakończeniu konfiguracji startowej:

MaszynaWynik
Ubuntu 22.04, 24.04, 26.04, Debian 12 i 13cloud-init status: done, logowanie kluczem działa
deb11status: error - opis w pułapkach
pbsProxmox Backup Server 3.4.9, obie usługi aktywne, panel na porcie 8007 zwraca HTTP 200, cztery dyski po 50 GiB widoczne
dockerDocker 29.8.1, usługa aktywna
awxk3s v1.34.3+k3s3, węzeł Ready, pody systemowe Running lub Completed
kdevinstalacja pulpitu trwała 714 sekund, potem restart do trybu graficznego - ale serwer X nie działał, opis w pułapkach

Na awx zwróć uwagę na jedno: kubectl dostarczany z k3s domyślnie czyta plik konfiguracyjny w /etc/rancher/k3s/, dostępny tylko dla roota, i zgłasza permission denied, nawet gdy konto ma własną kopię w ~/.kube/config. Pomaga jawne kubectl --kubeconfig ~/.kube/config.

Pułapki, na które trafiliśmy przy budowie labu

Zmiana w miejscu w Terraform włącza wyłączoną maszynę

Provider 0.8.3 zapisuje dysk w stanie jako volume_id, a nasz kod podaje go jako file (to celowe - opis jest w poprzednim artykule). Skutek: każdy plan pokazuje zmianę w miejscu dla wszystkich maszyn, nawet gdy nic się nie zmieniło. Sama zmiana jest nieszkodliwa, ale ma efekt uboczny. Sprawdziliśmy go celowo, na samej maszynie mon:

$ virsh -c qemu:///system domstate mon
shut off
$ terraform apply -target='module.vms.libvirt_domain.vm["mon"]'
Plan: 0 to add, 1 to change, 0 to destroy.
$ virsh -c qemu:///system domstate mon
running

Maszyna z running = false po zmianie w miejscu jest włączona. Dopóki dryf istnieje, po każdym apply w warstwie usługowej trzeba ją wyłączyć (virsh shutdown mon). Uwaga przy wyłączaniu: gość świeżo po starcie potrafi zignorować żądanie wyłączenia - u nas pierwsze nie zadziałało, drugie, wysłane po zakończeniu uruchamiania, tak. Ten przypadek opisuje też sekcja o znanych pułapkach w README katalogu terraform/.

Debian 11 bez agenta QEMU, bo repozytorium już go nie udostępnia

Konfiguracja startowa deb11 zakończyła się błędem. Log mówi dokładnie dlaczego:

E: Failed to fetch http://security.debian.org/debian-security/pool/updates/main/q/qemu/qemu-guest-agent_5.2%2bdfsg-11%2bdeb11u5_amd64.deb  404  Not Found

Tydzień wcześniej, przy pisaniu poprzedniego artykułu, ten sam system zatrzymywał się już na apt-get update, bo plik InRelease repozytorium bezpieczeństwa był przeterminowany. 17 września obraz był inny: InRelease miał datę 12 września i nie miał już pola Valid-Until, więc apt-get update przechodził, a indeks wskazywał jako kandydata wersję 1:5.2+dfsg-11+deb11u5. Tyle że w katalogu puli nie było już pliku dla Debiana 11 - tylko wersje dla Debiana 12 i 13. Indeks obiecuje pakiet, którego nie da się pobrać.

Maszyna działa, ma Pythona i daje się zalogować, tylko bez agenta QEMU nie zgłasza swojego adresu i trzeba go brać z DHCP (od angielskiego Dynamic Host Configuration Protocol). Debian 11 jest po końcu wsparcia i lab kolejny raz sam to zgłosił - tym razem innym objawem.

Agent QEMU nie odpowiadał po pierwszym uruchomieniu: obserwacja, nie reguła

Podczas pierwszego uruchomienia z 17 września na deb12, deb13, pbs, docker i mon pakiet qemu-guest-agent był zainstalowany, ale usługa nie odpowiadała jeszcze na virsh domifaddr --source agent. Pomagało uruchomienie usługi w gościu albo kolejny restart. Nie jest to właściwość każdego obrazu Debiana: 18 września na maszynach testowych deb12 i deb13 agent odpowiadał po 4-9 sekundach od startu, bez dowodu, że restart był przyczyną. Zawsze sprawdzaj faktyczny adres przez virsh domifaddr --source agent, a gdy go brakuje - przez DHCP lub konsolę.

Po restarcie hosta wstaje tylko jedna maszyna: domyślne ustawienia libvirt-guests w Debianie

O tym, co dzieje się z maszynami przy wyłączaniu i starcie hosta, decyduje usługa libvirt-guests. Podręcznik libvirt (libvirt.org opisuje najnowsze wydanie, 24 września 2026 był to libvirt 12.7.0; host ma 11.3) jako wartości domyślne podaje ON_BOOT=start i ON_SHUTDOWN=suspend. Skrypt w pakiecie Debiana ma jednak inne:

$ sed -n '/^URIS/,/^SYNC_TIME/p' /usr/lib/libvirt/libvirt-guests.sh
URIS="default"
ON_BOOT="ignore"
ON_SHUTDOWN="shutdown"
SHUTDOWN_TIMEOUT=300
...

Przy restarcie maszyny są więc łagodnie wyłączane (kolejno, z limitem 300 sekund), a po starcie hosta uruchamiają się tylko te z autostartem. Sprawdziliśmy to restartem: wstała wyłącznie awx. To zgodne z kodem (autostart = true ma tylko ona), ale łatwo o tym zapomnieć. Pozostałe włączamy ręcznie, a nie przez terraform apply - ten przy okazji włączyłby też mon.

Pulpit KDE na maszynie wirtualnej: serwer X padał 11 razy na minutę

Na kdev usługa menedżera logowania SDDM była aktywna, co wyglądało jak działający pulpit. Dopiero lista procesów pokazała serwer X w stanie zombie, z coraz to nowym numerem procesu. Dziennik SDDM zawierał 2589 startów serwera X w jednym uruchomieniu maszyny, około 11 na minutę, a /var/log/Xorg.0.log kończył się tak (fragment, bez znaczników czasu i adresów):

(EE) 7: /usr/lib/xorg/Xorg (xf86ProbeOutputModes+0x1b6)
(EE) Segmentation fault at address 0x0
Fatal server error:
(EE) Caught signal 11 (Segmentation fault). Server aborting

Maszyna ma parawirtualną kartę graficzną QXL, a serwer X wybierał dla niej sterownik qxl z pakietu xserver-xorg-video-qxl 0.1.6. Po usunięciu tego pakietu użył ogólnego sterownika modesetting i przestał padać - przez kolejne trzy minuty nie było ani jednego restartu. Warto wiedzieć, na czym ten sterownik działa: urządzeniem DRM (od angielskiego Direct Rendering Manager, czyli podsystemu grafiki w jądrze) w gościu jest simple-framebuffer, czyli prosty bufor ramki przekazany przez firmware, a nie sterownik karty QXL w jądrze. Obraz jest więc rysowany programowo i sam ekran logowania zajmuje około 36 procent jednego procesora gościa. Ile to kosztuje energii, zmierzyliśmy w artykule o zużyciu energii. Tę zmianę zrobiliśmy na razie ręcznie w gościu. Profil desktop jej nie zawiera, więc odbudowana maszyna wróci do stanu z błędem.

Lekcja jest ogólniejsza niż sam sterownik: „usługa aktywna” nie znaczy „działa”. SDDM był aktywny przez cały czas, bo to on restartował padający serwer.

Zużycie energii hosta KVM po budowie labu

Host ma pracować całą dobę, więc od razu zmierzyliśmy jego pobór. Dziesięć maszyn zaczynało od 5,3-5,9 W. Największy zysk dało wyłączenie emulowanego zegara HPET (od angielskiego High Precision Event Timer) i zbędnej grafiki w definicjach maszyn - przez arkusz XSLT w module (modules/vm-group/domain.xsl.tftpl), którego zmiana odtworzyła wszystkie domeny (dyski zostały, a konfiguracja startowa się nie powtórzyła). Całość, z metodą pomiaru bez watomierza, jest w artykule Laptop jako host KVM: jak obniżyliśmy zużycie energii o 40 procent.

Checklista budowy labu KVM na osobnym hoście z Debianem 13

  1. Pakiety wirtualizacji instalujesz z --no-install-recommends i jawnie dodajesz genisoimage, xsltproc oraz moduł SPICE, jeśli któraś maszyna ma pulpit.
  2. Odcisk klucza repozytorium porównujesz z oficjalną stroną, zanim dodasz repozytorium - a nie po instalacji.
  3. Sieć default ma autostart, a pula na dyski maszyn istnieje, zanim ruszy apply.
  4. Wiesz, gdzie działa Terraform, i rozumiesz, co provider wysyła przez sieć, gdy działa gdzie indziej.
  5. Pakujesz tylko gałęzie repozytorium i sprawdzasz, jakie referencje w nim siedzą.
  6. Obrazy kopiujesz jako pliki rzadkie i porównujesz sumy kontrolne po obu stronach.
  7. Na host trafia klucz publiczny, a nie prywatny. Do maszyn logujesz się przez przeskok.
  8. Stanu ze starego hosta nie kopiujesz. Lokalne pliki zmiennych tworzysz na nowo.
  9. Po apply w warstwie usługowej sprawdzasz, czy maszyny z running = false nadal są wyłączone.
  10. Sprawdzasz usługi w środku maszyn, a przy pulpicie - czy serwer graficzny nie restartuje się w pętli.
  11. Wiesz, które maszyny wstaną po restarcie hosta, i sprawdziłeś to jednym restartem.

Kod labu przeszedł tę przeprowadzkę bez zmian w logice - zmieniły się tylko lokalne ścieżki. Wszystko, co wymagało pracy, leżało poza kodem: pakiety, klucz repozytorium, pula i sieć, zachowanie usług przy restarcie oraz jeden sterownik graficzny. To dobra miara tego, co warto dopisać do dokumentacji labu, zanim zrobi się to następnym razem.

Chcesz testować zmiany, zanim trafią na produkcję?

Budujemy środowiska testowe odwzorowujące Twoją infrastrukturę, opisane kodem i odtwarzalne w kilka minut - także na sprzęcie, który już masz.