Precipice.tech Logo precipice.tech
Start / Blog / Container statt VM
Deep Dive · Virtualisierung

Eure VMs reservieren Speicher, den niemand benutzt

Eine VM bekommt Arbeitsspeicher zugewiesen, ein Container belegt nur, was er anfasst. Das ist kein Detail der Verwaltung, sondern der Grund, warum in vielen Clustern 80 Prozent des RAM belegt sind und trotzdem keine Anwendung schnell läuft. Wir rechnen es auf einem 512-GB-Host durch, messen es nach, und benennen die drei Fälle, in denen die VM trotzdem die richtige Antwort bleibt.

Autor Niklas Grempels Stand cgroup v2, KVM/QEMU, Proxmox VE 9 Lesezeit ~15 min Level Admin / Architekt
01

Das Symptom: der Cluster ist voll, aber nichts arbeitet

Das Gespräch läuft fast immer gleich. Der Virtualisierungs-Cluster ist bei 80 bis 90 Prozent Speicherbelegung, das Monitoring meldet gelb, die Beschaffung von zwei weiteren Hosts liegt schon im Freigabelauf. Gleichzeitig kann niemand eine einzige VM benennen, deren Anwendung tatsächlich am Speicher hängt. Die Auslastung ist hoch, die Arbeit ist es nicht.

Der Grund steckt nicht in der Applikation, sondern im Modell. Eine VM bekommt Arbeitsspeicher zugewiesen, ein Container belegt ihn. Das klingt nach einer Formulierungsfrage und ist in Wirklichkeit die ganze Differenz: zugewiesener Speicher ist für den Host verbraucht, unabhängig davon, ob im Gast jemals ein Byte davon benutzt wird. Belegter Speicher ist messbar an der Arbeit, die er trägt.

Dazu kommt der zweite Posten, der in keiner Sizing-Tabelle auftaucht: jede VM bringt ein vollständiges Betriebssystem mit. Einen eigenen Kernel, eigene Page Tables, eigenes systemd, eigenen Monitoring-Agent, eigenen Log-Shipper, eigenen Paketcache. Bei vierzig VMs betreibt man vierzig Kopien derselben Grundlast, um vierzig Instanzen derselben Anwendung zu fahren.

Worum es hier nicht geht Nicht um Docker gegen VMware als Glaubensfrage, und nicht um CPU-Overhead. Der Rechenaufwand der Virtualisierung ist auf moderner Hardware mit VT-x und EPT klein, meist im einstelligen Prozentbereich. Der Speicher ist die Stelle, an der das Modell wirklich Geld kostet, weil RAM die teuerste und am schlechtesten überbuchbare Ressource im Rack ist.
02

Was eine VM wirklich belegt

Eine VM mit 4 GB kostet den Host nicht 4 GB, sondern mehr. Und sie gibt davon nichts zurück, sobald der Gast den Speicher einmal angefasst hat. Vier Posten summieren sich:

  • Die Zuweisung selbst. Bei aktiviertem Preallocation oder Hugepage-Backing ist der Speicher ab dem Start weg. Ohne Preallocation wächst die Belegung nach Bedarf, aber nur in eine Richtung: einmal berührte Gastseiten bleiben beim QEMU-Prozess, weil der Host nicht wissen kann, dass der Gast sie längst freigegeben hat.
  • Das Gast-Betriebssystem. Ein schlank installiertes Debian oder RHEL mit systemd, SSH, Monitoring-Agent und Log-Shipper liegt im Betrieb realistisch bei 400 bis 600 MB. Nicht dramatisch, aber es multipliziert sich mit der Zahl der VMs.
  • Der Page Cache im Gast. Das ist der unterschätzte Posten. Ein Linux-Kernel betrachtet freien Speicher als verschwendeten Speicher und füllt ihn mit Dateisystem-Cache. Genau das ist im Gast das richtige Verhalten und für den Host fatal: aus dessen Sicht sind die Seiten benutzt. Eine VM mit 4 GB, deren Anwendung 700 MB braucht, meldet nach einer Woche Laufzeit fast 4 GB belegt, davon über 2 GB Cache für Dateien, die vielleicht nie wieder gelesen werden.
  • Der Hypervisor je Gast. Der QEMU-Prozess selbst, Shadow- bzw. verschachtelte Page Tables, Geräteemulation, vhost-Puffer. Je VM grob 80 bis 200 MB, abhängig von Gerätemodell und Speichergröße.

Bei ungünstiger Konfiguration kommt ein fünfter Posten dazu: doppelter Cache. Läuft eine virtuelle Platte mit cache=writeback, liegen dieselben Blöcke im Page Cache des Gasts und im Page Cache des Hosts. Deshalb ist cache=none (O_DIRECT am Host) für Produktionsgäste der Standard, nicht aus Performance-Gründen allein, sondern weil es eine ganze Cache-Ebene einspart.

shell
# Was der Host fuer eine VM wirklich haelt. rss ist die Wahrheit,
# actual nur der aktuell erlaubte Ballon-Wert.
virsh dommemstat db01 --live

# actual   4194304    <- der VM zugewiesen (KiB)
# rss      4098112    <- was der Host tatsaechlich fuer sie haelt
# available 4062336   <- was der Gast an Gesamtspeicher sieht
# unused    182400    <- was im Gast frei ist: 178 MB von 4 GB
# usable   2611200    <- frei PLUS reclaimbarer Cache: 2,5 GB

# Der Vergleich, der die Luecke zeigt: usable ist der Speicher, den
# der Gast hergeben koennte, aber nicht hergibt.
for d in $(virsh list --name); do
  echo -n "$d "
  virsh dommemstat "$d" | awk '/^(actual|rss|usable)/ {printf "%s=%dMB ", $1, $2/1024}'
  echo
done
Die Zahl, auf die es ankommt Vergleicht in dieser Ausgabe rss mit dem, was die Anwendung im Gast an anonymem Speicher hält. Die Differenz ist der Preis des Modells. Sie liegt bei typisch dimensionierten VMs im Bereich von 60 bis 80 Prozent der Zuweisung, und sie steigt mit der Laufzeit, weil der Gast-Cache sich füllt.
03

Was ein Container belegt: nichts, was er nicht anfasst

Ein Container ist keine kleine VM. Er ist ein normaler Prozess auf dem Host-Kernel, dem über Namespaces eine eigene Sicht und über cgroups eine Ressourcengrenze gegeben wurde. Daraus folgt der ganze Speichervorteil, und zwar an vier Stellen.

Ein Kernel für alle

Der Kernel läuft einmal. Es gibt eine Prozesstabelle, einen Scheduler, einen Satz Page Tables pro Prozess statt pro Gast, einen Netzwerkstack. Auch das Host-Userland existiert einmal. Der Posten, der im VM-Modell mit der Zahl der Instanzen multipliziert wird, ist im Container-Modell eine Konstante.

Ein Page Cache für alle

Alle Container teilen den Page Cache des Hosts. Fünfzig Container aus demselben Image lesen dieselben Inodes der Read-only-Layer, also liegen libc, die JVM oder der Python-Interpreter genau einmal im Speicher, unabhängig davon, wie oft der Container läuft. Bei VMs ist das ausgeschlossen: fünfzig Gäste bringen fünfzig separate Kopien derselben Bibliothek mit, weil die Seiten in fünfzig getrennten Adressräumen liegen.

Ein Limit ist keine Reservierung

Das ist der Kern der Sache. memory.max in cgroup v2 ist eine Obergrenze, keine Zuteilung. Ein Container mit memory.max=4G, dessen Prozess 700 MB anonymen Speicher hält, kostet den Host 700 MB. Das Limit kostet null. Man kann Spitzenreserven großzügig setzen, ohne sie zu bezahlen. Genau das ist im VM-Modell unmöglich, dort ist die Reserve der Preis.

Wer umgekehrt eine echte Reservierung braucht, hat sie auch: memory.min schützt einen Bereich hart gegen Reclaim, memory.low weich. Die Reservierung wird damit zur Ausnahme für die zwei kritischen Dienste, statt zum Default für alles.

Cache ist rückholbar, und der Kernel weiß es

Der Page Cache eines Containers zählt in memory.current mit, ist aber jederzeit räumbar. Steigt der Druck, nimmt der Kernel die Seiten zurück, ohne dass ein Prozess stirbt. Beim Gast-Cache in einer VM kann er das nicht, weil er die Seite nur als benutzten Gastspeicher sieht, nicht als Cache. Das ist derselbe physische Speicher mit einem völlig anderen Verhalten unter Druck.

shell
# cgroup v2: Limit, aktuelle Belegung, historischer Hoechstwert
cd /sys/fs/cgroup/system.slice/docker-abc123.scope
cat memory.max memory.current memory.peak

# 4294967296     <- Limit: kostet nichts
# 1043726336     <- aktuell belegt: 995 MB
# 1512136704     <- Spitze seit Start: 1,4 GB

# Die Aufschluesselung entscheidet, was davon echter Bedarf ist
grep -E '^(anon|file|slab|kernel_stack|sock) ' memory.stat

# anon         715653120   <- 682 MB: das ist der echte Bedarf
# file         298844160   <- 285 MB Cache: raeumbar, kein Bedarf
# slab          19226624
# kernel_stack   3244032

# PSI zeigt Speicherdruck, bevor der OOM-Killer es tut
cat memory.pressure
anon statt current Für Sizing zählt anon, nicht memory.current. current enthält den Cache und läuft in einem gesunden System immer gegen das Limit, das ist normal und kein Alarm. Auch docker stats rechnet deshalb inactive_file heraus, bevor es eine Zahl anzeigt. Wer nach current dimensioniert, baut die VM-Überdimensionierung in YAML nach.
04

Ein Host, drei Rechnungen

Rechnen wir es konkret. Der Host hat 512 GB RAM. Darauf sollen 96 gleichartige Dienste laufen, jeder mit einem gemessenen Arbeitsset von rund 700 MB anonymem Speicher und Spitzen um 1,2 GB. Die Anwendung ist in allen drei Modellen identisch, es ändert sich ausschließlich, was um sie herum gebaut wird.

0256 GB512 GB
Nutzdaten der Anwendung Gast- bzw. Host-Betriebssystem zugewiesen, aber nicht genutzt Hypervisor und Runtime gemeinsamer Page Cache frei
Abb. 1 · 96 Dienste mit je 700 MB Arbeitsset auf einem Host mit 512 GB (Modell oben umschalten)

Die Kupferfläche im ersten Modell ist der ganze Punkt: 269 GB, mehr als die Hälfte des Hosts, sind zugewiesen und tragen keine Arbeit. Sie sind im Gast als Page Cache oder freier Speicher gebunden, der Host kann sie nicht vergeben, und keine Beschaffung löst das Problem, weil die nächsten Hosts mit derselben Quote arbeiten.

Der zweite Blick lohnt auf die Balken: die teal-farbene Fläche links, die echten Nutzdaten der Anwendung, ist in allen drei Modellen exakt gleich groß. Der Faktor kommt nicht daher, dass Container die Anwendung schrumpfen. Er ist die Differenz zwischen zugewiesen und benutzt.

CONTAINERRSS plus Runtime-Anteil
0,73GB
VM, knapp dimensioniert1,5 GB zugewiesen
1,65GB
VM, wie üblich dimensioniert4 GB zugewiesen
4,15GB
Hostseitiger Speicherbedarf je Dienst, gleiche Anwendung mit 700 MB Arbeitsset. Die VM-Werte enthalten Zuweisung plus rund 150 MB QEMU und Page Tables, der Container-Wert 700 MB anonymen Speicher plus rund 30 MB Runtime-Anteil. Das Gast-Betriebssystem steckt bei den VMs innerhalb der Zuweisung, es verkleinert also den nutzbaren Rest.
Abb. 2 · Was ein Dienst den Host kostet, je nach Verpackung

Und hier kommt der ehrliche Zwischenruf: die 4 GB im dritten Balken sind eine Entscheidung, keine Naturkonstante. Wer VMs mit 1,5 GB baut, halbiert die Lücke. Zwei Dinge bleiben aber auch dann bestehen. Erstens zahlt man weiterhin 96 Gast-Kernel samt 96 Kopien der Grundlast. Zweitens verliert man mit der knappen Dimensionierung genau die Kopfreserve, die der Grund für die großzügige Zuweisung war: eine VM, deren Anwendung in eine Spitze von 1,2 GB läuft, beginnt bei 1,5 GB zu swappen oder trifft den OOM-Killer im Gast. Beim Container ist derselbe Puffer als Limit gratis.

PostenVM je DienstContainerWarum
Nutzdaten der Anwendung67 GB67 GBgleiche Software, gleiches Arbeitsset
Gast-Betriebssysteme48 GBentfällt96 Kopien der Grundlast gegen keine
Kernel und Host-Grundlast8 GB8 GBin beiden Modellen einmal
Zugewiesen, ungenutzt269 GB0 GBLimit statt Reservierung
Hypervisor bzw. Runtime14 GB3 GBkein QEMU-Prozess je Dienst
Page Cache96 getrennte Cachesein geteilter Cachegemeinsame Image-Layer
Nicht rückholbar belegt406 GB78 GBFaktor 5,2

Bei dieser Dichte verschiebt sich der Engpass. 96 Container in 78 GB heißt nicht, dass 500 Dienste auf den Host passen: irgendwann limitieren CPU, Netzwerk-Sockets, Dateideskriptoren oder die Ausfalldomäne. Genau das ist der gewünschte Zustand. Der Speicher hört auf, die bindende Grenze zu sein, und die Kapazitätsplanung dreht sich um Größen, die man mit Lasttests belegen kann.

05

Messen statt schätzen

Bevor irgendetwas migriert wird, wird gemessen, und zwar am bestehenden VM-Bestand. Die Frage ist nicht, wie viel RAM eine VM hat, sondern wie viel ihre Anwendung braucht. Drei Ausgaben genügen.

Frage 1: Wie groß ist das Arbeitsset wirklich?

Im Gast interessiert nur der anonyme Speicher der Anwendung. free -m ist dafür die falsche Ausgabe, weil sie den Cache mitzählt und deshalb bei jeder länger laufenden VM alarmierend aussieht.

shell (im Gast)
# Anonymer Speicher aller Prozesse: das ist der echte Bedarf.
# available in der zweiten Zeile ist die interessante Zahl,
# nicht used.
free -m
grep -E '^(AnonPages|Cached|Committed_AS|MemAvailable)' /proc/meminfo

# Pro Dienst, mit korrekt aufgeteiltem Shared Memory (PSS)
smem -k -c "pss uss command" -r | head -15
systemd-cgtop -m --order=memory

# Spitze ueber die Zeit, nicht der Momentwert: cgroup v2 merkt sich das
cat /sys/fs/cgroup/system.slice/app.service/memory.peak

Frage 2: Wie viel Zuweisung liegt clusterweit brach?

Diese Zahl ist die Grundlage jedes Gesprächs über Beschaffung. Sie kommt vom Hypervisor, nicht aus dem Gast, und sie braucht den Balloon-Treiber im Gast, sonst liefert virsh keine usable-Werte.

shell (am Host)
# Brachliegende Zuweisung ueber alle laufenden Gaeste summieren.
# usable = im Gast frei plus reclaimbarer Gast-Cache.
for d in $(virsh list --name); do
  virsh dommemstat "$d" | awk -v n="$d" '
    /^actual/ {a=$2} /^usable/ {u=$2}
    END {printf "%-20s zugewiesen %6d MB   brach %6d MB (%d %%)\n",
                n, a/1024, u/1024, (a?100*u/a:0)}'
done

# Proxmox: Zuweisung gegen tatsaechliche Host-Belegung
qm list | awk 'NR>1 {s+=$4} END {print "zugewiesen:", s, "MB"}'
free -m

Frage 3: Was würde der Container-Weg kosten?

Das ist keine Schätzung, sondern eine Messung mit einem einzigen Kandidaten. Ein Dienst wird containerisiert, mit einem großzügigen Limit gestartet, unter Produktionslast beobachtet, danach werden memory.peak und anon abgelesen. Multipliziert mit der Zahl gleichartiger Dienste ergibt das eine belastbare Zahl statt eines Prospektversprechens.

BeobachtungInterpretationNächster Schritt
usable über 50 % von actualVM ist deutlich zu großKandidat für Container oder Downsizing
usable nahe 0, rss = actualVM nutzt ihren Speicherhier gewinnt die Migration wenig RAM
AnonPages klein, Cached großCache füllt die ZuweisungBedarf ist der Anon-Wert, nicht used
memory.peak weit unter LimitLimit ist reine Reserveso lassen, es kostet nichts
memory.pressure steigtechter Druck, Reclaim läuftLimit anheben oder Dienst verteilen
06

Ballooning und KSM: Reparatur am falschen Modell

Die Hypervisor-Welt hat für dieses Problem Werkzeuge, und sie funktionieren. Nur sind sie Gegenmaßnahmen gegen eine Eigenschaft der Architektur, nicht deren Behebung. Wer sie einschaltet, sollte wissen, was er dafür zahlt.

MechanismusWas er tutWas er kostet
virtio-balloonzieht ungenutzte Gastseiten zurückreagiert in Sekunden, nicht Mikrosekunden; braucht einen kooperierenden Gast
free page reportingGast meldet freie Seiten laufendnur mit neuerem Kernel und Treiber; hilft nicht gegen Gast-Cache
KSMdedupliziert identische Seitendauerhafte CPU-Last durch Scannen, Latenzspitzen beim Copy-on-Write, Seitenkanal-Risiko zwischen Mandanten
Host-Swaplagert kalte Gastseiten ausder Gast weiß nichts davon und trifft die falschen Entscheidungen
Transparent Huge Pagessenkt TLB-Druckarbeitet gegen KSM und kann Speicher aufblähen
shell
# Bringt KSM auf diesem Host ueberhaupt etwas?
grep -H '' /sys/kernel/mm/ksm/{run,pages_sharing,pages_shared,full_scans}

# pages_sharing x 4 KiB = eingesparter Speicher.
# Unter ~5 % des Hosts ist die CPU-Last dafuer schwer zu begruenden.
awk '{printf "KSM spart %d MB\n", $1*4/1024}' /sys/kernel/mm/ksm/pages_sharing

# Ballooning wirkt nur mit Treiber im Gast. Fehlt er, ist actual == rss.
virsh qemu-monitor-command db01 --hmp 'info balloon'

Das entscheidende Problem an beidem: es sind Regelkreise mit Verzögerung. Der Ballon gibt Speicher zurück, wenn Druck entsteht, nicht bevor er entsteht. Genau in dem Moment, in dem der Host knapp wird, beginnt er, Gästen Seiten zu entziehen, deren Kernel darauf mit Reclaim und im schlechten Fall mit Swapping reagiert. Die Speicherknappheit wird damit in eine Latenzspitze in der Anwendung übersetzt, und zwar unter Last. Der Container-Weg hat diesen Regelkreis nicht, weil er den Speicher nie belegt hat.

KSM in Mandantenumgebungen Seitendeduplizierung über Mandantengrenzen hinweg ist seit Jahren als Seitenkanal beschrieben: Zugriffszeiten auf dedupliziert vorliegende Seiten verraten, dass ein anderer Gast denselben Inhalt hält. Wer VMs genau wegen der Isolation betreibt und dann KSM clusterweit einschaltet, hebt einen Teil der Begründung auf, für die er das VM-Modell gewählt hat.
07

Derselbe Fehler, nur in YAML

Der Vorteil ist kein Naturgesetz der Container, sondern eine Folge der Konfiguration. Man kann ihn vollständig verschenken, und in Kubernetes-Clustern passiert genau das regelmäßig: requests werden gesetzt wie VM-Größen.

requests.memory ist die Zahl, gegen die der Scheduler bucht. Sie ist die Reservierung. limits.memory ist die Obergrenze und landet als memory.max im cgroup. Wer aus Gewohnheit requests: 4Gi für einen Dienst mit 700 MB Arbeitsset schreibt, hat die VM-Reservierung nachgebaut, inklusive der brachliegenden Kapazität, nur ohne die Isolation dafür zu bekommen. Das ist der schlechteste Punkt von beiden Modellen.

yaml
# Falsch: request wie eine VM-Groesse. Der Scheduler bucht 4 Gi,
# benutzt werden 700 MB. Die Differenz ist verlorene Kapazitaet.
resources:
  requests: { memory: 4Gi }
  limits:   { memory: 4Gi }

# Richtig: request am gemessenen Arbeitsset plus kleiner Puffer,
# limit grosszuegig fuer die Spitze. Das Limit kostet nichts.
resources:
  requests: { memory: 900Mi }   # anon aus memory.stat plus ~25 %
  limits:   { memory: 2Gi }     # memory.peak plus Reserve
Die Ausnahme kennt man Für Dienste, die einen Speicherbereich hart brauchen und einen Reclaim nicht verzeihen, etwa Datenbanken mit großem Buffer Pool, setzt man requests gleich limits bewusst. Diese Klasse gehört in die Garantierte-Klasse, gerne auch weiter in eine VM. Der Fehler ist nicht die Reservierung, sondern die Reservierung als Standard für alles.

Dieselbe Regel gilt jenseits von Kubernetes. Ein MemoryMax in einer systemd-Unit oder ein --memory am Container-Start kostet nichts, solange es nicht erreicht wird. Sobald jemand anfängt, mit memory.min Bereiche festzunageln, ist er zurück im Reservierungsmodell und sollte dafür einen Grund nennen können.

08

Der ehrliche Teil: wo die VM richtig bleibt

Wer aus dem Speicherargument die Regel „nie wieder VMs“ macht, macht einen zweiten Fehler nach dem ersten. Es gibt Fälle, in denen das Reservierungsmodell nicht der Preis ist, sondern das Produkt.

  • Ein anderer Kernel. Container teilen den Kernel des Hosts. Windows, ein Legacy-System mit eigener Kernelversion, ein Gast mit exotischen Modulen oder eigenem Scheduler-Patch: das geht nicht als Container, und keine Rechnung ändert das.
  • Isolation als Zusage. Der Container ist durch Namespaces und Seccomp vom Kernel getrennt, nicht von der Hardware. Die Angriffsfläche ist die Syscall-Schnittstelle eines gemeinsamen Kernels. Wo fremde Mandanten oder fremder Code laufen, ist die VM-Grenze die belastbarere Zusage, und ihr Speicherpreis ist dann gekaufte Sicherheit.
  • Nachweispflichten. Wenn ein Prüfer, ein Kunde oder eine Zertifizierung eine dokumentierte Trennung auf Hypervisor-Ebene verlangt, ist das eine Anforderung und keine technische Meinung. Sie steht über der Effizienzrechnung.
  • Ausfalldomäne. Ein Kernel-Panic in einer VM trifft eine VM. Auf einem Container-Host trifft er alles, was darauf läuft. Dasselbe gilt für Kernel-Updates: ein Reboot des Container-Hosts ist ein Reboot aller Dienste.
  • Zustandsbehaftete Systeme mit Gerätezugriff. GPU-Passthrough, spezielle PCIe-Karten, Lizenzdongles, Systeme mit erwarteten Live-Migrationen: hier ist der Hypervisor der Ort, an dem diese Mechanik existiert.

Dazwischen liegt eine Zone, die man kennen sollte. MicroVMs wie Firecracker oder Cloud Hypervisor senken den Aufwand je Gast erheblich, weil sie die Geräteemulation radikal reduzieren, und Ansätze wie Kata Containers setzen die Container-Schnittstelle auf eine VM-Grenze. Sie verschieben die Kurve deutlich, aber sie heben den Kernpunkt nicht auf: es bleibt ein eigener Kernel, ein eigener Page Cache und eine eigene Speicherzuweisung je Instanz.

Die Realität ist geschichtet In der Praxis ist die Frage selten „VM oder Container“, sondern wo die Grenze liegt. Der Container-Host läuft in vielen Umgebungen selbst als VM, und das ist keine Inkonsequenz: die VM-Ebene trägt Mandanten- und Wartungsgrenzen, die Container-Ebene trägt die Dienste. Falsch ist nur das Muster mit einer VM je Dienst. Das kombiniert die Kosten der einen Ebene mit der Verwaltungslast der anderen. Wie sich die Größe dieser Trag-VMs auf Speicherlokalität auswirkt, steht in Die NUMA-Falle.
09

Betriebsregeln, die den Speicher freihalten

Die Migration muss nicht groß sein, um zu wirken. Sie muss an den Diensten anfangen, bei denen die Lücke zwischen Zuweisung und Bedarf am größten ist, und das sind fast immer die vielen kleinen, gleichartigen.

RegelWarum
Sizing gegen anonymen Speicher, nicht gegen usedPage Cache ist kein Bedarf, sondern Nutzung freier Kapazität
Brachliegende Zuweisung clusterweit berichtenusable je Gast summiert ist die Zahl, die eine Beschaffung entscheidet
Viele gleichartige Dienste zuerst migrierendort multipliziert sich die eingesparte Grundlast
Limits großzügig, Reservierungen sparsamein Limit kostet nichts, eine Reservierung kostet den ganzen Betrag
Eine VM je Dienst als Anti-Muster behandelnzahlt VM-Kosten und liefert nur Container-Isolation, wenn ohnehin geteilt wird
KSM nur mit gemessenem Nutzen und nie mandantenübergreifendCPU-Last und Seitenkanal gegen den eigentlichen Zweck des VM-Modells
Ausfalldomäne des Container-Hosts explizit festlegenein Kernel für alle heißt auch ein Reboot für alle
VM-Ebene für Kernel, Mandanten und Nachweise, Container für Dienstejede Ebene trägt, was nur sie kann
Zum Mitnehmen Der Speicher in einem überfüllten Virtualisierungs-Cluster ist selten knapp, er ist verteilt. Reserviert an Gäste, die ihn nicht brauchen, gebunden in 96 Kopien desselben Betriebssystems, gefüllt mit Cache, den kein Prozess mehr liest. Wer die Lücke zwischen actual und Bedarf einmal clusterweit summiert, hat meistens die nächsten zwei Hosts schon im Rack stehen. Sie sind nur falsch aufgeteilt.
Nächster Schritt

Erst die Lücke messen, dann Hosts kaufen

Wir sehen regelmäßig Cluster, in denen mehr als die Hälfte des Arbeitsspeichers zugewiesen ist, ohne Arbeit zu tragen. Bevor Budget in weitere Hosts fließt, schauen wir uns an, wie viel davon bei euch brachliegt und welche Dienste sich mit vertretbarem Aufwand umziehen lassen.