Blog ·
VM of container? Wat verkoop je op Proxmox
Een KVM-gast en een LXC-container delen een hypervisor, een nummerruimte en een prijslijst, en verder bijna niets. De verschillen die je geld kosten.
Door Provibr
Proxmox VE draait twee soorten gast. Een virtuele KVM-machine start achter geëmuleerde firmware zijn eigen kernel op, en een LXC-container deelt de kernel van de host waar hij op staat. Voor een klant die een VPS koopt zijn het allebei "een server met root erop", en daarom wordt de vergelijking meestal gemaakt in een marketingtabel met regels over dichtheid en overhead.
Die regels kloppen, en het zijn niet de regels die je geld gaan kosten. Wat je geld kost is de verzameling plekken waar de twee er in de API identiek uitzien en er onderhuids anders aan toe gaan, want daar doet een paneel, een facturatiesysteem of een bestelstroom stilletjes het verkeerde en merkt niemand het een maand lang.
We hebben onlangs een tweede soort rekencapaciteit aan onze eigen Proxmox-integratie toegevoegd, en dat betekende de API lezen met één specifieke vraag: waar lopen deze twee uiteen. Dit is wat dat opleverde, in de volgorde waarin het ons verraste.
Eén cluster, één nummerruimte
Begin bij het nummer, want daar hangt de rest aan. Een gast in Proxmox wordt aangesproken met een nummer, en het is verleidelijk om aan te nemen dat virtuele machines en containers elk hun eigen reeks krijgen: 100 zou een VM kunnen zijn en 100 zou ook een container kunnen zijn, uit elkaar gehouden door hun soort.
Dat kan niet. De nummerruimte wordt over het hele cluster gedeeld, en drie eigenschappen van de API zeggen dat. Het endpoint dat het eerstvolgende vrije nummer uitgeeft neemt geen soortparameter aan, dus het kan niet weten welke van de twee je op het punt staat aan te maken. De cluster-resourcelijst geeft machines en containers samen terug op hetzelfde numerieke veld. En de gastenlijst van het cluster zelf is op dat nummer gesleuteld.
Dat heeft een rechtstreeks gevolg voor alles wat Proxmox-gasten in een eigen database bewaart. Zet je de soort in je uniciteitsvoorwaarde, zodat "machine 5001" en "container 5001" twee verschillende rijen zijn, dan heb je een schema dat twee rijen voor één gast kan bevatten en ze erover kan laten vechten. Het nummer is op zichzelf uniek, en de soort is een waarneming die ernaast bewaard wordt. Kies je reeksen voor een vloot, dan verandert het rekenwerk in een VMID-reeks kiezen op Proxmox niet zodra er containers bij komen, en dat is precies de bedoeling.
Een container wordt uitgepakt, niet gekloond
Het tweede verschil zit in het aanmaakpad, en het is groter dan het lijkt.
Een virtuele machine wordt normaal gesproken gemaakt door een sjabloon te klonen: je noemt een bron, je kiest volledig of gekoppeld, en je krijgt een kopie van een schijfimage. Een container wordt gemaakt door een archief uit te pakken op een vers volume. Er is geen brongast, er is geen keuze tussen volledig en gekoppeld, en er is geen cloud-init-schijf, want er is niets om een schijf aan te hangen.
Het verzoek heeft daardoor bijna geen velden gemeen met het verzoek dat een machine aanmaakt. Een container wil een ostemplate die naar een archief op een opslag wijst, een unprivileged-vlag, een hostname, een rootfs en een waarde voor swap. Een machine wil scsi0, scsihw, bios, boot en een ide2 als hij vanaf een ISO opstart. Het ene vocabulaire hergebruiken voor het andere is de fout die je bewust moet vermijden: de woorden lijken genoeg op elkaar dat een veld dat disk heet binnen een jaar twee verschillende dingen betekent in dezelfde codebasis.
Twee details in dat verzoek zijn het stelen waard, wat je er verder ook op bouwt.
rootfs=<storage>:<size> is een toewijzing en geen verwijzing. Het betekent "maak op deze opslag een nieuw volume van zoveel gigabyte aan". De vorm die een bestaand volume noemt ziet er bijna identiek uit en doet iets van een andere orde: die neemt een volume over waar de gegevens van iemand anders nog in kunnen staan.
Een parameter weglaten is het veilige antwoord. Nesting, keyctl, FUSE, bind mounts en het doorgeven van apparaten staan allemaal uit tenzij je ze meestuurt, en er is geen "lege" waarde die je niet mag vergeten mee te sturen. De juiste standaardhouding voor een hostingplatform is daarom een kort verzoek en geen lang verzoek. Met het architectuurveld is het net zo: Proxmox leidt het af uit het archief, en een waarde meesturen die daarmee in tegenspraak is mislukt bij het uitpakken.
Drie dingen die een container nooit zal doen
Sommige gaten zijn punten op een routekaart. Drie zijn structureel, en die twee categorieën in je eigen product door elkaar halen is de manier waarop je een functie belooft die niet kán bestaan.
| Handeling | KVM-gast | LXC-container |
|---|---|---|
| Starten, stoppen, afsluiten, verwijderen | ja | ja, dezelfde vorm, ander padsegment |
| Pauzeren of in slaapstand zetten | ja | nee: dat is de QEMU-monitor |
| Van het netwerk opstarten met PXE | ja | nooit |
| Installeren vanaf een ISO | ja | nooit |
| Een opstartvolgorde, BIOS of UEFI kiezen | ja | nooit |
| Console | VNC-framebuffer | een terminal, over een ander protocol |
| Swap | onzichtbaar voor de host | een hypervisorinstelling met een getal |
Vijf van die regels vragen meer dan een cel, in drie groepen.
Netboot, installeren vanaf een ISO en het kiezen van firmware zijn om één reden onmogelijk en niet om drie: een container heeft geen firmware. Hij draait geen bootloader, hij heeft geen opstartvolgorde, en bij het starten komt niets kijken dat opgedragen zou kunnen worden om het eerst op het netwerk te proberen. Verkoop je een product waarin "opnieuw installeren vanuit onze imagebibliotheek" een functie is, houd er dan rekening mee dat het PXE-pad van DHCP-antwoord tot afgeronde installatie geen tegenhanger voor containers heeft. Een container opnieuw opbouwen is een ander mechanisme met andere garanties, en het verdient een eigen scherm in plaats van een grijs gemaakte knop.
De console is hetzelfde soort verschil onder een vertrouwde naam. Proxmox geeft je een console voor een container, maar het is een terminal over een websocket en niet de framebuffer van een grafische kaart, en een VNC-client krijgt hem niet in beeld. Achter één consoletabblad zitten dan twee uitvoeringen, en het eerlijke antwoord voor de tussentijd is zeggen dat het tabblad er nog niet is, in plaats van een viewer openen die een zwarte rechthoek toont.
Pauzeren en de slaapstand verdienen een voetnoot, want ze zetten een val voor handhavingslogica. Zet je platform een machine stil zodra een klant over een limiet gaat, en betekent "stilzetten" pauzeren, dan vallen containers volledig buiten de handhaving: het commando wordt geweigerd, geen enkele worker meldt iets, en de klant draait door. Die grens hoort bij de modus te liggen en niet bij het commando. Een container stoppen kan uitstekend.
Swap is een productbeslissing, geen standaardwaarde
Hier is degene die in supporttickets terechtkomt.
Proxmox geeft een nieuwe container 512 MiB swap tenzij je iets anders zegt. Neem je dat stilzwijgend over, dan levert een plan dat verkocht is als "2 GiB geheugen" 2,5 GiB bruikbaar geheugen op, en het verschil verschijnt nergens als een groter getal: het verschijnt als een container die traag wordt in plaats van tegen een eerlijk tekort aan geheugen aan te lopen, maanden later, op een host die is gaan swappen.
Wij sturen de waarde bij elke aanmaak expliciet mee, met nul als onze standaard. Nul is een keuze en geen afwezigheid. Wat je ook kiest, kies het bewust, schrijf het op het plan, en zorg dat het getal dat een klant ziet het getal is dat de hypervisor krijgt.
Swap meten heeft zijn eigen prijs. De bulklijst die je voor elke gast in een cluster de tellers voor processor, geheugen, schijf en netwerk geeft, draagt helemaal geen swapveld, voor geen van beide soorten. De enige plek waar Proxmox het meldt is het statusendpoint per gast, dus het is één extra HTTP-aanroep per draaiende container, voor altijd. Wij lezen het één keer per minuut: drie keer per minuut verdrievoudigt de belasting op de hypervisor van iemand anders voor een getal dat in minuten beweegt, en één keer per vijf minuten zet precies één meting in een bak van vijf minuten, waardoor de maximumkolom gelijk wordt aan het gemiddelde en dus versiering is.
Twee fouten die we hebben uitgeleverd door aan te nemen dat het hetzelfde was
Ze stonden allebei maanden live voordat de ronde ernaar op zoek ging.
De eerste: ons importscherm zette containers in de lijst als virtuele machines. De cluster-resourcelijst met type=vm is geen QEMU-filter, hij geeft beide soorten terug, en het veld dat zei welke van de twee het was werd simpelweg niet gelezen. Er ging niets mis. De lijst klopte niet.
De tweede was stiller. Elke draaiende container kreeg twee aanroepen van de gastagent per polronde, plus één na elk commando, tegen een pad dat alleen voor QEMU bestaat. Elk daarvan was een gegarandeerde mislukking, en er kwam niets bovendrijven, want een mislukte optionele verrijking hoort te overleven en dat deed hij. Het is gevonden door een test die telt welke paden aangeroepen worden in plaats van op uitkomsten te toetsen, en die gewoonte is het kopiëren waard: toets je alleen op resultaten, dan blijft een hele categorie zinloos werk onzichtbaar.
Wat we zouden opschrijven voordat we het een of het ander verkopen
Beslis je wat een hostingproduct op Proxmox moet aanbieden, dan brengen vier vragen je een heel eind.
- Is de soort een eigenschap van het plan of een keuze bij het afrekenen? Allebei is verdedigbaar. Een standaardwaarde onder de keuze is dat niet: een klant die een container bestelde en een machine kreeg, kreeg een ander beveiligingsmodel, een andere kernel en andere mogelijkheden dan wat hij koos.
- Welke weigeringen zijn blijvend en welke zijn tijdelijk? Zeg dat in de interface, met die woorden. "Kan niet voor een container" en "nog niet gebouwd" zijn twee verschillende beloftes.
- Waar komt de bescherming tegen adresvervalsing vandaan? Het eerlijke gat in ons eigen werk: een gekloonde machine krijgt bij aflevering IP-filtering en een container nog niet. Proxmox heeft voor allebei dezelfde firewall-endpoints, dus het is een bouwstap en geen obstakel, maar een container die zonder wordt overgedragen kan verkeer sturen dat beweert van iemand anders te zijn.
- Wat laat de monitoring voor een container zien? Alles wat afgeleid is van een gastagent, een framebuffer of firmware is leeg. Leeg is prima. Leeg gepresenteerd als een gezonde nul is dat niet.
Het planveld, het bestelpad en het aanmaakverzoek zijn gebouwd en gemeten tegen de rauwe HTTP-vorm van de API. Wat we niet gedaan hebben is een container aanmaken op de productiehypervisor van iemand anders, dus de eerlijke omschrijving van onze containerondersteuning is "de vorm klopt en de retourslag is ongetoetst", en dat is iets nuttigs om hardop over je eigen platform te kunnen zeggen.
Dit kwam voort uit het bouwen van de Proxmox-integratie voor Provibr, waar de agent binnen het eigen netwerk van de klant draait en uitsluitend uitgaand verbindt. De verwante gewoonte om een geslaagd antwoord van een hypervisor niet te vertrouwen staat in waarom een Proxmox-200 geen uitkomst is.