Was bleibt von 1 GB RAM übrig? Leerlauf, Docker und CPU-Steal auf dem Mini-Server
Wie viel Speicher bleibt auf einem Server mit 1 GB RAM für eigene Dienste? Gemessen: 663 MiB verfügbar frisch, 714 MiB nach dem Abspecken, 669 MiB mit Docker und einem Container, im Dauerbetrieb rund 580 MiB. Mit Messskripten und 24 Stunden CPU-Steal.
Werbung Mit * markierte Links sind Werbelinks: Bei einem Kauf erhalten wir eine Provision, der Preis bleibt gleich. Als Amazon-Partner verdiene ich an qualifizierten Verkäufen. Mehr dazu

Ein netcup VPS piko G11s hat 1 vCPU und 1 GB RAM. Reicht das für Docker und ein paar Dienste, oder ist der Speicher schon voll, bevor der erste Container läuft? Diese Anleitung misst es nach, bevor in den nächsten Teilen echte Last dazukommt: Was belegt ein frisch installiertes Ubuntu, was bringt es, unnötige Dienste zu entfernen, was kostet Docker selbst und was ein einzelner Container. Dazu kommt eine Aufzeichnung über 24 Stunden, ob sich der kleine Server die CPU mit anderen teilen muss.
Dies ist Teil 1 der Reihe „Mini-Server“. Die Reihe packt Schritt für Schritt mehr auf denselben Server, bis er bricht, und misst jedes Mal, ob es ihn juckt.
Was Sie brauchen
- Einen Server mit 1 GB RAM und Ubuntu 24.04, hier das minimale Image aus dem Server Control Panel (SCP) von netcup.
- Zugang per SSH als root oder mit sudo.
- Rund zwei Stunden für die Messungen mit je drei Neustarts, dazu 24 Stunden Laufzeit für die Steal-Aufzeichnung.
- Grundwissen zu Docker, siehe Docker Compose unter Linux.
Schritt 1: Messskripte einrichten
Ein einzelner Wert für den freien Speicher sagt wenig. Direkt nach dem Start laufen noch Einrichtungsdienste, später springen Zeitgeber für Paketlisten oder Protokolle an. Deshalb gilt hier für jeden Zustand dasselbe Verfahren: Server neu starten, 10 Minuten warten, dann eine Momentaufnahme. Das passiert dreimal hintereinander, im Diagramm steht der mittlere der drei Werte (Median).
Die Momentaufnahme liest den verfügbaren Speicher, die größten Prozesse und die laufenden Dienste aus. Legen Sie dafür zuerst das Verzeichnis an und speichern Sie das Skript als /root/mini/leerlauf.sh:
# mkdir -p /root/mini#!/bin/sh
# Momentaufnahme Leerlauf
echo "== free -m"; free -m
echo "== dmesg Memory"; dmesg | grep -E "Memory: .*available"
echo "== RSS Top 15 (MiB)"
ps -eo rss,comm --sort=-rss | head -16 | awk 'NR==1{print;next}{printf "%7.1f %s\n",$1/1024,$2}'
echo "== RSS Summe (MiB)"; ps -eo rss= | awk '{s+=$1}END{printf "%.1f\n",s/1024}'
echo "== Dienste laufend"
systemctl list-units --type=service --state=running --no-pager --no-legend | awk '{print $1}'
echo "== Platte"; df -h / | tail -1
echo "== Start"; systemd-analyze | head -1Die wichtigste Zahl ist available aus free -m, im Kernel MemAvailable. Sie schätzt, wie viel Speicher neue Programme bekommen, ohne dass das System auslagern muss. Darin steckt auch Seitencache, den der Kernel bei Bedarf freigibt. used und die Summe der Prozesse (RSS) sind nur Hilfsgrößen: RSS zählt geteilte Bibliotheken bei jedem Prozess mit.
Für die Aufzeichnung über 24 Stunden schreibt ein zweites Skript, /root/mini/sammler.sh, jede Minute eine Zeile mit den CPU-Zählern aus /proc/stat und dem verfügbaren Speicher:
#!/bin/sh
# jede Minute eine CSV-Zeile
F=/root/mini/sammler.csv
[ -f $F ] || echo "zeit,user,nice,system,idle,iowait,irq,softirq,steal,memavail_kb" > $F
C=$(awk '/^cpu /{print $2","$3","$4","$5","$6","$7","$8","$9}' /proc/stat)
M=$(awk '/^MemAvailable/{print $2}' /proc/meminfo)
echo "$(date -u +%FT%TZ),$C,$M" >> $FEin systemd-Timer ruft es jede Minute auf. Die beiden Dateien /etc/systemd/system/mini-sammler.service und /etc/systemd/system/mini-sammler.timer:
[Unit]
Description=Mini-Server Messwerte
[Service]
Type=oneshot
ExecStart=/root/mini/sammler.sh[Unit]
Description=Mini-Server Messwerte jede Minute
[Timer]
OnCalendar=*-*-* *:*:00
AccuracySec=1s
[Install]
WantedBy=timers.target# chmod 700 /root/mini/sammler.sh /root/mini/leerlauf.sh
# systemctl daemon-reload
# systemctl enable --now mini-sammler.timerVerifizieren: Nach zwei Minuten stehen Kopfzeile und erste Werte in der Datei.
# tail -2 /root/mini/sammler.csvSchritt 2: Den frischen Server messen
Wo die ersten 67 MiB bleiben
Gebucht ist 1 GB, free -m zeigt als total aber nur 957 MiB. Den Rest belegen Kernel und Firmware, bevor das System überhaupt startet. Das Startprotokoll des Kernels zeigt die Aufteilung:
# dmesg | grep -E "Memory: .*available"Memory: 854696K/1044280K available (22528K kernel code, 4444K rwdata, 14456K rodata, 4948K init, 4756K bss, 189324K reserved, 0K cma-reserved)Einen Teil davon gibt der Kernel nach dem Start wieder frei, übrig bleiben die 957 MiB. Mit dieser Zahl rechnen alle weiteren Werte.
Verifizieren: 10 Minuten nach dem Start zeigt die Momentaufnahme den verfügbaren Speicher. Auf dem frischen Server sah eine der drei Messungen so aus:
# sh /root/mini/leerlauf.sh | head -4== free -m
total used free shared buff/cache available
Mem: 957 294 615 0 187 663
Swap: 0 0 0Frisch installiert: 663 MiB verfügbar
Das minimale Ubuntu 24.04.5 aus dem SCP bringt 678 Pakete mit und startet 19 Dienste. Gebraucht werden auf einem VPS nicht alle: snapd für Snap-Pakete, multipathd für Speichernetze mit mehreren Pfaden, udisks2 für Laufwerke auf dem Desktop und ModemManager für Mobilfunkmodems. Zusammen belegten diese vier Prozesse 89 MiB.

| Zustand | verfügbar (Median) | Spanne | Prozesse (RSS) | Dienste |
|---|---|---|---|---|
| Frisch installiert | 663 MiB | 659 bis 685 MiB | 256 MiB | 19 |
| Abgespeckt | 714 MiB | 699 bis 734 MiB | 156 MiB | 14 |
| Plus Docker | 687 MiB | 653 bis 690 MiB | 283 MiB | 16 |
| Plus ein Container | 669 MiB | 658 bis 684 MiB | 311 MiB | 16 |
Schritt 3: Vier unnötige Dienste entfernen
Die vier Pakete lassen sich mit einem Befehl entfernen. autoremove nimmt danach die Abhängigkeiten mit, die nur sie gebraucht haben, hier unter anderem ntfs-3g und die Bibliotheken von udisks2.
Achtung: Mit snapd verschwinden alle Snap-Pakete. Prüfen Sie vorher mit snap list, ob etwas installiert ist. Auf dem frischen Image war die Liste leer. apt entfernt außerdem die Metapakete ubuntu-server und ubuntu-server-minimal, weil sie die vier Pakete verlangen. Das System läuft ohne sie weiter, Updates kommen wie gewohnt.
# snap list
# apt-get purge snapd multipath-tools modemmanager udisks2
# apt-get autoremove --purge
# rm -rf /snap /var/snap /var/lib/snapd /var/cache/snapd
# rebootVerifizieren: Nach dem Neustart laufen 14 statt 19 Dienste, keiner der vier ist mehr dabei.
# systemctl list-units --type=service --state=running --no-legend | wc -l
# systemctl list-units --type=service --state=running --no-legend | grep -E 'snapd|multipath|udisks|ModemManager'14Ergebnis: Die Prozesse belegen zusammen 156 statt 256 MiB, verfügbar sind 714 statt 663 MiB. Dass die verfügbare Menge nur um gut 50 MiB steigt, obwohl die Prozesse 100 MiB weniger belegen, liegt an der Art, wie RSS zählt: Darin stecken auch die eingeblendeten Programmdateien und Bibliotheken. Diese Seiten führt der Kernel als Seitencache und zählt sie ohnehin als verfügbar, geteilte Bibliotheken stehen zudem bei jedem Prozess einzeln. Der Start wurde dabei knapp zwei Sekunden schneller, von rund 10,7 auf 8,8 Sekunden.
Schritt 4: Docker installieren
Docker kommt aus dem offiziellen Paketarchiv von Docker, wie in der Installationsanleitung von Docker beschrieben. Zuerst den Schlüssel des Archivs holen:
# apt-get install -y ca-certificates curl
# install -m 0755 -d /etc/apt/keyrings
# curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
# chmod a+r /etc/apt/keyrings/docker.ascDann die Paketquelle als Datei /etc/apt/sources.list.d/docker.sources anlegen. Bei anderen Ubuntu-Versionen steht statt noble deren Codename, den . /etc/os-release; echo $VERSION_CODENAME zeigt:
Types: deb
URIs: https://download.docker.com/linux/ubuntu
Suites: noble
Components: stable
Signed-By: /etc/apt/keyrings/docker.asc# apt-get update
# apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
# rebootVerifizieren: Der Docker-Dienst läuft und meldet seine Version.
# docker version --format 'Docker {{.Server.Version}}'Docker 29.9.3Ohne einen einzigen Container belegen die beiden Hintergrunddienste in der Prozessliste schon 127 MiB: dockerd rund 85 MiB, containerd rund 42 MiB. Das ist mehr, als das Abspecken dort eingespart hat. Ein großer Teil davon sind aber die eingeblendeten Programmdateien, die der Kernel als Seitencache führt und weiter als verfügbar zählt. Vom verfügbaren Speicher kostet Docker deshalb nur 27 MiB: 687 statt 714 MiB, immer noch mehr als im frischen Zustand. Auf der Platte belegt Docker rund 0,4 GB.

Schritt 5: Einen Container starten
Als Beispiel läuft ein nginx-Container, nur lokal erreichbar:
# docker run -d --name web --restart unless-stopped -p 127.0.0.1:8080:80 nginx:alpineVerifizieren: Der Container läuft und antwortet.
# docker stats --no-stream --format "table {{.Name}}\t{{.CPUPerc}}\t{{.MemUsage}}\t{{.MemPerc}}" web
# curl -sI http://127.0.0.1:8080 | head -1NAME CPU % MEM USAGE / LIMIT MEM %
web 0.00% 9.625MiB / 957.5MiB 1.01%
HTTP/1.1 200 OKnginx selbst braucht knapp 10 MiB, dazu kommt pro Container ein Verwaltungsprozess (containerd-shim) mit rund 11 MiB. Verfügbar bleiben 669 MiB. Das Image belegt 95 MB auf der Platte. Die eigentliche Grundlast trägt also nicht der Container, sondern Docker selbst. Jeder weitere kleine Container kostet vor allem seinen eigenen Speicher plus den Verwaltungsprozess.
Schritt 6: CPU-Steal über 24 Stunden
Ein VPS teilt sich die Rechenkerne des Hosts mit den virtuellen Maschinen anderer Kunden. Will die virtuelle CPU rechnen, während der Host gerade eine dieser anderen Maschinen bedient, zählt der Kernel die Wartezeit als Steal. Mit dem eigenen Datenverkehr hat das nichts zu tun: Auch ein Server, der hinter einer Firewall völlig im Leerlauf steht, kann Steal haben, wenn die Nachbarn auf dem Host viel rechnen. Der Sammler aus Schritt 1 liest den Zähler jede Minute aus /proc/stat. Der Anteil je Minute ergibt sich aus der Differenz zweier Zeilen: Steal geteilt durch die Summe aller CPU-Zähler. Dieser Befehl rechnet das für die ganze Datei aus und überspringt Neustarts, bei denen die Zähler wieder bei null beginnen:
# awk -F, 'NR>2{t=0;neg=0;for(i=2;i<=9;i++){d[i]=$i-p[i];t+=d[i];if(d[i]<0)neg=1} if(t>0&&!neg){s=100*d[9]/t;n++;sum+=s;if(s>m)m=s}} NR>1{for(i=2;i<=9;i++)p[i]=$i} END{printf "Minuten %d, Steal Mittel %.2f %%, Maximum %.2f %%\n",n,sum/n,m}' /root/mini/sammler.csvMinuten 4884, Steal Mittel 0.01 %, Maximum 0.43 %Verifizieren: Nach 24 Stunden stehen rund 1.440 Zeilen in der Datei.
# wc -l /root/mini/sammler.csv
Ausgewertet wurden 1.440 Minutenwerte, mit Docker und dem nginx-Container im Leerlauf. Der Steal lag im Mittel bei 0,01 %, in 95 % der Minuten bei höchstens 0,02 %. Nur eine einzige Minute am Morgen erreichte 0,41 %, über 5 % lag keine. Die feinste Stufe liegt bei rund 0,02 %, weil der Kernel die Zeit in Hundertstelsekunden zählt: Eine Minute hat 6.000 davon. Die Aufzeichnung lief insgesamt gut drei Tage, auch dann blieb die schlechteste Minute bei 0,43 %. Steal entsteht allerdings nur, wenn die eigene CPU rechnen will, und im Leerlauf lag die eigene Last im Mittel bei 0,29 %. Aussagekräftiger ist deshalb die Minute mit 0,41 %: Es war die Minute des automatischen Updates mit rund einem Drittel Last. Selbst dort blieb der Steal unter einem halben Prozent. Anzeichen für einen überbuchten Host gab es keine. Ob das unter Dauerlast hält, zeigen die nächsten Teile.
Im Dauerbetrieb sinkt der verfügbare Speicher
Die untere Linie im Diagramm zeigt eine zweite Beobachtung: Über den Tag lagen zwischen 576 und 623 MiB verfügbar, also weniger als die 669 MiB kurz nach dem Start. Der Sprung kam in einer einzigen Minute, als die letzte Momentaufnahme lief: Wer viele Dateien und Verzeichnisse durchläuft, etwa bei Updates, Backups oder einer Messung mit du, füllt die Zwischenspeicher des Kernels für Dateien und Verzeichnisse (Slab). Nach drei Tagen waren das 230 MiB. Den Großteil davon gibt der Kernel bei Bedarf frei, MemAvailable rechnet ihn aber nur teilweise mit ein. Dazu kam fwupd, das über seinen Zeitgeber gestartet war und rund 39 MiB belegte. Während der automatischen Updates fiel der verfügbare Speicher kurz bis auf gut 540 MiB. Planen Sie deshalb mit rund 580 MiB für eigene Dienste und etwas Reserve für solche Spitzen, nicht mit dem Wert direkt nach dem Start.
Verifizieren: So sehen Sie die Zwischenspeicher des Kernels und ob fwupd läuft.
# grep -E "^(Slab|SReclaimable)" /proc/meminfo
# ps -eo rss,comm --sort=-rss | head -3Slab: 235324 kB
SReclaimable: 184616 kB
RSS COMMAND
43828 dockerd
39812 fwupdWie Sie Steal mit Bordmitteln wie mpstat und sar beobachten und ab wann er stört, steht in Steal-Time messen.
Warum ein einzelner Wert nicht reicht
Zwischen drei Messungen desselben Zustands lagen bis zu 37 MiB. Zwei Ausreißer fielen besonders auf: Bei einer Messung des frischen Systems liefen 21 statt 19 Dienste, bei einer Messung mit Docker 19 statt 16. Zum Messzeitpunkt lief gerade fwupd, der Dienst für Firmware-Updates, samt upowerd und polkitd, und belegte rund 60 MiB zusätzlich. fwupd startet über einen eigenen Zeitgeber und taucht deshalb mal auf und mal nicht. Wer nur einmal misst, kann so zwei Zustände verwechseln. Bei einem Server mit 1 GB sind 30 bis 60 MiB Schwankung 3 bis 6 % des Speichers, das ist für die Planung relevant.
Typische Fehler
- Start dauert über 2 Minuten,
systemd-analyze blamezeigt2min 252ms systemd-networkd-wait-online.service Der Server hat eine zweite Netzwerkkarte ohne Konfiguration, etwa eine übrig gebliebene Karte für ein Cloud vLAN. Der Start wartet, bis alle Karten online sind. Karte im SCP entfernen oder in netplan als optional markieren (
optional: true). Hier verkürzte das Entfernen den Start von 2 Minuten 7 Sekunden auf rund 11 Sekunden.- Die SCP-API lehnt das Entfernen einer Netzwerkkarte ab:
"code": "server.vxlan.wrongstate","message": "Server must be in state 'SHUTOFF'." Karten lassen sich nur am ausgeschalteten Server entfernen. Server ausschalten, Karte entfernen, wieder einschalten. Das dauerte hier insgesamt 22 Sekunden.
Häufige Fragen
Sollte ich auf 1 GB RAM überhaupt Docker nutzen?
Docker belegt hier in der Prozessliste rund 127 MiB für dockerd und containerd, am verfügbaren Speicher kostet es rund 30 MiB, mit einem Container rund 45 MiB. Dafür bekommen Sie fertige Images, einfache Updates und klare Grenzen pro Dienst. Für einen einzelnen Dienst ohne Docker sparen Sie das, ab zwei oder drei Diensten wiegt der Komfort die Kosten meist auf. Wie weit der Speicher reicht, messen die nächsten Teile.
Fehlt nach dem Abspecken etwas Wichtiges?
Für einen VPS mit einer virtuellen Platte nicht. Die automatischen Sicherheitsupdates (unattended-upgrades) bleiben bewusst installiert, sie belegen rund 23 MiB. Wer sie entfernt, muss Updates selbst einspielen.
Warum hat der Server keinen Swap?
Das Image aus dem SCP legt keinen Swap an. Läuft der Speicher voll, beendet der Kernel Prozesse. Ob Swap oder zram bei 1 GB helfen, misst ein eigener Teil der Reihe.
Fazit
Ein frisches Ubuntu lässt auf dem VPS piko G11s 663 von 957 MiB verfügbar. Vier unnötige Dienste zu entfernen bringt gut 50 MiB, Docker samt einem kleinen Container kostet davon rund 45 MiB wieder. Mit Docker und einem Container bleiben rund 670 MiB für eigene Dienste, also gut zwei Drittel des Speichers. Im Dauerbetrieb sind es eher 580 MiB, weil Kernel-Zwischenspeicher und fwupd dazukommen. Steal spielte im Leerlauf keine Rolle, selbst während des automatischen Updates nicht. Teil 2 der Reihe misst, wie viele Aufrufe eine statische Website mit Caddy auf diesem Server aushält.
Weiterführende Anleitungen und Quellen
- Steal-Time messen: Wie viel Rechenzeit Ihr netcup-VPS verliert
- Wann bricht der Server ein? Lasttest mit k6 auf einem kleinen VPS
- Docker Compose unter Linux
- Linux-Server absichern: UFW-Firewall und Fail2ban
- Docker-Container automatisch aktualisieren
- Docker: Install Docker Engine on Ubuntu
- Linux-Kernel: Dokumentation zu /proc, darunter MemAvailable
- man proc_stat: Felder von /proc/stat, darunter steal


