Próximo seminario web: Seguridad empresarial para Claude Code | 21 de abril · 11:00 a. m. PST. Regístrese aquí →

SSH server contenedores for Kubernetes development

Por Chirag Jain

Actualizado: February 29, 2024

Resumir con

El año pasado, hablamos de correr Cuadernos Jupyter alojados y VS Code (servidor de código) en tus clústeres de Kubernetes. Comparamos varios enfoques y soluciones existentes, incluidos el alquiler y la administración de máquinas virtuales. Luego describimos nuestros enfoques para abordar los problemas de usabilidad a fin de hacer que la experiencia fuera más agradable y abstraer los detalles de Kubernetes.

Desde entonces, hemos recibido muchos comentarios de nuestros clientes, principalmente sobre la falta de una mejor experiencia de desarrollo para aplicaciones completas. Si bien Jupyter Lab es ideal para libretas interactivas y para realizar ediciones ligeras, llevarlo a todas sus capacidades de IDE puede requerir mucho trabajo con las extensiones de Jupyter y, aun así, puede que no sea una gran experiencia para bases de código que no sean de Python. Para subsanar estas deficiencias, lanzamos Servidor de códigos soporte que es más o menos VS Code en el navegador. Si bien es una solución que no requiere ninguna configuración y alivia muchos problemas de experiencia de desarrollador con Jupyter Lab, los usuarios comentaron que tenían problemas al trabajar con las extensiones de VS Code.

Por ejemplo, Pylance, la extensión que proporciona una excelente compatibilidad con el lenguaje Python en VS Code no se puede instalar en Code Server debido a una licencia propiedad de Microsoft. En cambio, los usuarios tienen que confiar en una combinación de Jedi y Derecho de autor que aún no están a la altura de Pylance. Sin embargo, otro ejemplo es CoPilot de Github - si bien es posible instalarlo en Code Server, es necesario manipular manualmente el archivo de extensión y actualizar la versión de Code Server.

Si bien la experiencia de edición de Code Server no es mala, a veces hay un retraso notable y texto confuso en la terminal, lo que puede resultar molesto. Siempre supimos que conectar VS Code local con un servidor VS Code remoto a través de SSH o túneles sería una mejor experiencia.

El objetivo es permitir a los usuarios crear una implementación que ejecute el servidor OpenSSH en una imagen de contenedor basada en Ubuntu con la misma persistencia de disco que Jupyter Lab y permitir que los usuarios se conecten a ella.

Así es como se ve en la plataforma (documentos):

En esta publicación, veremos cómo implementamos la conexión a contenedores mediante SSH sin proporcionar acceso directo al clúster y sin enviar tráfico fuera de la VPC.

Istio y enrutamiento

Cuando implementamos aplicaciones, normalmente configuramos un nombre de dominio para llegar a esos servicios, pero comprar un dominio para cada aplicación es prohibitivamente caro. En su lugar, compramos un único dominio (por ejemplo, acmecorp.com), configuramos subdominios (docs.acmecorp.com) o prefijos de ruta (acmecorp.com/blog/) y, a continuación, utilizamos un router para hacer coincidir las reglas y dirigir el tráfico a diferentes aplicaciones.

Nosotros utilizamos Istio para todas nuestras rutas de entrada. Istio, entre otras muchas funciones, ofrece prácticas abstracciones para configurar el subyacente Enviado proxy que realmente gestiona todo el enrutamiento.

Vamos a entender cómo se enruta una solicitud HTTP

En lo anterior, cuando un usuario intenta buscar https://myapp.acmecorp.com/api/v1

  1. En primer lugar, *.acmecorp.com es un DNS resuelto en la IP pública del balanceador de cargas externo. El puerto se deduce como 443 debido al protocolo https.
  2. Se establece una conexión TCP con el balanceador de cargas y se envía la carga útil de la solicitud HTTP
  3. Load Balancer dirige la carga útil de la solicitud a Istio Ingress Pods
  4. Istio Ingress lo analiza todo Servicios virtualesconfiguración (y Gateway), coincide con el nombre de host (lo que es más importante, el subdominio myapp) y el prefijo de ruta y las rutas al servicio de Kubernetes correspondiente
  5. Kubernetes dirige la solicitud a uno de los puntos finales (pod) del servicio

Esto se denomina enrutamiento de capa 7 porque utilizamos campos reales de la especificación HTTP para realizar el enrutamiento.

Enrutamiento en el contexto de SSH

SSH usa un protocolo personalizado que usa TCP para el transporte. Una conexión SSH simple tiene un aspecto similar al siguiente

ssh user@somemachine.acmecorp.com -p 22

Aquí estamos intentando conectarnos a somemachine.acmecorp.com en el puerto 22. Aquí somemachine.acmecorp.com:22 tiene que convertirse en una combinación única de dirección IP y puerto para llegar al destino. Pero recuerda que en nuestra configuración, todos los subdominios están configurados para apuntar al mismo balanceador de cargas, lo que significa que abc.acmecorp.com, xyz.acmecorp.com y somemachine.acmecorp.com se resuelven en la misma dirección IP y, a continuación, Istio/Envoy debe mirar el subdominio y decidir hacia dónde enrutar. Pero en el caso de SSH, esto no es posible porque después de resolver la dirección IP y establecer una conexión TCP, lo único que Istio ve es la IP y el número de puerto del balanceador de cargas, y SSH cifra el contenido real de los paquetes. Entonces, ¿cómo podemos enrutar a varios destinos SSH diferentes del clúster?

Opción 1: usar puertos únicos en el mismo LoadBalancer

Como solo necesitamos garantizar combinaciones únicas de direcciones IP y puertos, podemos asignar diferentes puertos en el balanceador de cargas a contenedores SSH únicos.

Luego podemos configurar Coincidencia de puertos de ruta TCP con Istio

Aquí, todo el tráfico TCP que llegue al puerto 22 del LoadBalancer llegará al servicio A y todo el tráfico TCP del puerto 23 llegará al servicio B.

Si bien esto funciona bien, existen algunas limitaciones

  • Se puede alcanzar un máximo de 65.535 contenedores SSH con un solo balanceador de cargas. Esto no es gran cosa porque, siendo realistas, no esperamos que tantos contenedores SSH se desplieguen al mismo tiempo.
  • El problema más complicado es abrir y liberar de forma dinámica y precisa los puertos del balanceador de cargas externo sin interrumpir ningún otro tráfico normal. Si bien es cierto que es posible, cualquier error o condición de carrera podría provocar graves interrupciones en otras aplicaciones. Sin mencionar que la apertura arbitraria de puertos es un riesgo de seguridad importante para muchos de nuestros clientes.

Opción 2: usar un LoadBalancer nuevo para cada contenedor SSH

En este caso, hemos apuntado explícitamente a abc.acmecorp.com y xyz.acmecorp.com a dos balanceadores de cargas externos diferentes en lugar del comodín *.acmecorp.com. Ahora cada uno de ellos apunta a una dirección IP única y pueden ser enrutados por dos direcciones diferentes Puerta de enlace Istio (uno a uno vinculado con un balanceador de cargas externo). La limitación obvia en este caso es que el aprovisionamiento de un nuevo balanceador de cargas por contenedor SSH resulta prohibitivamente caro.

¿Hay alguna forma de aprovechar el enrutamiento a nivel HTTP y seguir funcionando solo con el tráfico TCP? ¡Introduzca HTTP CONNECT!

Proxy mediante HTTP CONNECT

El CONEXIÓN HTTP El método permite establecer un «túnel» entre dos destinos a través de un proxy. Imagínese los viejos tiempos de las centralitas telefónicas: quiere llamar a un número pero no tiene una línea directa para comunicarse con él, sino que un operador intermedio facilita la conexión en su nombre y luego evita que las dos partes se comuniquen.

Telephone switchboard - Wikipedia

Recomendamos ver el siguiente vídeo para obtener una buena explicación: https://www.youtube.com/watch?v=PAJ5kK50qp8

Afortunadamente, en nuestro caso, ya utilizamos un proxy capaz de usar CONNECT - Envoy Proxy. Veamos cómo funcionaría en nuestro caso de uso:

  1. El cliente abre una conexión a acmecorp.com:80, el balanceador de cargas externo que dirige el tráfico a Envoy.
  2. El cliente envía una solicitud HTTP CONNECT

CONECTAR svc-a.ns.cluster.svc.local:80 HTTP/1.1
Anfitrión: svc-a.ns.cluster.svc.local

que indica a Envoy que establezca una conexión TCP a svc-a.ns.cluster.svc.local:80 en su nombre

  1. Una vez que se establece una conexión, se devuelve A 200 OK al cliente.
  2. Después de este punto, Envoy deja de preocuparse por el contenido del tráfico y actúa como un «túnel» que permite que el tráfico fluya entre el cliente y la cápsula. Puede ser cualquier cosa que funcione sobre TCP, incluido, entre otros, SSH.

Tenga en cuenta que svc-a.ns.cluster.svc.local:80 es un servicio de Kubernetes y no apunta a ninguna dirección IP pública, sino que solo se puede resolver dentro del clúster de Kubernetes. Como Envoy vive dentro del clúster, podemos configurarlo para que llegue a los pods que se encuentran detrás de él.

Todo lo que queda es configurar Envoy para que haga ese enrutamiento. Desafortunadamente, Istio no tiene abstracciones de alto nivel para configurar esto fácilmente, sino que tenemos que aplicar parches a la configuración de Envoy usando Filtros Envoy

Filtros Envoy

Comprender las capacidades de Envoy y los filtros de Envoy está fuera del alcance de esta entrada de blog, pero tómalo como una forma cómoda de modificar las reglas de enrutamiento de Istio mediante pequeños parches. Para habilitar el enrutamiento basado en CONNECT, necesitamos

  1. Tener un puerto expuesto públicamente Equilibrador de carga para aceptar el tráfico TCP (por ejemplo, digamos 2222) y configurar el correspondiente Puerta de enlace Istio para aceptar el tráfico HTTP. Elegimos quedarnos con el puerto 80 porque ya lo usamos para el tráfico HTTP normal y el tráfico SSH se cifrará de todos modos.
  2. Configure el puerto expuesto públicamente en Gateway para aceptar solicitudes de tipo CONNECT. Descubrimos que ya está habilitado para las solicitudes al puerto 80. Para cualquier otro puerto, puedes aplicar un filtro Envoy de la siguiente manera:
Por ejemplo, habilite CONNECT en el puerto 2222APIVersion: networking.istio.io/v1alpha3
tipo: EnvoyFilter
especificación:
Parches de configuración:
- Aplicar a: NETWORK_FILTER
partido:
contexto: GATEWAY
oyente:
Cadena de filtros:
filtro:
nombre: envoy.filters.network.http_connection_manager
Número de puerto: 2222
parche:
operación: MERGE
valor:
configuración_escrita:
'@type': >-
Escriba .googleapis.com/envoy.extensions.filters.network.HTTP_Connection_Manager.v3.HttpConnectionManager
opciones de protocolo HTTP 2:
allow_connect: verdadero
upgrade_configs:
- tipo_actualización: CONECTAR
Work load selector:
tags:
aplicación: tfy-istio-ingress
  1. Para cada contenedor SSH, configure el enrutamiento basado en CONNECT:

Versión de API: networking.istio.io/v1alpha3
tipo: EnvoyFilter
metadatos:
nombre: filtro svc-a-ns-ssh-envoy-filter
espacio de nombres: istio-system
especificación:
Configuration Parches:
- Aplicar a: NETWORK_FILTER
partido:
contexto: GATEWAY
oyente:
Filter Kadin:
filter:
name: envoy.filters.network.http_connection_manager
Port number: 80
parche:
operación: FUSIONAR
valor:
configuración escrita:
'@type': >-
Escriba .googleapis.com/envoy.extensions.filters.network.HTTP_Connection_Manager.v3.HttpConnectionManager
route_config:
nombre: local_route
hostes_virtuales:
- dominios:
- svc-a.ns.svc.cluster.local: 80
name: svc-a-ns-ssh-vh
rutas:
- coinciden:
connect_matcher: {}
recorrido:
clúster: >-
saliente|80||svc-a.ns.svc.cluster.local
upgrade_configs:
- connect_config: {}
habilitado: verdadero
tipo_actualización: CONECTAR
Work load selector:
tags:
sitio: tfy-istio-ingress

Es un YAML que da mucho miedo, pero lo único que estamos haciendo es modificar el oyente del puerto 80 del Gateway para que coincida con la solicitud CONNECT de svc-a.ns.svc.cluster.local:80 y enrutarlo a outbound|80||svc-a.ns.svc.cluster.local, es decir, nuestro puerto 80 del servicio de Kubernetes svc-a.ns.svc.cluster.local, el servidor OpenSSH está esperando conexiones SSH dentro del contenedor.

Iniciar CONNECT en el lado del cliente SSH

Por sí solo, el cliente SSH no sabe nada acerca de HTTP CONNECT. En su lugar, ofrece un Proxy Command opción que permite a otros programas facilitar la conexión SSH. Aqui utilizamos el Proxy Tunnel proyecto que hace que esto sea fácil. La configuración en ~/.ssh/config parece que sigue

Hospedar svc-a-ns
Usuario jovyan
Nombre del host svc-a.ns.svc.cluster.local
Puerto 80
ServerAlive Interval 100
Identity file ~/.ssh/my-private-key
Proxy Tunnel ProxyCommand -v -p ssh.acmecorp.com: 80 -o %h -d %h: %p

Una vez hecho esto, los usuarios ahora pueden conectarse y configurar fácilmente su flujo de trabajo de desarrollo favorito, ya sea Neovim, VS Code, JetBrains IDE, etc.

Limitaciones y posibles soluciones

Si bien esta función mejora en gran medida la experiencia del desarrollador en términos de edición y ejecución de código, aún se aplican algunas limitaciones porque seguimos ejecutándolo dentro de un contenedor.

  • Docker no funciona porque ya estamos dentro de un contenedor. Teóricamente, es posible hacer que algunas cosas funcionen con ENCONTRAR, pero viene con sus desafíos.
  • Cambios realizados en el sistema de archivos raíz del contenedor / no son persistentes cuando se reinicia el contenedor. Ofrecemos una forma de ampliar la imagen de nuestro servidor SSH y partir de esas imágenes personalizadas.
  • Los Pods de Kubernetes están diseñados para ser efímeros y se pueden mover, pero eso no es deseable para un entorno de desarrollo. Configuramos los presupuestos de disrupción de los pods para evitar que los pods se muevan de un sitio a otro.
  • Aunque el proxy es transparente, el tráfico sigue fluyendo a través de los módulos del balanceador de cargas y de Istio Envoy. Esto significa que hacer algo extraño durante el desarrollo, como subir o descargar archivos enormes, puede consumir ancho de banda y recursos y afectar al resto del tráfico. Es mejor usar un conjunto independiente de pods de LoadBalancer, Gateway y Envoy para conectarse a los contenedores SSH.

Contenedores de servidores SSH in Kubernetes in TrueFoundry

True Foundry es una implementación de PaaS de ML/LLM sobre Kubernetes para acelerar los flujos de trabajo de los desarrolladores y, al mismo tiempo, permitirles una flexibilidad total a la hora de probar e implementar modelos, al tiempo que garantiza una seguridad y un control totales para el equipo de Infra. A través de nuestra plataforma, permitimos a los equipos implementar y supervisar modela en 15 minutos con un 100% de confiabilidad, escalabilidad y la capacidad de revertirse en segundos, lo que les permite ahorrar costos y lanzar los modelos a la producción más rápido, lo que permite obtener un verdadero valor empresarial.

La forma más rápida de crear, gobernar y escalar su IA

Inscríbase
Tabla de contenido

Controle, implemente y rastree la IA en su propia infraestructura

Reserva 30 minutos con nuestro Experto en IA

Reserve una demostración

La forma más rápida de crear, gobernar y escalar su IA

Demo del libro

Descubra más

October 5, 2023
|
5 minutos de lectura

<Webinar>GenAI Showcase para empresas

Best Fine Tuning Tools for Model Training
May 3, 2024
|
5 minutos de lectura

Las 6 mejores herramientas de ajuste para el entrenamiento de modelos en 2026

May 25, 2023
|
5 minutos de lectura

LLM de código abierto: abrazar o perecer

August 27, 2025
|
5 minutos de lectura

Mapeando el mercado de la IA local: desde chips hasta aviones de control

April 22, 2026
|
5 minutos de lectura

Mercados de agentes de IA: el futuro de la automatización de nivel empresarial

No se ha encontrado ningún artículo.
Detailed Guide to What is an AI Gateway?
April 22, 2026
|
5 minutos de lectura

¿Qué es AI Gateway? Conceptos básicos y guía

No se ha encontrado ningún artículo.
April 22, 2026
|
5 minutos de lectura

Aprovechar la puerta de enlace de IA de TrueFoundry para el cumplimiento de FIPS

No se ha encontrado ningún artículo.
April 22, 2026
|
5 minutos de lectura

Integración de GraySwan con TrueFoundry

No se ha encontrado ningún artículo.
No se ha encontrado ningún artículo.

Blogs recientes

Realice un recorrido rápido por el producto
Comience el recorrido por el producto
Visita guiada por el producto