{"id":28823,"date":"2026-02-28T13:32:05","date_gmt":"2026-02-28T12:32:05","guid":{"rendered":"https:\/\/blog.mi.hdm-stuttgart.de\/?p=28823"},"modified":"2026-02-28T13:46:34","modified_gmt":"2026-02-28T12:46:34","slug":"morehuehner-ein-moorhuhn-remake-als-cloud-native-multiplayer-browsergame","status":"publish","type":"post","link":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/2026\/02\/28\/morehuehner-ein-moorhuhn-remake-als-cloud-native-multiplayer-browsergame\/","title":{"rendered":"Morehuehner: Ein Moorhuhn-Remake als Cloud-Native Multiplayer-Browsergame"},"content":{"rendered":"\n<div class=\"wp-block-jetpack-markdown\"><h2>1. Einleitung<\/h2>\n<p>\u201cMoorhuhn\u201d, wer erinnert sich nicht? Damals auf Windows XP, in der Mittagspause oder nach der Schule, mit dem Fadenkreuz \u00fcber den Bildschirm und auf pixelige H\u00fchner geballert. F\u00fcr uns war Moorhuhn eines dieser Spiele, das man eigentlich nie alleine spielen wollte. Man sa\u00df vor dem Rechner, jemand schaute \u00fcber die Schulter, und am Ende wurde verglichen: <em>\u201cIch hatte 210 Punkte!\u201d<\/em> &#8211; <em>\u201cJa klar, du hast aber auch das goldene Huhn erwischt.\u201d<\/em><\/p>\n<p>Was Moorhuhn gefehlt hat? Ein echtes Multiplayer-Erlebnis. Nicht nur Highscores vergleichen, sondern gleichzeitig auf dieselben H\u00fchner schie\u00dfen, sich im Score-Ranking live messen und das ganze direkt im Browser, ohne Installation, ohne Download.<\/p>\n<p>So entstand <strong>Morehuehner<\/strong>: Ein Moorhuhn-Remake mit Echtzeit-Multiplayer, gebaut als Cloud-Native-Anwendung mit Kubernetes. Die Idee klingt erstmal simpel. Die Umsetzung? Die hatte es in sich.<\/p>\n<p>Unser Tech-Stack im \u00dcberblick:<\/p>\n<ul>\n<li><strong>Web-Frontend<\/strong>: Next.js mit React und Tailwind CSS<\/li>\n<li><strong>Lobby-Server<\/strong>: Socket.IO auf der Bun-Runtime<\/li>\n<li><strong>Game-Server<\/strong>: Socket.IO auf der Bun-Runtime<\/li>\n<li><strong>Lobby-Discovery-Service<\/strong>: Elysia.js (ebenfalls Bun-nativ)<\/li>\n<li><strong>Monorepo-Management<\/strong>: Turborepo mit Bun Workspaces<\/li>\n<li><strong>Orchestrierung<\/strong>: Kubernetes mit Kustomize<\/li>\n<\/ul>\n<p>Jeder dieser Services ist ein eigenst\u00e4ndiger Microservice, containerisiert und unabh\u00e4ngig skalierbar. Die hohe Skalierbarkeit erreichen wir durch Kubernetes, da verschiedene Microservices je nach Last unabh\u00e4ngig voneinander horizontal skaliert werden k\u00f6nnen. Das macht unser Projekt cloud-native: nicht nur \u201cirgendwie in der Cloud\u201d, sondern architektonisch darauf ausgelegt, die St\u00e4rken von Container-Orchestrierung voll auszunutzen.<\/p>\n<hr>\n<h2>2. Anforderungen<\/h2>\n<p>Bevor wir losgelegt haben, mussten wir uns erstmal einig werden: Was soll das Ding eigentlich k\u00f6nnen? Was <em>muss<\/em> es k\u00f6nnen und was nicht? Wir haben unsere Anforderungen in zwei Kategorien aufgeteilt.<\/p>\n<h3>Funktionale Anforderungen<\/h3>\n<ul>\n<li><strong>Multiplayer<\/strong>: Bis zu 4 Spieler schie\u00dfen gleichzeitig auf H\u00fchner in derselben Spielrunde. Kein Singleplayer-Modus mit Highscore-Vergleich, sondern echtes Echtzeit-Multiplayer.<\/li>\n<li><strong>Realtime-Gameplay<\/strong>: Latenz gering genug f\u00fcr ein gutes Spielerlebnis. Bei einem Shooter z\u00e4hlt jede Millisekunde, denn wenn man klickt und das Huhn erst eine halbe Sekunde sp\u00e4ter reagiert, macht das keinen Spa\u00df.<\/li>\n<li><strong>Lobby-System<\/strong>: Spieler sollen sich in Lobbys zusammenfinden k\u00f6nnen, bevor eine Runde startet. Beitreten, Ready-Status, automatischer Countdown bei voller Lobby.<\/li>\n<li><strong>Magazin- und Nachlade-Logik<\/strong>: 8 Schuss pro Magazin, dann manuell nachladen. Das zwingt zu taktischem Spielen, man kann nicht einfach wild draufhalten.<\/li>\n<li><strong>Verschiedene Seltenheitsstufen<\/strong>: Normale H\u00fchner (10 Punkte), schnelle H\u00fchner (25 Punkte) und seltene Bonus-H\u00fchner (50 Punkte). Schnellere H\u00fchner sind schwerer zu treffen, geben aber mehr Punkte.<\/li>\n<\/ul>\n<h3>Nicht-funktionale Anforderungen<\/h3>\n<ul>\n<li><strong>Cloud-Native<\/strong>: Die gesamte Architektur soll auf Container-Orchestrierung mit Kubernetes ausgelegt sein.<\/li>\n<li><strong>Horizontal skalierbar<\/strong>: Mehr Spieler? Mehr Pods. So einfach soll es sein, zumindest in der Theorie.<\/li>\n<li><strong>Lokal ausf\u00fchrbar<\/strong>: Kein AWS-Account, keine Cloud-Kosten zum Entwickeln. Alles l\u00e4uft mit Minikube auf dem eigenen Rechner.<\/li>\n<li><strong>Kein Login-System<\/strong>: Website \u00f6ffnen, Name eingeben, spielen. Keine Registrierung, keine Passw\u00f6rter. Der Fokus lag auf dem Spiel und der Infrastruktur, nicht auf User-Management.<\/li>\n<li><strong>Moderner Tech-Stack<\/strong>: TypeScript von vorne bis hinten, Bun als Runtime, Turborepo als Monorepo-Tool. Wir wollten mit aktuellen Technologien arbeiten, nicht mit einem Legacy-Setup.<\/li>\n<li><strong>Serverseitige Validierung<\/strong>: Treffer werden auf dem Server validiert. Der Client schickt die Klick-Koordinaten, der Server pr\u00fcft ob tats\u00e4chlich ein Huhn in Reichweite war. Kein Cheaten durch manipulierte Client-Events.<\/li>\n<\/ul>\n<hr>\n<h2>3. Unsere Cloud Challenge<\/h2>\n<p>Urspr\u00fcnglich hatten wir einen klaren Plan: Deployment auf AWS. Kubernetes-Cluster in der Cloud, eigene Domain, das volle Programm. Wir hatten schon die Architektur im Kopf: EKS, Load Balancer, etc.<\/p>\n<p>Doch dann kam die harte Realit\u00e4t: AWS-Account-Sperre, unklare Kostensituation, und pl\u00f6tzlich standen wir ohne Cloud-Infrastruktur da. Der Worst Case f\u00fcr ein Projekt, das \u201cCloud-Native\u201d sein soll.<\/p>\n<p>Der Pivot war schnell beschlossen: <strong>Lokales Deployment mit Minikube.<\/strong> Statt sich mit dem AWS-Support herumzuschlagen, bauen wir alles so, dass es lokal auf dem eigenen Rechner l\u00e4uft. Nat\u00fcrlich trotzdem mit denselben Kubernetes-Konzepten, die auch in einer echten Cloud-Umgebung zum Einsatz kommen.<\/p>\n<p>Und das ist der entscheidende Punkt: Minikube ist kein \u201cSpielzeug-Kubernetes\u201d. Es nutzt dieselben APIs, dieselben Ressourcentypen, denselben NGINX-Ingress-Controller. Unsere Deployments, Services, ConfigMaps und RBAC-Regeln sind identisch zu dem, was auf einem echten Cluster laufen w\u00fcrde. Der einzige Unterschied ist die Umgebung: statt <code class=\"\" data-line=\"\">us-east-1<\/code> hei\u00dft es <code class=\"\" data-line=\"\">minikube<\/code>. Die Kubernetes-Konzepte und die Probleme, die wir l\u00f6sen mussten, bleiben exakt dieselben.<\/p>\n<hr>\n<h2>4. Grundlagen<\/h2>\n<h3>Kubernetes<\/h3>\n<p>Kubernetes ist ein Container-Orchestrierungssystem. Es verwaltet, wo und wie Container laufen, skaliert sie bei Bedarf und sorgt daf\u00fcr, dass sie nach einem Absturz automatisch neu gestartet werden. F\u00fcr unser Projekt nutzen wir folgende Konzepte:<\/p>\n<ul>\n<li><strong>Deployments<\/strong>: Definieren, wie viele Instanzen (Pods) eines Services laufen sollen. Unser Lobby-Deployment startet z.B. mit 3 Replicas. Jeder Pod ist eine eigenst\u00e4ndige Lobby.<\/li>\n<li><strong>Services<\/strong>: Stellen eine stabile Netzwerk-Adresse f\u00fcr eine Gruppe von Pods bereit. Wir nutzen sowohl normale ClusterIP-Services (f\u00fcr Ingress-Routing) als auch Headless-Services (<code class=\"\" data-line=\"\">clusterIP: None<\/code>) f\u00fcr die direkte Pod-Discovery.<\/li>\n<li><strong>Ingress<\/strong>: Der \u201cEingang\u201d von au\u00dfen in den Cluster. Unser NGINX-Ingress routet <code class=\"\" data-line=\"\">\/<\/code> zum Web-Frontend, <code class=\"\" data-line=\"\">\/api\/*<\/code> zum Discovery-Service, <code class=\"\" data-line=\"\">\/lobby\/socket.io\/*<\/code> zum Lobby-Service und <code class=\"\" data-line=\"\">\/game\/socket.io\/*<\/code> zum Game-Service.<\/li>\n<li><strong>ConfigMaps<\/strong>: Zentrale Konfiguration f\u00fcr alle Services, Ports, Game-Settings und die Redis-URL. Alles an einem Ort, statt in jedem Pod einzeln.<\/li>\n<li><strong>ServiceAccounts + RBAC<\/strong>: Unser Lobby-Discovery-Service braucht Zugriff auf die Kubernetes-API, um Pod-IPs abzufragen. Daf\u00fcr bekommt er einen eigenen ServiceAccount mit einer Role, die nur <code class=\"\" data-line=\"\">endpoints<\/code> lesen darf (Principle of Least Privilege).<\/li>\n<\/ul>\n<p><strong>Warum Kustomize?<\/strong> Wir brauchen verschiedene Konfigurationen f\u00fcr verschiedene Umgebungen: lokal (Minikube) mit reduzierten Replicas und <code class=\"\" data-line=\"\">imagePullPolicy: Never<\/code>, und Production mit Autoscaling und h\u00f6heren Ressourcen-Limits. Kustomize l\u00f6st das elegant mit Base-Manifests und Overlays, ohne Templates oder Helm-Charts.<\/p>\n<h3>Minikube<\/h3>\n<p>Minikube startet einen vollwertigen Kubernetes-Cluster in einer lokalen VM oder einem Docker-Container. F\u00fcr uns ist es das perfekte Tool f\u00fcr lokale Entwicklung:<\/p>\n<ul>\n<li><strong><code class=\"\" data-line=\"\">minikube docker-env<\/code><\/strong>: L\u00e4sst das lokale Docker-CLI direkt gegen den Docker-Daemon innerhalb von Minikube arbeiten. Hei\u00dft: Wir bauen unsere Images einmal und sie sind sofort im Cluster verf\u00fcgbar, ohne Registry, ohne Push.<\/li>\n<li><strong><code class=\"\" data-line=\"\">minikube tunnel<\/code><\/strong>: Erstellt einen Netzwerk-Tunnel, damit der Ingress-Controller von au\u00dfen erreichbar ist. So k\u00f6nnen wir im Browser auf <code class=\"\" data-line=\"\">http:\/\/morehuehner.local<\/code> zugreifen.<\/li>\n<li><strong>Ingress-Addon<\/strong>: Minikube bringt einen NGINX-Ingress-Controller als Addon mit. Ein <code class=\"\" data-line=\"\">minikube addons enable ingress<\/code> und das Routing funktioniert.<\/li>\n<\/ul>\n<p>Unser Setup-Skript <code class=\"\" data-line=\"\">dev-k8s.sh<\/code> automatisiert den gesamten Prozess: Minikube starten, Docker-Env konfigurieren, alle vier Images bauen, Kubernetes-Manifeste anwenden und warten, bis alle Deployments ready sind.<\/p>\n<h3>Next.js<\/h3>\n<p>Next.js ist unser Frontend-Framework: React-basiert, mit Server-Side-Rendering und dateibasiertem Routing. F\u00fcr Morehuehner nutzen wir es prim\u00e4r als Client-Side-App: Die Lobby-Auswahl, die Lobby-View und das Game-Canvas sind alles React-Komponenten, die \u00fcber Socket.IO-Client mit den Backend-Services kommunizieren. Der Turbopack-Dev-Server macht die lokale Entwicklung angenehm schnell.<\/p>\n<h3>Socket.IO<\/h3>\n<p>Socket.IO ist unsere Wahl f\u00fcr die Echtzeit-Kommunikation. Es abstrahiert WebSocket-Verbindungen, bietet Rooms (f\u00fcr Lobby- und Game-Sessions), automatische Reconnects und, ganz wichtig, den Redis-Adapter f\u00fcr Multi-Pod-Sync. In der lokalen Entwicklung nutzt es den Polling-Fallback, im Kubernetes-Modus erzwingen wir reinen WebSocket-Transport, um Probleme mit Sticky-Sessions zu umgehen.<\/p>\n<h3>Elysia.js<\/h3>\n<p>Elysia ist ein ultraschnelles HTTP-Framework f\u00fcr die Bun-Runtime. Unser Lobby-Discovery-Service braucht keine WebSocket-Verbindungen, er beantwortet einfache REST-Requests: Lobby-Liste abrufen, Game-Server-Status abfragen, den am wenigsten ausgelasteten Game-Pod f\u00fcr eine neue Runde zuweisen. Elysia ist daf\u00fcr perfekt: minimaler Overhead, schnelle Cold-Starts, TypeScript-nativ.<\/p>\n<h3>Redis<\/h3>\n<p>Redis dient bei uns als Pub\/Sub-Backbone f\u00fcr die Cross-Pod-Kommunikation der Lobby-Server. \u00dcber den <code class=\"\" data-line=\"\">@socket.io\/redis-adapter<\/code> k\u00f6nnen alle Lobby-Pods Events austauschen, ohne sich gegenseitig direkt zu kennen. Lokal, ohne Kubernetes, wird Redis nicht ben\u00f6tigt. Der Adapter wird nur aktiviert, wenn die Umgebungsvariable <code class=\"\" data-line=\"\">REDIS_URL<\/code> gesetzt ist.<\/p>\n<hr>\n<h2>5. Deployment-Setup<\/h2>\n<h3>Kustomize-Struktur<\/h3>\n<p>Unser Kubernetes-Setup folgt dem Kustomize-Muster mit drei Schichten:<\/p>\n<pre><code class=\"\" data-line=\"\">k8s\/\n\u251c\u2500\u2500 base\/              # Shared Manifests\n\u2502   \u251c\u2500\u2500 configmap.yaml\n\u2502   \u251c\u2500\u2500 deployment-game.yaml\n\u2502   \u251c\u2500\u2500 deployment-lobby.yaml\n\u2502   \u251c\u2500\u2500 deployment-lobby-discovery.yaml\n\u2502   \u251c\u2500\u2500 deployment-redis.yaml\n\u2502   \u251c\u2500\u2500 deployment-web.yaml\n\u2502   \u251c\u2500\u2500 ingress.yaml\n\u2502   \u251c\u2500\u2500 rbac.yaml\n\u2502   \u251c\u2500\u2500 service-*.yaml\n\u2502   \u2514\u2500\u2500 kustomization.yaml\n\u251c\u2500\u2500 overlays\/\n\u2502   \u251c\u2500\u2500 minikube\/      # Lokale Entwicklung\n\u2502   \u2502   \u2514\u2500\u2500 kustomization.yaml\n\u2502   \u2514\u2500\u2500 production\/    # Autoscaling, HPAs\n\u2502       \u251c\u2500\u2500 hpa-game.yaml\n\u2502       \u251c\u2500\u2500 hpa-lobby.yaml\n\u2502       \u2514\u2500\u2500 kustomization.yaml\n<\/code><\/pre>\n<p>Die <strong>Base<\/strong> definiert alle Ressourcen mit sinnvollen Defaults. Das <strong>Minikube-Overlay<\/strong> reduziert Replicas (2 Lobbys, 1 Game-Pod, 1 Web-Pod) und setzt <code class=\"\" data-line=\"\">imagePullPolicy: Never<\/code>, damit Minikube die lokal gebauten Images nutzt. Das <strong>Production-Overlay<\/strong> f\u00fcgt HorizontalPodAutoscaler hinzu und skaliert die Ressourcen-Limits hoch.<\/p>\n<h3>Key Features unseres Deployments<\/h3>\n<ul>\n<li><strong>1 Lobby-Pod = 1 Lobby<\/strong>: Jeder Lobby-Pod verwaltet genau eine Lobby mit eigenem In-Memory-Zustand. Mehr Lobbys? Einfach <code class=\"\" data-line=\"\">kubectl scale deployment\/lobby --replicas=5<\/code>.<\/li>\n<li><strong>N Games pro Game-Pod<\/strong>: Game-Pods k\u00f6nnen mehrere Spielrunden gleichzeitig hosten. Die <code class=\"\" data-line=\"\">GameManager<\/code>-Klasse verwaltet eine <code class=\"\" data-line=\"\">Map&lt;string, GameRoom&gt;<\/code>. Jeder Room ist eine laufende Partie.<\/li>\n<li><strong>Sticky Sessions<\/strong>: NGINX Ingress setzt Affinity-Cookies (<code class=\"\" data-line=\"\">LOBBY_AFFINITY<\/code>, <code class=\"\" data-line=\"\">GAME_AFFINITY<\/code>), damit Folge-Requests eines Spielers beim selben Pod landen.<\/li>\n<li><strong>Headless Services f\u00fcr Pod-Discovery<\/strong>: <code class=\"\" data-line=\"\">lobby-headless<\/code> und <code class=\"\" data-line=\"\">game-headless<\/code> Services mit <code class=\"\" data-line=\"\">clusterIP: None<\/code> geben der Endpoints-API die tats\u00e4chlichen Pod-IPs zur\u00fcck, statt eine virtuelle ClusterIP. Der Discovery-Service nutzt das, um jeden Pod einzeln anzusprechen.<\/li>\n<li><strong>Dynamische Game-Allocation<\/strong>: Wenn eine Lobby voll ist, fragt der Lobby-Pod den Discovery-Service nach dem Game-Pod mit der geringsten Auslastung. Der Discovery-Service sortiert alle Game-Pods nach Anzahl aktiver Rooms und gibt den besten Kandidaten zur\u00fcck.<\/li>\n<li><strong>Downward API<\/strong>: Pod-Name und Pod-IP werden \u00fcber die Kubernetes Downward API als Umgebungsvariablen injiziert. So kennt jeder Pod seine eigene Identit\u00e4t.<\/li>\n<\/ul>\n<h3>Ingress-Routing<\/h3>\n<p>Unser Ingress besteht aus vier Regeln, die den gesamten Traffic intelligent verteilen:<\/p>\n<pre><code class=\"language-yaml\" data-line=\"\"># Frontend (catch-all)\n- path: \/                    \u2192 service: web (Port 3000)\n# REST API (Discovery)\n- path: \/api(\/|$)(.*)        \u2192 service: lobby-discovery (Port 3010)\n# Lobby WebSocket\n- path: \/lobby\/socket.io\/    \u2192 service: lobby (Port 3002)\n# Game WebSocket\n- path: \/game\/socket.io\/     \u2192 service: game (Port 3001)\n<\/code><\/pre>\n<p>Alle WebSocket-Pfade bekommen extra Annotations f\u00fcr Proxy-Timeouts (3600s), HTTP\/1.1 und Sticky-Sessions. Der <code class=\"\" data-line=\"\">rewrite-target<\/code> sorgt daf\u00fcr, dass <code class=\"\" data-line=\"\">\/lobby\/socket.io\/<\/code> als <code class=\"\" data-line=\"\">\/socket.io\/<\/code> beim Lobby-Pod ankommt, die Server erwarten den Standard-Socket.IO-Pfad.<\/p>\n<hr>\n<h2>6. Problem #1: WebSockets und Horizontal Pod Autoscaling<\/h2>\n<h3>Das Problem<\/h3>\n<p>Horizontal Pod Autoscaling klingt erstmal nach einer sauberen Architektur. Ist es auch, bis man WebSockets ins Spiel bringt.<\/p>\n<p>WebSocket-Verbindungen sind <strong>stateful und langlebig<\/strong>. Ein Spieler verbindet sich mit einem Lobby-Pod, und ab diesem Moment h\u00e4lt dieser Pod den Zustand f\u00fcr diesen Spieler im Speicher: Name, Ready-Status, Lobby-ID. Das widerspricht der Grundannahme von Kubernetes: <strong>alle Pods sind austauschbar.<\/strong><\/p>\n<p>Konkret sieht das Problem so aus:<\/p>\n<ol>\n<li>Spieler A will Lobby <code class=\"\" data-line=\"\">abc<\/code> beitreten, die auf <code class=\"\" data-line=\"\">Pod 1<\/code> l\u00e4uft.<\/li>\n<li>Der WebSocket-Connect geht durch den Ingress, der per <strong>Round-Robin<\/strong> einen Pod ausw\u00e4hlt.<\/li>\n<li>Spieler A landet auf <code class=\"\" data-line=\"\">Pod 2<\/code>, dem falschen Pod.<\/li>\n<li><code class=\"\" data-line=\"\">Pod 2<\/code> hat keine Ahnung von Lobby <code class=\"\" data-line=\"\">abc<\/code>, weil der Zustand nur auf <code class=\"\" data-line=\"\">Pod 1<\/code> existiert.<\/li>\n<\/ol>\n<p>Der Sticky-Cookie <code class=\"\" data-line=\"\">LOBBY_AFFINITY<\/code> greift <strong>zu sp\u00e4t<\/strong>, er wird erst nach dem initialen Request gesetzt. Aber zu diesem Zeitpunkt ist der Spieler bereits am falschen Pod gelandet.<\/p>\n<p>Autoscaling versch\u00e4rft das Ganze zus\u00e4tzlich: Der HPA kann jederzeit Pods herunterfahren, wodurch bestehende WebSocket-Verbindungen und der gesamte In-Memory-Zustand verloren gehen.<\/p>\n<h3>Wie wir es diagnostiziert haben<\/h3>\n<p>Debugging war z\u00e4h. In der Web-Oberfl\u00e4che zeigten sich Inkonsistenzen: Manchmal funktionierte ein Join, manchmal nicht. Der Lobby-Status flackerte. Spieler tauchten auf und verschwanden wieder. Das T\u00fcckische: Es funktionierte <em>manchmal<\/em>,  n\u00e4mlich genau dann, wenn der Round-Robin zuf\u00e4llig den richtigen Pod traf. In der lokalen Entwicklung mit nur einem Pod war das Problem unsichtbar.<\/p>\n<p>Wir haben gelernt: Oft f\u00fchren viele verschiedene Probleme zu <em>einem<\/em> Fehlerbild, was das Debugging extrem schwer und z\u00e4h macht. Erst als wir anfingen, die Pod-Logs aller Lobby-Instanzen gleichzeitig zu beobachten, wurde klar, dass die Requests am falschen Pod ankamen.<\/p>\n<h3>M\u00f6gliche L\u00f6sungsans\u00e4tze<\/h3>\n<p>Wir haben drei Optionen evaluiert:<\/p>\n<p><strong>Option A: Redis Adapter mit Event-Forwarding<\/strong><\/p>\n<p>Der <code class=\"\" data-line=\"\">@socket.io\/redis-adapter<\/code> verbindet alle Lobby-Pods \u00fcber Redis Pub\/Sub. Die Grundidee: 1 Pod = 1 Lobby bleibt erhalten, der Zustand bleibt lokal im Speicher. Aber wenn ein Event am falschen Pod ankommt, leitet dieser es per <code class=\"\" data-line=\"\">serverSideEmit<\/code> \u00fcber Redis an den richtigen Pod weiter. Broadcasts werden \u00fcber Redis an alle Sockets im Room zugestellt, egal auf welchem Pod sie physisch verbunden sind.\nEin Nachteil: Es muss ein zus\u00e4tzlicher Service verwendet werden, der weitere Ressourcen allokiert.<\/p>\n<p><strong>Option B: StatefulSets mit Ingress-Mapping<\/strong><\/p>\n<p>Das Lobby-Deployment wird zu einem StatefulSet mit festen Pod-Namen (<code class=\"\" data-line=\"\">lobby-0<\/code>, <code class=\"\" data-line=\"\">lobby-1<\/code>, \u2026). Pro Pod ein eigener Service und Ingress-Pfad (<code class=\"\" data-line=\"\">\/lobby-0\/socket.io\/<\/code>). Das Frontend verbindet sich direkt zum richtigen Pod-Pfad. <strong>Nachteil<\/strong>: Die Ingress-Konfiguration muss bei jeder Skalierung angepasst werden, das skaliert nicht.<\/p>\n<p><strong>Option C: Agones (Game-Server-Orchestrator)<\/strong><\/p>\n<p>Googles Open-Source-Framework f\u00fcr dedizierte Game-Server auf Kubernetes. Verwaltet automatisch IP-Zuordnung pro Session. <strong>Nachteil<\/strong>: Hohe Komplexit\u00e4t, eigenes CRD-\u00d6kosystem, Overkill f\u00fcr ein Lobby-System.<\/p>\n<h3>Unsere L\u00f6sung: Option A<\/h3>\n<p>Wir haben uns f\u00fcr den Redis-Adapter entschieden. So funktioniert der Flow:<\/p>\n<\/div>\n\n\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2026\/02\/redis.png\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"510\" data-attachment-id=\"28825\" data-permalink=\"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/2026\/02\/28\/morehuehner-ein-moorhuhn-remake-als-cloud-native-multiplayer-browsergame\/redis-2\/\" data-orig-file=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2026\/02\/redis.png\" data-orig-size=\"2294,1143\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"redis\" data-image-description=\"\" data-image-caption=\"\" data-large-file=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2026\/02\/redis-1024x510.png\" src=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2026\/02\/redis-1024x510.png\" alt=\"\" class=\"wp-image-28825\" srcset=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2026\/02\/redis-1024x510.png 1024w, https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2026\/02\/redis-300x149.png 300w, https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2026\/02\/redis-768x383.png 768w, https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2026\/02\/redis-1536x765.png 1536w, https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2026\/02\/redis-2048x1020.png 2048w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><\/figure>\n\n\n\n<div class=\"wp-block-jetpack-markdown\"><p>Der entscheidende Mechanismus in der <code class=\"\" data-line=\"\">index.ts<\/code> des Lobby-Servers: Beim <code class=\"\" data-line=\"\">join<\/code>-Event pr\u00fcft der Pod, ob die angeforderte <code class=\"\" data-line=\"\">lobbyId<\/code> zu seiner lokalen Lobby geh\u00f6rt. Falls ja, wird lokal verarbeitet. Falls nein, tritt der Socket trotzdem dem Socket.IO-Room bei (damit Broadcasts ihn erreichen) und das Event wird per <code class=\"\" data-line=\"\">serverSideEmit<\/code> \u00fcber Redis an alle anderen Pods weitergeleitet. Der Pod, der die Lobby besitzt, verarbeitet das Event dann lokal.<\/p>\n<p>Dasselbe Forwarding-Pattern implementieren wir f\u00fcr <code class=\"\" data-line=\"\">ready<\/code>, <code class=\"\" data-line=\"\">leave<\/code> und <code class=\"\" data-line=\"\">disconnect<\/code> Events.<\/p>\n<p>Ein weiteres Detail, das uns Stunden gekostet hat: <strong>WebSocket-Only im K8s-Modus.<\/strong> Socket.IO nutzt standardm\u00e4\u00dfig ein Upgrade-Verfahren. Erst HTTP-Polling, dann WebSocket-Upgrade. In Kubernetes ist das ein Problem, weil die initialen Polling-Requests nicht garantiert beim selben Pod landen, selbst mit Sticky-Sessions. Die L\u00f6sung: Im K8s-Modus erzwingen wir <code class=\"\" data-line=\"\">transports: [&#039;websocket&#039;]<\/code> auf der Client-Seite, um den Polling-Fallback komplett zu umgehen. Lokal bleibt Polling als Fallback aktiv.<\/p>\n<p>Und das Beste: <strong>Lokal funktioniert alles ohne Redis.<\/strong> Der Adapter wird nur aktiviert, wenn <code class=\"\" data-line=\"\">REDIS_URL<\/code> gesetzt ist. In der lokalen Entwicklung gibt es kein Cross-Pod-Problem und kein Redis n\u00f6tig.<\/p>\n<h3>Was wir gelernt haben<\/h3>\n<p>Entwickelt man wirklich \u201cCloud Native\u201d ohne Abstraktionsebenen wie AWS Lambda Functions oder verwaltete Message-Queues, muss man solch komplexe Probleme selbst angehen. Nicht alle Technologien verstehen sich von Haus aus mit den Architekturprinzipien von Cloud-Native-Umgebungen. Au\u00dferdem: WebSocket-Verbindungen und ihre Details, pl\u00f6tzlich bewegt man sich auf Netzwerkebene und muss verstehen, wie HTTP-Upgrades, Cookies und Load-Balancer zusammenspielen.<\/p>\n<hr>\n<h2>7. Problem #2: Pod-Hopping (Von der Lobby zum Game-Server)<\/h2>\n<h3>Das Problem<\/h3>\n<p>Die Lobby l\u00e4uft, alle Spieler sind ready, der Countdown z\u00e4hlt herunter \u2026 und dann? Alle Spieler m\u00fcssen von ihrem Lobby-Pod zu einem Game-Pod wechseln. Aber welchem? Und wie stellt man sicher, dass alle im selben Game-Room landen?<\/p>\n<p>Die Herausforderungen:<\/p>\n<ol>\n<li><strong>Game-Server-Auswahl<\/strong>: Welcher Game-Pod hat noch Kapazit\u00e4t? Game-Pods k\u00f6nnen mehrere Rooms gleichzeitig hosten. Wir wollen den am wenigsten ausgelasteten Pod w\u00e4hlen.<\/li>\n<li><strong>Verbindungsdaten-Weitergabe<\/strong>: Die Spieler m\u00fcssen wissen, <em>wohin<\/em> sie sich verbinden sollen. Host, Port und eine gemeinsame Game-ID.<\/li>\n<li><strong>Sauberer \u00dcbergang<\/strong>: Die WebSocket-Verbindung zur Lobby muss getrennt und eine neue zum Game-Server aufgebaut werden, ohne dass der User etwas davon merkt.<\/li>\n<\/ol>\n<h3>Wie wir es diagnostiziert haben<\/h3>\n<p>Anfangs hatten wir einen statischen Fallback: Alle Lobbys schickten ihre Spieler zum selben Game-Server (<code class=\"\" data-line=\"\">GAME_SERVICE_HOST<\/code>). Funktionierte lokal mit einem Pod. In Kubernetes mit mehreren Game-Pods? Chaos. Manche Spieler landeten auf Pod A, andere auf Pod B. Verschiedene Pods, verschiedene Room-Maps, verschiedene Spielrunden.<\/p>\n<h3>Die L\u00f6sung<\/h3>\n<p>Der Flow sieht so aus: Wenn alle Spieler ready sind (oder die Lobby voll ist), startet der <code class=\"\" data-line=\"\">LobbyManager<\/code> den Countdown. Nach Ablauf ruft er <code class=\"\" data-line=\"\">allocateGameAndRedirect()<\/code> auf:<\/p>\n<ol>\n<li>\n<p><strong>Game-Allocation \u00fcber den Discovery-Service<\/strong>: Der Lobby-Pod sendet einen POST-Request an <code class=\"\" data-line=\"\">\/allocate-game<\/code> des Lobby-Discovery-Services. Dieser fragt \u00fcber die Kubernetes Endpoints-API alle Game-Pods ab, ruft deren <code class=\"\" data-line=\"\">\/health<\/code>-Endpoint auf (der die Anzahl aktiver Rooms zur\u00fcckgibt) und sortiert nach Auslastung. Der Pod mit den wenigsten aktiven Rooms wird zur\u00fcckgegeben.<\/p>\n<\/li>\n<li>\n<p><strong>Broadcast der Verbindungsdaten<\/strong>: Der Lobby-Pod generiert eine Game-ID und broadcastet ein <code class=\"\" data-line=\"\">redirect-to-game<\/code>-Event an alle Spieler im Room. Das Event enth\u00e4lt <code class=\"\" data-line=\"\">gameId<\/code>, <code class=\"\" data-line=\"\">host<\/code>, <code class=\"\" data-line=\"\">port<\/code> und ein Token.<\/p>\n<\/li>\n<li>\n<p><strong>Client-seitiger Redirect<\/strong>: Im Frontend empf\u00e4ngt die <code class=\"\" data-line=\"\">LobbyView<\/code>-Komponente das <code class=\"\" data-line=\"\">redirect-to-game<\/code>-Event. Sie setzt ein <code class=\"\" data-line=\"\">isRedirecting<\/code>-Flag (damit der Disconnect-Handler nicht den State l\u00f6scht), speichert die Game-Server-Daten, wechselt die View auf das <code class=\"\" data-line=\"\">GameCanvas<\/code> und trennt die Lobby-Verbindung. Das <code class=\"\" data-line=\"\">GameCanvas<\/code> baut dann eine neue Socket.IO-Verbindung zum Game-Server auf und joined mit derselben Player-ID und Game-ID.<\/p>\n<\/li>\n<\/ol>\n<p>Das Zusammenspiel der Services macht den Lobby-Discovery-Service zum zentralen Koordinator: Er kennt alle Pods (\u00fcber Headless-Services und die Endpoints-API), er kennt deren Auslastung (\u00fcber die Health-Endpoints) und er trifft die Entscheidung, welcher Pod herausgesucht wird.<\/p>\n<p>F\u00fcr die Kubernetes-API-Zugriffe hat der Discovery-Service einen eigenen ServiceAccount mit einer RBAC-Role, die ausschlie\u00dflich <code class=\"\" data-line=\"\">endpoints<\/code> in der <code class=\"\" data-line=\"\">morehuehner<\/code>-Namespace lesen darf, nicht mehr.<\/p>\n<\/div>\n\n\n\n<figure class=\"wp-block-image aligncenter size-large\"><a href=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2026\/02\/Bildschirmfoto-2026-02-28-um-13.14.16.png\"><img loading=\"lazy\" decoding=\"async\" width=\"261\" height=\"1024\" data-attachment-id=\"28828\" data-permalink=\"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/2026\/02\/28\/morehuehner-ein-moorhuhn-remake-als-cloud-native-multiplayer-browsergame\/bildschirmfoto-2026-02-28-um-13-14-16\/\" data-orig-file=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2026\/02\/Bildschirmfoto-2026-02-28-um-13.14.16.png\" data-orig-size=\"273,1072\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"Bildschirmfoto 2026-02-28 um 13.14.16\" data-image-description=\"\" data-image-caption=\"\" data-large-file=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2026\/02\/Bildschirmfoto-2026-02-28-um-13.14.16-261x1024.png\" src=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2026\/02\/Bildschirmfoto-2026-02-28-um-13.14.16-261x1024.png\" alt=\"\" class=\"wp-image-28828\" srcset=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2026\/02\/Bildschirmfoto-2026-02-28-um-13.14.16-261x1024.png 261w, https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2026\/02\/Bildschirmfoto-2026-02-28-um-13.14.16.png 273w\" sizes=\"auto, (max-width: 261px) 100vw, 261px\" \/><\/a><\/figure>\n\n\n\n<div class=\"wp-block-jetpack-markdown\"><h3>Was wir gelernt haben<\/h3>\n<p>Service-Discovery ist in Kubernetes kein Selbstl\u00e4ufer. Man muss sich aktiv entscheiden, wie Pods sich gegenseitig finden. Headless Services, Endpoints-API, RBAC, das sind alles Puzzleteile, die man zusammensetzen muss. Wenn das System jedoch einmal steht, ist die Implementierung elegant: Neue Game-Pods tauchen automatisch in der Discovery auf, ohne dass irgendwo eine Konfiguration angepasst werden muss.<\/p>\n<hr>\n<h2>8. Lessons Learned und Fazit<\/h2>\n<h3>Was wir \u00fcber Kubernetes und Minikube gelernt haben<\/h3>\n<p><strong>Minikube 1st, Cloud 2nd.<\/strong> Lokales Prototyping mit Minikube hat unsere Feedback-Loops massiv verk\u00fcrzt. Statt auf Cloud-Deploys zu warten, konnten wir in Sekunden rebuilden, redeployen und testen. Unser <code class=\"\" data-line=\"\">dev-k8s.sh<\/code>-Skript baut alle vier Images und rollt das Deployment in unter zwei Minuten aus. F\u00fcr ein Uni-Projekt, bei dem man abends nochmal schnell was ausprobieren will, ist das Gold wert.<\/p>\n<p><strong>WebSockets + Kubernetes = tricky.<\/strong> WebSocket-Verbindungen sind langlebig und stateful, w\u00e4hrend Kubernetes f\u00fcr stateless HTTP-Traffic konzipiert ist. Diese Grundproblematik hat uns mehr Stunden gekostet als jedes andere Problem im Projekt. Sticky Sessions allein reichen nicht aus. Man ben\u00f6tigt ein Forwarding-Konzept und muss den Transport-Layer verstehen.<\/p>\n<p><strong>Ops-Aufwand &gt; Implementation.<\/strong> Das Schreiben des eigentlichen Game-Codes, also Chicken-Spawning, Hit-Detection und Score-Berechnung, war vergleichsweise einfach. Die <code class=\"\" data-line=\"\">GameManager<\/code>-Klasse hat klare Zust\u00e4ndigkeiten und war in wenigen Wochen fertig. Das Containerisieren, Deployen und zum Laufen Bringen der Services in Kubernetes hat ein Vielfaches an Zeit verschlungen. Dockerfile-Optimierung, Ingress-Debugging, RBAC-Konfiguration, Redis-Setup. Das alles summiert sich.<\/p>\n<h3>Cloud vs. Lokal: Trade-offs<\/h3>\n<p>Als AWS wegfiel, hat uns Minikube gerettet. Aber es hat Grenzen: Es gibt kein echtes DNS, kein TLS mit Let\u2019s Encrypt und keine echte Netzwerk-Latenz zwischen Nodes. Unser System ist auf echte Cloud-Bedingungen vorbereitet und das Production-Overlay mit HPAs und erh\u00f6hten Ressourcen-Limits existiert bereits. Den letzten Beweis, dass es unter Last auf einem echten Cluster funktioniert, k\u00f6nnen wir jedoch noch nicht liefern.<\/p>\n<h3>W\u00fcrden wir es wieder so machen?<\/h3>\n<p>Ja, mit Einschr\u00e4nkungen. Die Microservice-Architektur hat sich bew\u00e4hrt. Da Lobby und Game v\u00f6llig unterschiedliche Skalierungsmuster haben (1 Pod = 1 Lobby vs. N Rooms pro Game-Pod) und sauber getrennt sind, wurde das Debugging trotz aller Komplexit\u00e4t vereinfacht. Turborepo mit geteilten TypeScript-Typen war ein Segen. Dass dieselben Interfaces auf Client und Server vorhanden sind, eliminiert eine ganze Kategorie von Bugs.<\/p>\n<p>Was wir anders machen w\u00fcrden: Wir w\u00fcrden fr\u00fcher mit Redis und Multi-Pod-Setups testen, statt erst am Ende die Kubernetes-Probleme zu entdecken. Und vielleicht h\u00e4tten Agones von Anfang an evaluiert werden sollen, nicht f\u00fcr die Lobby, aber f\u00fcr die Game-Server.<\/p>\n<h3>Tipps f\u00fcr andere<\/h3>\n<ul>\n<li><strong>Startet mit Minikube.<\/strong> Nicht mit der Cloud. Baut euer Setup lokal, versteht die Kubernetes-Konzepte, und deployt erst in die Cloud, wenn ihr ein funktionierendes lokales Setup habt.<\/li>\n<li><strong>Plant f\u00fcr Multi-Pod von Tag 1.<\/strong> Wenn euer Service Zustand im Speicher h\u00e4lt und ihr plant, ihn horizontal zu skalieren, denkt <em>sofort<\/em> \u00fcber Cross-Pod-Kommunikation nach. Nicht erst, wenn die erste Demo vor der T\u00fcr steht.<\/li>\n<li><strong>Headless Services sind eure Freunde.<\/strong> F\u00fcr jede Art von Service-Discovery innerhalb des Clusters: <code class=\"\" data-line=\"\">clusterIP: None<\/code> und die Endpoints-API geben euch direkten Zugriff auf einzelne Pod-IPs.<\/li>\n<li><strong>Testet mit mehreren Pods.<\/strong> Mit einem Pod funktioniert <em>alles<\/em>. Die echten Probleme tauchen erst auf, wenn Load-Balancing ins Spiel kommt.<\/li>\n<\/ul>\n<hr>\n<h2>9. Ausblick<\/h2>\n<h3>M\u00f6gliche Erweiterungen<\/h3>\n<ul>\n<li><strong>User-Management<\/strong>: Login, Accounts, persistente Highscores. Aktuell sind die Daten weg, wenn der Pod stirbt.<\/li>\n<li><strong>Powerups<\/strong>: Mehr Gameplay-Tiefe. Doppelte Punkte, Slow-Motion, Rapid Fire. Der <code class=\"\" data-line=\"\">GameManager<\/code> mit seinem Tick-basierten Game-Loop w\u00e4re daf\u00fcr gut vorbereitet.<\/li>\n<li><strong>Metrics Dashboard<\/strong>: Prometheus + Grafana f\u00fcr Serverlast, aktive Rooms, Spieleranzahl pro Pod. Die Health-Endpoints existieren bereits. Man m\u00fcsste sie nur in ein Prometheus-Format bringen.<\/li>\n<\/ul>\n<h3>Wie k\u00f6nnte man es auf echtes Cloud-Deployment vorbereiten?<\/h3>\n<p>Der Sprung von Minikube in eine echte Cloud-Umgebung ist kleiner als man denkt:<\/p>\n<ol>\n<li><strong>Domain und DNS einrichten<\/strong>: Eine echte Domain registrieren, DNS-Records auf den Cluster zeigen. Der Ingress unterst\u00fctzt bereits Host-basiertes Routing.<\/li>\n<li><strong>Kubernetes-Cluster aufsetzen<\/strong>: Entweder \u00fcber einen KaaS-Anbieter (Managed Kubernetes wie GKE, EKS oder DigitalOcean Kubernetes) oder f\u00fcr die Mutigen: ein selbst verwalteter Cluster mit Talos Linux auf eigener Hardware.<\/li>\n<li><strong>Deployment<\/strong>: Unser Production-Overlay anwenden, eine Container-Registry einrichten (statt der lokalen Minikube-Images), TLS-Zertifikate \u00fcber cert-manager und los geht\u2019s.<\/li>\n<\/ol>\n<p>Die Architektur steht. Die Kubernetes-Manifeste sind bereit. Was fehlt, ist der letzte Schritt.<\/p>\n<\/div>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"","protected":false},"author":1155,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[1],"tags":[84,7,3,154,340],"ppma_author":[936,1202,1199,1174],"class_list":["post-28823","post","type-post","status-publish","format-standard","hentry","category-allgemein","tag-aws","tag-cloud","tag-docker","tag-kubernetes","tag-minikube"],"aioseo_notices":[],"jetpack_featured_media_url":"","jetpack-related-posts":[{"id":5175,"url":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/2019\/02\/24\/benefiting-kubernetes-part-2-deploy-with-kubectl\/","url_meta":{"origin":28823,"position":0},"title":"Migrating to Kubernetes Part 2 &#8211; Deploy with kubectl","author":"Can Kattwinkel","date":"24. February 2019","format":false,"excerpt":"Written by: Pirmin Gersbacher, Can Kattwinkel, Mario Sallat Migrating from Bare Metal to Kubernetes The interest in software containers is a relatively new trend in the developers world. Classic VMs have not lost their right to exist within a world full of monoliths yet, but the trend is clearly towards\u2026","rel":"","context":"In &quot;Allgemein&quot;","block_context":{"text":"Allgemein","link":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/category\/allgemein\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2019\/02\/pexels-photo-379964.jpeg?resize=350%2C200&ssl=1","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2019\/02\/pexels-photo-379964.jpeg?resize=350%2C200&ssl=1 1x, https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2019\/02\/pexels-photo-379964.jpeg?resize=525%2C300&ssl=1 1.5x, https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2019\/02\/pexels-photo-379964.jpeg?resize=700%2C400&ssl=1 2x, https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2019\/02\/pexels-photo-379964.jpeg?resize=1050%2C600&ssl=1 3x"},"classes":[]},{"id":6338,"url":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/2019\/03\/15\/kubernetesk8s-everywhere-but-how\/","url_meta":{"origin":28823,"position":1},"title":"Kubernetes (K8S) everywhere, but how?","author":"Immanuel Haag","date":"15. March 2019","format":false,"excerpt":"In the last months, nearly everybody has been talking about Kubernetes. It\u2019s incredible! This semester the Stuttgart Media University even held a training course on this topic. For DevOps or \u201ccloud-computing specialist\u201d mastering Kubernetes and the concepts around it is becoming more and more important. This blog post won\u2019t explain\u2026","rel":"","context":"In &quot;Allgemein&quot;","block_context":{"text":"Allgemein","link":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/category\/allgemein\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2023\/08\/up-and-running-with-kubernetes-13-638.jpg?resize=350%2C200&ssl=1","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2023\/08\/up-and-running-with-kubernetes-13-638.jpg?resize=350%2C200&ssl=1 1x, https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2023\/08\/up-and-running-with-kubernetes-13-638.jpg?resize=525%2C300&ssl=1 1.5x"},"classes":[]},{"id":26208,"url":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/2024\/02\/29\/die-meere-der-systemtechnik-navigieren-eine-reise-durch-die-bereitstellung-einer-aktien-webanwendung-in-der-cloud\/","url_meta":{"origin":28823,"position":2},"title":"Die Meere der Systemtechnik navigieren: Eine Reise durch die Bereitstellung einer Aktien-Webanwendung in der Cloud","author":"mk306","date":"29. February 2024","format":false,"excerpt":"Auf zu neuen Ufern: Einleitung Die Cloud-Computing-Technologie hat die Art und Weise, wie Unternehmen Anwendungen entwickeln, bereitstellen und skalieren, revolutioniert. In diesem Beitrag, der im Rahmen der Vorlesung \u201c143101a System Engineering und Management\u201d entstanden ist, werden wir uns darauf konzentrieren, wie eine bereits bestehende Webanwendung zur Visualisierung und Filterung von\u2026","rel":"","context":"In &quot;Cloud Technologies&quot;","block_context":{"text":"Cloud Technologies","link":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/category\/scalable-systems\/cloud-technologies\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2024\/02\/Dashboard2-Kopie-1.png?resize=350%2C200&ssl=1","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2024\/02\/Dashboard2-Kopie-1.png?resize=350%2C200&ssl=1 1x, https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2024\/02\/Dashboard2-Kopie-1.png?resize=525%2C300&ssl=1 1.5x, https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2024\/02\/Dashboard2-Kopie-1.png?resize=700%2C400&ssl=1 2x, https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2024\/02\/Dashboard2-Kopie-1.png?resize=1050%2C600&ssl=1 3x, https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2024\/02\/Dashboard2-Kopie-1.png?resize=1400%2C800&ssl=1 4x"},"classes":[]},{"id":21651,"url":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/2021\/09\/18\/deploy-random-chat-application-on-aws-ec2-with-kubernetes\/","url_meta":{"origin":28823,"position":3},"title":"Deploying Random Chat Application on AWS EC2 with Kubernetes","author":"dv029","date":"18. September 2021","format":false,"excerpt":"1. Introduction For the examination of the lecture \u201cSoftware Development for Cloud Computing\u201d, I want to build a simple Random Chat Application. The idea of this application is based on the famous chat application called Omegle. Omegle is where people can meet random people in the world and can have\u2026","rel":"","context":"In &quot;Cloud Technologies&quot;","block_context":{"text":"Cloud Technologies","link":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/category\/scalable-systems\/cloud-technologies\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/image-19.png?resize=350%2C200&ssl=1","width":350,"height":200},"classes":[]},{"id":28550,"url":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/2026\/02\/21\/entwicklung-einer-verteilten-cloud-anwendung-am-beispiel-eines-multiplayer-spiels\/","url_meta":{"origin":28823,"position":4},"title":"Entwicklung einer verteilten Cloud-Anwendung am Beispiel eines Multiplayer Spiels","author":"Tom Bestvater","date":"21. February 2026","format":false,"excerpt":"Einleitung Den meisten sollte das Spielprinzip von \u201cCookie Clicker\u201d bekannt sein: Ein Klick auf einen Keks erh\u00f6ht den Spielstand um einen Punkt. Das Spiel ist endlos, hat keine Punktegrenze. Es geht darum, im Leaderboard nach oben zu klettern. Im Rahmen der Vorlesung \u201cSystem Engineering and Management\u201d (143101a)\u00a0 erweiterten wir das\u2026","rel":"","context":"In &quot;Allgemein&quot;","block_context":{"text":"Allgemein","link":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/category\/allgemein\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2026\/02\/Auth-Flow-Diagram-1.png?resize=350%2C200&ssl=1","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2026\/02\/Auth-Flow-Diagram-1.png?resize=350%2C200&ssl=1 1x, https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2026\/02\/Auth-Flow-Diagram-1.png?resize=525%2C300&ssl=1 1.5x, https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2026\/02\/Auth-Flow-Diagram-1.png?resize=700%2C400&ssl=1 2x"},"classes":[]},{"id":25999,"url":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/2023\/09\/15\/automate-pdf-a-cloud-driven-workflow-tool-with-cloud-functions-and-kubernetes\/","url_meta":{"origin":28823,"position":5},"title":"Automate PDF &#8211; A Cloud-Driven Workflow Tool with Cloud Functions and Kubernetes","author":"fb089","date":"15. September 2023","format":false,"excerpt":"Gitlab You can find the Project under this link https:\/\/gitlab.mi.hdm-stuttgart.de\/fb089\/automatecloud Wiki You can find all the Infos in our Gitlab Wiki (https:\/\/gitlab.mi.hdm-stuttgart.de\/fb089\/automatecloud\/-\/wikis\/AutomateCloud). You can even try it urself. Feel free Short Description Automate PDF is a workflow automation tool created in the course \u201cSoftware Development for Cloud Computing\u201d. The application\u2026","rel":"","context":"In &quot;Allgemein&quot;","block_context":{"text":"Allgemein","link":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/category\/allgemein\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2023\/09\/Bildschirmfoto-2023-09-15-um-19.23.39.png?resize=350%2C200&ssl=1","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2023\/09\/Bildschirmfoto-2023-09-15-um-19.23.39.png?resize=350%2C200&ssl=1 1x, https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2023\/09\/Bildschirmfoto-2023-09-15-um-19.23.39.png?resize=525%2C300&ssl=1 1.5x"},"classes":[]}],"jetpack_sharing_enabled":true,"authors":[{"term_id":936,"user_id":1155,"is_guest":0,"slug":"michael_dick","display_name":"Michael Dick","avatar_url":"https:\/\/secure.gravatar.com\/avatar\/709f2a71925177dbd54b3120d4d93c394d6eaa32eae8409769f7247fac3be2cf?s=96&d=mm&r=g","0":null,"1":"","2":"","3":"","4":"","5":"","6":"","7":"","8":""},{"term_id":1202,"user_id":1317,"is_guest":0,"slug":"tom_flocken","display_name":"Tom Flocken","avatar_url":"https:\/\/secure.gravatar.com\/avatar\/228025319015e324c526241dc0c997160d0f0e665080818b5866b56690a29fa5?s=96&d=mm&r=g","0":null,"1":"","2":"","3":"","4":"","5":"","6":"","7":"","8":""},{"term_id":1199,"user_id":1314,"is_guest":0,"slug":"leonard_lais","display_name":"Leonard Lais\u00e9","avatar_url":"https:\/\/secure.gravatar.com\/avatar\/e543f96dae797a9d3a585e54c63fbc3406f0e91d6c938b7055536af3d0b40080?s=96&d=mm&r=g","0":null,"1":"","2":"","3":"","4":"","5":"","6":"","7":"","8":""},{"term_id":1174,"user_id":1303,"is_guest":0,"slug":"pascal_leyrer","display_name":"Pascal Leyrer","avatar_url":"https:\/\/secure.gravatar.com\/avatar\/43a2f24033c4855b6e0345716657e83360c80cf949c1b09791ee3da0055b4cc9?s=96&d=mm&r=g","0":null,"1":"","2":"","3":"","4":"","5":"","6":"","7":"","8":""}],"_links":{"self":[{"href":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/wp-json\/wp\/v2\/posts\/28823","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/wp-json\/wp\/v2\/users\/1155"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/wp-json\/wp\/v2\/comments?post=28823"}],"version-history":[{"count":5,"href":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/wp-json\/wp\/v2\/posts\/28823\/revisions"}],"predecessor-version":[{"id":28831,"href":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/wp-json\/wp\/v2\/posts\/28823\/revisions\/28831"}],"wp:attachment":[{"href":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/wp-json\/wp\/v2\/media?parent=28823"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/wp-json\/wp\/v2\/categories?post=28823"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/wp-json\/wp\/v2\/tags?post=28823"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/wp-json\/wp\/v2\/ppma_author?post=28823"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}