Ma propre conclusion de ce matin était fausse, et une mesure l'a réfutée. J'avais écrit — code, README, commit — que le gel à 12 vCPU venait du SURENGAGEMENT : cette VM avait douze vCPU sur un hôte qui en avait deux. Descente réelle : l'étage 4 à huit vCPU, sur un parent qui en avait NEUF, charge 1,47, aucun surengagement. Gelé pareil. 32 Mio lus en 106 minutes, même RIP à trois relevés espacés de cinq minutes. C'est le nombre de vCPU de l'invité imbriqué, et rien d'autre. Le dimensionnement de bas en haut donnait 8 vCPU à l'étage 4, 7 au 5 : il rendait larges précisément les étages qui doivent rester étroits. Trois largeurs fixes le remplacent — métal, intermédiaire, fond. La mémoire et le disque, eux, restent dimensionnés depuis le bas. VCPU_INTERMEDIAIRE = 3 est une hypothèse assumée : deux démarre au quatrième étage, huit gèle, rien n'est mesuré entre les deux. --- EN --- My own conclusion from this morning was wrong, and a measurement refuted it. I had written — code, README, commit — that the 12-vCPU freeze came from OVERCOMMIT: that VM had twelve vCPU on a host with two. Real descent: level 4 at eight vCPU, on a parent with NINE, load 1.47, no overcommit whatsoever. Frozen all the same. 32 MiB read in 106 minutes, same RIP at three readings five minutes apart. It is the nested guest's vCPU count, nothing else. Bottom-up sizing gave level 4 eight vCPU and level 5 seven: it made wide exactly the levels that must stay narrow. Three fixed widths replace it — metal, intermediate, floor. Memory and disk stay sized from the bottom. VCPU_INTERMEDIAIRE = 3 is an owned hypothesis: two boots at the fourth level, eight freezes, nothing is measured in between. Assisted-by: claude-opus-5 (cherry picked from commit ee45ff4f333c69e3862e277334cb34efa39bbd57)
5.9 KiB
LongTest — des tests qui créent de vraies machines
Ce ne sont pas des tests unitaires. Ils créent des machines virtuelles, y
installent des systèmes, et durent des heures. Ils vivent ici et non dans
test/, que le lanceur unitaire balaie : ./script/test/run_unit_test.sh
doit rester lançable en quelques secondes, sur n'importe quelle machine, y
compris sans virtualisation.
Ils se lancent depuis le menu — TODO › Execute › Test › Tests longs — ou
directement.
deep_proxmox.py — jusqu'à quel étage un Proxmox dans un Proxmox tient-il ?
La profondeur d'imbrication praticable ne se déduit pas, elle se mesure — et une mesure n'est pas une mesure.
Un examen à la main d'UNE VM du quatrième étage a trouvé un invité 36 fois plus lent que le temps réel (583 secondes d'horloge pour 16 secondes de temps invité, chaque ligne d'ACPI prenant une seconde), puis un noyau gelé : même RIP à trois relevés deux minutes d'écart, et pas un octet écrit sur le disque.
Lancer ce script a réfuté la conclusion qu'on en avait tirée. Sa propre VM du quatrième étage — 2 vCPU là où celle de la main en avait 12 — a démarré, s'est installée, et a écrit des gigaoctets. Ce qui ressemblait à un plafond d'imbrication était un plafond de parallélisme sous imbrication. C'est précisément ce que l'algorithme borne, et c'est ainsi qu'il a cessé d'être une supposition.
D'où le script : un chiffre obtenu une fois, sur une machine, dans une chaîne, est une anecdote.
./LongTest/deep_proxmox.py --depth 10 --dry-run # le plan, rien de créé
./LongTest/deep_proxmox.py --depth 10 # des heures
./LongTest/deep_proxmox.py --detruire # défaire
La descente est uniforme. Chaque étage, le premier compris, passe par les
mêmes six étapes : créer, attendre le ssh, installer Proxmox, redémarrer et
vérifier le noyau, remettre pmxcfs debout, contrôler le stockage. Seule la
création diffère — libvirt en local, qm ensuite.
Il envoie notre install_proxmox.sh par scp au lieu de laisser la VM
cloner le dépôt : c'est notre code qu'on veut éprouver, et le dépôt distant
est souvent en retard sur le checkout — un correctif absent du distant a fait
« revenir » le même défaut sur trois VM de suite.
L'algorithme de ressources — dimensionné depuis le bas
La première version cédait à l'enfant ce que le parent pouvait céder, et une descente réelle a montré ce que cela coûte. L'étage 4 se retrouvait avec 44 Go de mémoire et 2 vCPU sur un hôte qui en avait 2 — cent pour cent de surengagement, à chaque étage, avec l'hyperviseur lui-même à servir par-dessus. Son installation dépassait deux heures et demie contre treize minutes pour l'étage 3, et l'extrapolation de ce rapport donnait cinq ANS pour le dixième.
Le sens est donc inversé pour la mémoire et le disque. Le plus profond reçoit ce qu'un Proxmox de test demande vraiment — 4 Go de mémoire, 25 Go de disque — et chaque parent au-dessus ajoute son propre surcoût, rien d'autre : 2 Gio et 10 Go. Une descente à dix étages demande ainsi 22 Go et 115 Go à son premier étage, là où la cession de haut en bas voulait 50 Go de mémoire pour la même profondeur. Le processeur, lui, suit une autre règle — voir plus bas.
Trois budgets peuvent borner la profondeur, et script/proxmox/nesting.py
nomme celui qui a manqué :
- la mémoire — chaque étage doit faire tourner ses propres démons
(
pve-cluster,pvestatd,pvedaemon,pveproxy) et héberger son enfant ; - le disque — le disque de l'enfant vit dans celui du parent, qui doit aussi contenir son propre système ;
- le processeur — il ne croît pas avec la profondeur. Tout étage imbriqué garde une largeur fixe et étroite ; seul le premier compte sur les cœurs physiques. Ou la machine peut porter ce premier étage, ou elle ne peut rien.
Cette troisième règle est mesurée, et il a fallu deux descentes pour la poser juste. Un invité imbriqué au quatrième étage gèle en tout début de démarrage dès qu'il est large : douze vCPU la première fois, huit la seconde — même pointeur d'instruction à trois relevés espacés de cinq minutes, 32 Mio lus et plus un octet pendant 106 minutes. Deux vCPU démarrent.
Le premier gel avait été imputé au surengagement : cette VM à douze vCPU tournait sur un hôte qui en avait deux. La seconde mesure l'a réfuté — huit vCPU sur un parent qui en avait neuf, charge 1,47, aucun surengagement, et le même gel. C'est le nombre de vCPU de l'invité imbriqué, et non son rapport à celui de son hôte.
Au troisième étage, 9 vCPU démarrent en 117 s. Le seuil est entre le troisième et le quatrième étage : aucun étage imbriqué n'est donc rendu large. Une version précédente de cet algorithme donnait un vCPU de plus à chaque parent, ce qui rendait l'étage 4 large de huit — exactement le cas gelé. La règle rendait large ce qui doit rester étroit.
D'où trois largeurs fixes : VCPU_METAL pour l'étage 1 (sur le métal, aucun
risque de gel — onze vCPU y ont démarré en 42 s), VCPU_IMBRIQUE pour le plus
profond, et VCPU_INTERMEDIAIRE entre les deux, juste assez large pour héberger
son enfant sans être aussi étroit que lui. Ce nombre du milieu est une
hypothèse : deux démarre au quatrième étage, huit gèle, et rien n'est mesuré
entre les deux. C'est la descente qui tranche.
La mémoire n'est pas le levier. Sur cette même VM examinée à la main, la faire passer de 9 Go à 2 Go n'a rien déplacé : elle s'arrêtait après avoir lu les mêmes 32 Mio, c'est-à-dire simplement la taille des fichiers d'amorçage.
Le plan est affiché avant que quoi que ce soit ne soit créé, et le script ne promet jamais une profondeur qu'il sait irréalisable — mieux vaut annoncer six étages et en réussir six que d'en promettre dix et mourir au septième sans savoir pourquoi.