aslain.dev
0%
01 Hizmetler 02 Hakkımda 03 Projeler 04 Stack 05 Blog 06 İletişim
← Tüm makaleler Game-Server

Docker Game-Server: portabel im Container betreiben

Einen Docker Game-Server aufzusetzen löst deinen Server von der Abhängigkeit von einem einzigen Betriebssystem oder einer einzigen Maschine: Jede Abhängigkeit, Version und Konfiguration wird in einem Image verpackt, sodass der Server überall, wohin du ihn verschiebst, gleich läuft. Du sagst nie wieder „auf meinem Rechner lief es, aber auf dem VPS startete es nicht". In diesem Artikel betrachten wir die Logik hinter der Containerisierung eines Game-Servers, wie man persistente Speicherdaten schützt, das Port-Mapping, automatische Neustarts sowie das Sichern und Verschieben von allem auf eine andere Maschine — alles mit praktischen Beispielen.

Warum einen Game-Server containerisieren?

Beim klassischen Aufbau wirfst du den Server auf eine nackte Maschine, installierst manuell die richtige Laufzeitumgebung (Java, .NET, eine bestimmte glibc-Version usw.) und schreibst Service-Dateien. Das Problem ist, dass dieser Aufbau spezifisch für diese Maschine ist. Docker dreht das um:

  • Portabilität: Dasselbe Image läuft identisch auf deiner Entwicklungsmaschine, auf einem VPS und auf einem Backup-Server.
  • Isolation: Der Server läuft in seinem eigenen Container; er verschmutzt das Host-System nicht und gerät nicht in Versionskonflikte mit anderen Diensten.
  • Reproduzierbarkeit: Deine Konfiguration lebt in einem Dockerfile und einer compose.yaml; du kannst den gesamten Aufbau mit einem Befehl neu erstellen.
  • Einfache Versionsverwaltung: Image-Tags (:1.20, :latest) fixieren die Serverversion und erlauben bei Bedarf ein Zurückrollen.

Ein fertiges Image oder dein eigenes Dockerfile?

Für die meisten populären Spiele gibt es Community-Images. Für Minecraft ist beispielsweise itzg/minecraft-server ein ausgereiftes und weit verbreitetes Image, das EULA, Version und Speicher über Umgebungsvariablen regelt. Wenn ein fertiges Image existiert, ist dessen Nutzung der schnellste Weg. Für einen benutzerdefinierten oder selbst geschriebenen Server musst du jedoch dein eigenes Image bauen. Für eine einfache Linux-Server-Binary sieht ein typisches Dockerfile so aus:

FROM debian:12-slim

# Laufzeitabhängigkeiten
RUN apt-get update && apt-get install -y --no-install-recommends \
        ca-certificates libstdc++6 \
    && rm -rf /var/lib/apt/lists/*

# Ein eigener Benutzer statt root
RUN useradd --system --create-home --uid 1000 gameserver
USER gameserver
WORKDIR /home/gameserver

# Serverdateien kopieren
COPY --chown=gameserver:gameserver ./server/ ./

# Spiel-Port (Beispiel: UDP 27015)
EXPOSE 27015/udp

CMD ["./game_server", "--config", "server.cfg"]

Hier stecken ein paar gute Angewohnheiten drin: Der Aufbau auf einer -slim-Basis hält das Image klein, --no-install-recommends entfernt unnötige Pakete, und den Server als Nicht-root-Benutzer laufen zu lassen ist für die Sicherheit wichtig. Root innerhalb eines Containers erhöht das Risiko auf dem Host.

Persistente Daten: Spielstände gehören in ein Volume

Das ist der kritischste Punkt. Ein Container ist flüchtig; wird er mit docker rm entfernt, verschwindet sein Dateisystem mit ihm. Wenn der Welt-Spielstand, die Spielerdaten und die Konfiguration im Container bleiben, verlierst du bei einem Update alles. Die Lösung ist, diese Ordner an ein Volume oder ein Host-Verzeichnis zu binden:

docker run -d \
  --name game-server \
  -p 27015:27015/udp \
  -v /srv/game/data:/home/gameserver/data \
  --restart unless-stopped \
  mein-server:1.0

Die Klausel -v /srv/game/data:/home/gameserver/data bindet einen persistenten Ordner auf dem Host an das Datenverzeichnis des Containers. Selbst wenn du den Container löschst, aktualisierst oder auf eine andere Maschine verschiebst, bleiben die Spielstände nun auf der Host-Seite. Stelle beim Konfigurieren deines Servers sicher, dass der Speicherpfad auch wirklich in dieses gebundene Verzeichnis schreibt.

Port-Mapping: TCP oder UDP?

Game-Server nutzen meist UDP, denn beim Echtzeitspiel zählt niedrige Latenz mehr als das erneute Senden verlorener Pakete. Manche Server öffnen zusätzlich einen TCP-Query/RCON-Port. Im -p-Flag musst du das Protokoll korrekt angeben:

  • -p 27015:27015/udp — der UDP-Port für den Spielverkehr.
  • -p 27015:27015/tcp — der TCP-Port für RCON / Abfragen (falls nötig).

Die Zahl links ist der Host-Port, die rechts der Container-Port. Ist der Server von außen nicht erreichbar, ist dies die erste Anlaufstelle: Entweder ist das Protokoll falsch (TCP/UDP vertauscht) oder die VPS-Firewall (zum Beispiel ufw) blockiert den Port.

Ein sauberer Aufbau mit Compose

Statt lange docker run-Zeilen auf der Kommandozeile zu tippen, ist es weitaus nachhaltiger, die Konfiguration in eine compose.yaml-Datei zu verlagern. Die gesamte Definition des Servers steht in einer Datei und startet mit docker compose up -d:

services:
  game:
    build: .
    container_name: game-server
    ports:
      - "27015:27015/udp"
    volumes:
      - ./data:/home/gameserver/data
    environment:
      MAX_PLAYERS: "32"
      SERVER_NAME: "Aslain Server"
    restart: unless-stopped
    deploy:
      resources:
        limits:
          memory: 2g
          cpus: "2.0"

Das restart: unless-stopped hier sorgt dafür, dass der Container automatisch wieder hochkommt, selbst wenn der Server abstürzt oder die Maschine neu startet — eine entscheidende Einstellung für einen Game-Server. Der Block deploy.resources.limits verhindert, dass ein einzelner Game-Server die gesamte CPU und den gesamten RAM verschlingt und den Host blockiert.

Sichern und auf einen anderen Server umziehen

Das Schönste am Container-Ansatz ist, dass die Migration kaum mehr als das Kopieren des Datenordners bedeutet. Da das Image überall gleich ist, musst du auf dem neuen Server nur das Image ziehen/bauen und das Datenverzeichnis wiederherstellen:

# Momentaufnahme des Datenordners (am sichersten bei gestopptem Server)
docker compose stop game
tar czf backup-$(date +%F).tar.gz ./data
docker compose start game

# Auf dem neuen Server:
tar xzf backup-2026-06-28.tar.gz
docker compose up -d

Für weniger Ausfallzeit auf einem Live-Server kannst du zuerst den „save"-Befehl im Spiel auslösen, sodass alles auf die Festplatte geschrieben wird, und danach das Backup erstellen. Du kannst diesen Backup-Schritt auch an einen cron-Job koppeln, um automatisch tägliche Backups zu erzeugen.

Häufige Fragen

Gibt es bei einem Docker Game-Server Leistungseinbußen?

Unter Linux ist Docker keine virtuelle Maschine; es nutzt eine leichte Isolationsschicht, die sich den Kernel mit dem Host teilt. Der messbare Mehraufwand für CPU und Speicher ist sehr gering und verursacht keine Latenz, die Spieler spüren würden. Auf der Netzwerkseite fügt das Standard-Bridge-Netzwerk einen kleinen NAT-Overhead hinzu; willst du das nicht, kannst du die Ports mit network_mode: host direkt auf dem Host freigeben.

Verschwindet mein Welt-Spielstand, wenn der Container gelöscht wird?

Nein, wenn du die Daten an ein Volume oder ein Host-Verzeichnis gebunden hast. Mit -v nach außen gemountete Ordner sind unabhängig vom Lebenszyklus des Containers; selbst wenn du den Container löschst und neu erstellst, bleiben die Spielstände an Ort und Stelle. Die Daten außerhalb des Containers zu halten ist die wichtigste Regel überhaupt.

Kann ich auch einen Windows-Game-Server containerisieren?

Docker ist auf Linux-Servern am stärksten. Eine Server-Binary, die nur unter Windows läuft, erfordert Windows-Container, ein begrenzterer und umständlicherer Weg. In den meisten Fällen holst du das Beste aus Docker heraus, indem du Server mit einem Linux-Build bevorzugst.

Willst du deinen Game-Server in einen Container umziehen? Um den gesamten Aufbau gemeinsam zu planen — vom Schreiben des Dockerfiles bis zu persistenten Daten, Backups und VPS-Deployment — nimm Kontakt mit mir auf.

Bu kategorideki tüm yazılar →

Devamı için