Blank white background with no objects or features visible.

Hallo EMEA! TrueFoundry baut seine Präsenz in Europa, dem Nahen Osten und Afrika weiter aus. Mehr erfahren. →

SSH-Server-Container für die Entwicklung auf Kubernetes

von Chirag Jain

Aktualisiert: November 3, 2026

Published: April 20, 2026

Letztes Jahr haben wir über die Ausführung von Hosted Jupyter Notebooks und VS Code (Code Server) auf Ihren Kubernetes-Clustern gesprochen. Wir haben verschiedene Ansätze und bestehende Lösungen verglichen, einschließlich des Mietens und Verwaltens von VMs. Anschließend haben wir unsere Ansätze beschrieben, um Benutzerfreundlichkeitsprobleme zu beheben, die Nutzung zu verbessern und Kubernetes-Details zu abstrahieren.

Seitdem haben wir viel Feedback von unseren Kunden erhalten, vor allem das Fehlen einer besseren Entwicklungs-Experience für vollwertige Anwendungen. Während Jupyter Lab hervorragend für interaktive Notebooks und leichtes Editieren geeignet ist, erfordert die Erweiterung auf vollständige IDE-Funktionen möglicherweise viel Bastelei mit Jupyter-Erweiterungen und ist für Nicht-Python-Codebasen möglicherweise immer noch keine optimale Erfahrung. Um solche Unzulänglichkeiten zu beheben, haben wir die Unterstützung für Code Server eingeführt, was mehr oder weniger VS Code im Browser ist. Obwohl es sich um eine Lösung ohne Einrichtungsaufwand handelt und viele Developer Experience-Probleme mit Jupyter Lab lindert, berichteten Benutzer von Hürden bei der Arbeit mit VS Code-Erweiterungen.

Beispielsweise kann Pylance, die Erweiterung, die eine hervorragende Python-Sprachunterstützung in VS Code bietet, aufgrund einer proprietären Microsoft-Lizenz nicht auf dem Code Server installiert werden. Stattdessen müssen sich Benutzer auf eine Kombination aus Jedi und Pyright verlassen, die mit Pylance immer noch nicht mithalten können. Ein weiteres Beispiel ist Github CoPilot – obwohl die Installation auf dem Code Server möglich ist, erfordert sie manuelle Anpassungen an der Erweiterungsdatei und ein Upgrade der Code Server-Version.

Obwohl die Editier-Experience auf dem Code Server nicht schlecht ist, gibt es manchmal eine spürbare Verzögerung und durcheinandergebrachten Text im Terminal, was störend sein kann. Wir wussten schon immer, dass die Verbindung von lokalem VS Code mit dem Remote-VS Code Server über SSH oder Tunnels eine bessere Erfahrung bieten würde.

Das Ziel besteht darin, den Benutzern das Erstellen eines Deployments zu ermöglichen, auf dem der OpenSSH Server in einem Ubuntu-basierten Container-Image mit derselben Festplattenpersistenz wie bei Jupyter Lab läuft, und den Benutzern die Verbindung dazu zu ermöglichen.

So sieht es auf der Plattform aus (docs):

In diesem Beitrag erläutern wir, wie wir die Verbindung zu Containern über SSH implementiert haben, ohne direkten Zugriff auf den Cluster zu gewähren und ohne Traffic außerhalb der VPC zu senden.

Istio und Routing

Wenn wir Anwendungen deployen, konfigurieren wir normalerweise einen Domainnamen, um diese Dienste zu erreichen, aber der Kauf einer Domain für jede Anwendung ist unerschwinglich teuer. Stattdessen kaufen wir eine einzelne Domain (z. B. acmecorp.com), konfigurieren Subdomains (docs.acmecorp.com) und/oder Pfad-Präfixe (acmecorp.com/blog/) und verwenden dann einen Router, um Regeln abzugleichen und Traffic an verschiedene Anwendungen zu leiten.

Wir verwenden Istio für unser gesamtes Ingress-Routing. Istio bietet neben vielen Funktionen komfortable Abstraktionen zur Konfiguration des zugrunde liegenden Envoy-Proxys, der tatsächlich das gesamte Routing verwaltet.

Verstehen wir, wie eine HTTP-Anfrage geroutet wird

Im obigen Beispiel, wenn ein Benutzer versucht, https://myapp.acmecorp.com/api/v1 aufzurufen:

  1. Zuerst wird *.acmecorp.com per DNS auf die öffentliche IP des externen Load Balancers aufgelöst. Der Port wird aufgrund des HTTPS-Protokolls als 443 abgeleitet.
  2. Eine TCP-Verbindung zum Load Balancer wird hergestellt und die HTTP-Request-Payload wird gesendet.
  3. Der Load Balancer leitet die Request-Payload an die Istio Ingress Pods weiter.
  4. Istio Ingress prüft alle VirtualServices-Konfigurationen (und die Gateway-Konfiguration), gleicht den Hostnamen (vor allem die Subdomain myapp) und das Pfad-Präfix ab und leitet an den entsprechenden Kubernetes Service weiter.
  5. Kubernetes leitet die Anfrage an einen der Endpunkte (Pod) für den Service weiter.

Dies wird als Layer 7 Routing bezeichnet, da wir tatsächliche Felder aus der HTTP-Spezifikation für das Routing verwenden.

Routing im Kontext von SSH

SSH verwendet ein benutzerdefiniertes Protokoll, das TCP für den Transport nutzt. Eine einfache SSH-Verbindung sieht etwa wie folgt aus‍

ssh user@somemachine.acmecorp.com -p 22

Hier versuchen wir, eine Verbindung zu somemachine.acmecorp.com auf Port 22 herzustellen. Hier muss somemachine.acmecorp.com:22 auf eine eindeutige Kombination aus IP-Adresse und Port aufgelöst werden, um das Ziel zu erreichen. Erinnern wir uns jedoch daran, dass in unserem Setup alle Subdomains so konfiguriert sind, dass sie auf denselben Load Balancer zeigen – das bedeutet, dass abc.acmecorp.com, xyz.acmecorp.com und somemachine.acmecorp.com alle auf dieselbe IP-Adresse aufgelöst werden und Istio/Envoy dann auf die Subdomain schauen und entscheiden soll, wohin geroutet wird. Im Fall von SSH ist dies jedoch nicht möglich, da Istio nach dem Auflösen der IP-Adresse und dem Herstellen einer TCP-Verbindung nur die Load Balancer-IP und die Portnummer sieht; die tatsächlichen Inhalte der Pakete werden von SSH verschlüsselt. Wie können wir also zu mehreren verschiedenen SSH-Zielen im Cluster routen?

Option 1: Eindeutige Ports auf demselben LoadBalancer verwenden

Da wir nur eindeutige Kombinationen aus IP-Adresse und Ports sicherstellen müssen, können wir den eindeutigen SSH-Containern einfach verschiedene Ports auf dem Load Balancer zuweisen.

Wir können dann ein TCP Route Port Match mit Istio konfigurieren.

Hier erreicht der gesamte TCP-Traffic, der an Port 22 des LoadBalancers eingeht, Service A, und der gesamte TCP-Traffic auf Port 23 erreicht Service B.

Obwohl dies gut funktioniert, gibt es einige Einschränkungen:

  • Maximal 65.535 SSH-Container können hinter einem einzigen Load Balancer erreicht werden. Das ist kein großes Problem, da wir realistischerweise nicht erwarten, dass so viele SSH-Container gleichzeitig deployed sind.
  • Das schwierigere Problem besteht darin, Ports auf dem externen Load Balancer präzise und dynamisch zu öffnen und freizugeben, ohne jemals den normalen Traffic zu unterbrechen. Obwohl dies durchaus möglich ist, könnte jeder Bug oder jede Race Condition zu schwerwiegenden Ausfallzeiten für andere Anwendungen führen. Ganz zu schweigen davon, dass das Öffnen beliebiger Ports für viele unserer Kunden ein erhebliches Sicherheitsrisiko darstellt.

Option 2: Einen neuen LoadBalancer für jeden SSH-Container verwenden

In diesem Fall haben wir abc.acmecorp.com und xyz.acmecorp.com explizit auf zwei verschiedene externe Load Balancer verwiesen, anstatt das Wildcard *.acmecorp.com zu verwenden. Nun zeigen sie jeweils auf eine eindeutige IP-Adresse und können von zwei verschiedenen Istio Gateways geroutet werden (eins-zu-eins mit einem externen Load Balancer verknüpft). Die offensichtliche Einschränkung hierbei ist, dass die Bereitstellung eines neuen Load Balancers pro SSH-Container unerschwinglich teuer wird.

Gibt es eine Möglichkeit, die Vorteile des Routings auf HTTP-Ebene zu nutzen und dennoch nur mit TCP-Traffic zu arbeiten? Hier kommt HTTP CONNECT ins Spiel!

Proxying mit HTTP CONNECT

Die HTTP CONNECT-Methode ermöglicht das Einrichten eines „Tunnels“ zwischen zwei Zielen über einen Proxy. Stellen Sie sich die alten Zeiten der Telefonvermittlungen vor – Sie möchten eine Nummer anrufen, haben aber keine direkte Leitung dorthin; stattdessen stellt ein Vermittler dazwischen die Verbindung in Ihrem Namen her und zieht sich dann zurück, damit die beiden Parteien kommunizieren können.

Telephone switchboard - Wikipedia

Wir empfehlen, sich das folgende Video für eine gute Erklärung anzusehen: https://www.youtube.com/watch?v=PAJ5kK50qp8

Glücklicherweise verwenden wir in unserem Fall bereits einen Proxy, der CONNECT nutzen kann: Envoy Proxy. Schauen wir uns an, wie das in unserem Anwendungsfall funktionieren würde:

  1. Der Client öffnet eine Verbindung zu acmecorp.com:80 – dem externen Load Balancer, der den Traffic an Envoy leitet.
  2. Der Client sendet eine HTTP CONNECT-Anfrage

CONNECT svc-a.ns.cluster.svc.local:80 HTTP/1.1
Host: svc-a.ns.cluster.svc.local

welche Envoy anweist, in ihrem Namen eine TCP-Verbindung zu svc-a.ns.cluster.svc.local:80 herzustellen

  1. Sobald eine Verbindung hergestellt ist, wird ein 200 OK an den Client zurückgegeben.
  2. Ab diesem Zeitpunkt kümmert sich Envoy nicht mehr um den Inhalt des Traffics und fungiert als „Tunnel“, der den Traffic zwischen dem Client und dem Pod fließen lässt. Dies kann alles sein, was auf TCP basiert, einschließlich, aber nicht beschränkt auf SSH.

Beachten Sie, dass svc-a.ns.cluster.svc.local:80 ein Kubernetes Service ist und nicht auf eine öffentliche IP-Adresse zeigt, sondern nur innerhalb des Kubernetes-Clusters aufgelöst werden kann. Da sich Envoy innerhalb des Clusters befindet, können wir ihn so konfigurieren, dass er die Pods dahinter erreicht.

Es bleibt nur noch, Envoy so zu konfigurieren, dass er ein solches Routing durchführt. Leider verfügt Istio nicht über hochrangige Abstraktionen, um dies einfach zu konfigurieren; stattdessen müssen wir Patches auf die Envoy-Konfiguration anwenden, indem wir Envoy Filters verwenden.

Envoy Filters

Das Verständnis der Envoy-Funktionen und Envoy Filters den Rahmen dieses Blogbeitrags sprengen würde, betrachten Sie es einfach als eine bequeme Möglichkeit, Istio-Routing-Regeln mit kleinen Patches zu ändern. Um CONNECT-basiertes Routing zu aktivieren, müssen wir:

  1. Einen öffentlich zugänglichen Port auf dem LoadBalancer haben, um TCP-Traffic zu akzeptieren (z. B. 2222), und das entsprechende Istio Gateway so konfigurieren, dass es HTTP-Traffic akzeptiert. Wir haben uns entschieden, bei Port 80 zu bleiben, da wir ihn bereits für normalen HTTP-Traffic verwenden und der SSH-Traffic ohnehin verschlüsselt wird.
  2. Den öffentlich zugänglichen Port am Gateway so konfigurieren, dass er Anfragen vom Typ CONNECT akzeptiert. Wir haben festgestellt, dass dies für Anfragen an Port 80 bereits aktiviert ist. Für jeden anderen Port können Sie einen Envoy Filter wie folgt anwenden:
   E.g. Enable CONNECT on Port 2222apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
spec:
 configPatches:
   - applyTo: NETWORK_FILTER
     match:
       context: GATEWAY
       listener:
         filterChain:
           filter:
             name: envoy.filters.network.http_connection_manager
         portNumber: 2222
     patch:
       operation: MERGE
       value:
         typed_config:
           '@type': >-
             type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
           http2_protocol_options:
             allow_connect: true
           upgrade_configs:
             - upgrade_type: CONNECT
 workloadSelector:
   labels:
     app: tfy-istio-ingress
  1. Für jeden SSH-Container CONNECT-basiertes Routing konfigurieren:

apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
 name: svc-a-ns-ssh-envoy-filter
 namespace: istio-system
spec:
 configPatches:
   - applyTo: NETWORK_FILTER
     match:
       context: GATEWAY
       listener:
         filterChain:
           filter:
             name: envoy.filters.network.http_connection_manager
         portNumber: 80
     patch:
       operation: MERGE
       value:
         typed_config:
           '@type': >-
             type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
           route_config:
             name: local_route
             virtual_hosts:
               - domains:
                   - svc-a.ns.svc.cluster.local:80
                 name: svc-a-ns-ssh-vh
                 routes:
                   - match:
                       connect_matcher: {}
                     route:
                       cluster: >-
                         outbound|80||svc-a.ns.svc.cluster.local
                       upgrade_configs:
                         - connect_config: {}
                           enabled: true
                           upgrade_type: CONNECT
 workloadSelector:
   labels:
     istio: tfy-istio-ingress

Das ist ein sehr furchterregend aussehendes YAML, aber alles, was wir tun, ist das Ändern des Listeners auf Port 80 am Gateway, um nach CONNECT-Anfragen an svc-a.ns.svc.cluster.local:80 zu suchen und sie an outbound|80||svc-a.ns.svc.cluster.local zu leiten, d. h. an den Port 80 des Kubernetes Service svc-a.ns.svc.cluster.local, wo unser OpenSSH-Server im Container auf SSH-Verbindungen wartet.

Puffern von CONNECT auf der SSH-Client-Seite

Von sich aus weiß der SSH-Client nichts von HTTP CONNECT. Stattdessen bietet er eine ProxyCommand-Option, die es anderen Programmen ermöglicht, die SSH-Verbindung zu erleichtern. Hier verwenden wir das ProxyTunnel-Projekt, das dies vereinfacht. Die Konfiguration in ~/.ssh/config sieht wie folgt aus

Host svc-a-ns
 User jovyan
 HostName svc-a.ns.svc.cluster.local
 Port 80
 ServerAliveInterval 100
 IdentityFile ~/.ssh/my-private-key
 ProxyCommand proxytunnel -v -p ssh.acmecorp.com:80 -o %h -d %h:%p

Nachdem all dies erledigt ist, können sich Benutzer jetzt einfach verbinden und ihren bevorzugten Entwicklungs-Workflow einrichten – sei es Neovim, VS Code, JetBrains IDE usw.

Einschränkungen & Potenzielle Lösungen

Obwohl diese Funktion die Developer Experience in Bezug auf Code-Bearbeitung und -Ausführung erheblich verbessert, gelten weiterhin einige Einschränkungen, da wir immer noch innerhalb eines Containers laufen.

  • Docker funktioniert nicht, weil wir uns bereits in einem Container befinden. Theoretisch ist es möglich, einige Dinge mit DIND zum Laufen zu bringen, aber das bringt eigene Herausforderungen mit sich.
  • Änderungen am Root-Dateisystem des Containers / sind über Container-Neustarts hinweg nicht persistent. Wir bieten eine Möglichkeit, unser SSH-Server-Image zu erweitern und von diesen benutzerdefinierten Images aus zu starten.
  • Kubernetes Pods sind als kurzlebig gedacht und können verschoben werden, was für eine Entwicklungsumgebung jedoch unerwünscht ist. Wir konfigurieren Pod Disruption Budgets, um zu verhindern, dass der Pod verschoben wird.
  • Obwohl das Proxying transparent ist, fließt der Traffic weiterhin durch den Load Balancer und die Istio Envoy Pods. Das bedeutet, dass ungewöhnliche Aktionen in der Entwicklung, wie das Hoch- oder Herunterladen riesiger Dateien, Bandbreite und Ressourcen verbrauchen und anderen Traffic beeinträchtigen können. Es ist am besten, ein separates Set von LoadBalancer-, Gateway- und Envoy-Pods für die Verbindung zu SSH-Containern zu verwenden.

SSH-Server-Container auf Kubernetes bei TrueFoundry

TrueFoundry ist eine ML/LLM-Deployment-PaaS über Kubernetes, um Entwickler-Workflows zu beschleunigen und ihnen volle Flexibilität beim Testen und Deployen von Modellen zu bieten, während gleichzeitig volle Sicherheit und Kontrolle für das Infra-Team gewährleistet werden. Über unsere Plattform ermöglichen wir es Teams, Modelle in 15 Minuten mit 100 % Zuverlässigkeit, Skalierbarkeit und der Möglichkeit zum Rollback in Sekunden zu deployen und zu überwachen – so können Kosten gespart und Modelle schneller in die Produktion gebracht werden, was echten geschäftlichen Mehrwert schafft.  

Try now.

One gateway for all your models, MCP servers, and agents. No credit card needed.

Melde dich an
Inhaltsverzeichniss

Steuern, implementieren und verfolgen Sie KI in Ihrer eigenen Infrastruktur

Buchen Sie eine 30-minütige Fahrt mit unserem KI-Experte

Eine Demo buchen

Der schnellste Weg, deine KI zu entwickeln, zu steuern und zu skalieren

Demo buchen
Summarize with
ChatGPT logo by OpenAI
Perplexity AI logo
Blurry red snowflake on white background, symmetrical frosty design with soft edges and abstract shape.

Entdecke mehr

October 5, 2023
|
Lesedauer: 5 Minuten

<Webinar>GenAi Showcase for Companies

Best Fine Tuning Tools for Model Training
May 3, 2024
|
Lesedauer: 5 Minuten

Die 6 besten Fine-Tuning-Tools für das Modelltraining im Jahr 2026

May 25, 2023
|
Lesedauer: 5 Minuten

Open-Source-LLMs: Nutzen oder untergehen

August 27, 2025
|
Lesedauer: 5 Minuten

Kartierung des On-Prem-AI-Marktes: Von Chips bis zu Control Planes

November 14, 2026
|
Lesedauer: 5 Minuten

Claude Managed Agents vs LangChain Deep Agents: Which Agent Harness Should You Choose?

Keine Artikel gefunden.
November 13, 2026
|
Lesedauer: 5 Minuten

Claude Managed Agents vs TrueForge: Which Agent Harness Should Enterprise Teams Run in 2026

Keine Artikel gefunden.
 What is an LLM Gateway
November 13, 2026
|
Lesedauer: 5 Minuten

Was ist ein LLM Gateway? Ein kompletter Leitfaden

Technik und Produkt
November 13, 2026
|
Lesedauer: 5 Minuten

Helm Charts auf ArtifactHub über Hosting auf GitHub Pages

Technik und Produkt
Keine Artikel gefunden.

Aktuelle Blogs

Black left pointing arrow symbol on white background, directional indicator.
Black left pointing arrow symbol on white background, directional indicator.
Machen Sie eine kurze Produkttour
Produkttour starten
Produkttour