- Gitpod ha usado Kubernetes durante 6 años para construir una “plataforma de entornos de desarrollo remotos”, dando soporte a 1.5 millones de usuarios y ofreciendo miles de entornos de desarrollo cada día
- Sin embargo, se dio cuenta de que Kubernetes no es adecuado para construir entornos de desarrollo
- Esto no trata de si se debe o no usar Kubernetes para cargas de trabajo de producción, ni de cómo crear la experiencia de desarrollador para desplegar aplicaciones en K8s
→ Se trata de cómo construir entornos de desarrollo en la nube (o de cómo no hacerlo)
[Por qué los entornos de desarrollo son especiales]
- Tienen mucho estado y una interacción intensa
- No pueden moverse entre nodos
- Grandes volúmenes de código fuente, cachés de compilación, contenedores Docker, datos de prueba, etc. cambian con frecuencia y migrarlos tiene un costo alto
- A diferencia de los servicios de producción, aquí hay una interacción 1 a 1 entre el desarrollador y el entorno
- Los desarrolladores están profundamente ligados al código fuente y a sus cambios
- No les gusta perder cambios en el código fuente ni ser bloqueados por el sistema
- Los entornos de desarrollo son especialmente sensibles a los fallos
- Tienen patrones de uso de recursos impredecibles
- La mayor parte del tiempo no necesitan mucho ancho de banda de CPU, pero pueden requerir varios núcleos en unos cientos de ms
- Si tarda más que eso, se traduce en latencia inaceptable y falta de respuesta
- Requieren permisos y capacidades amplias
- A diferencia de las cargas de trabajo de producción, necesitan acceso root y capacidad para descargar/instalar paquetes
- Lo que en producción sería un problema de seguridad, en un entorno de desarrollo es comportamiento esperado (acceso root, funciones de red ampliadas, montajes adicionales de filesystem, etc.)
- Estas características los diferencian de las cargas de trabajo de aplicaciones comunes y afectan fuertemente las decisiones de infraestructura
[Sistema actual: Kubernetes]
- En los inicios de Gitpod, Kubernetes parecía la opción ideal como infraestructura
- Su escalabilidad, orquestación de contenedores y rico ecosistema encajaban bien con la visión de entornos de desarrollo en la nube
- Pero a medida que crecieron la escala y la base de usuarios, surgieron dificultades en seguridad y manejo de estado
- Kubernetes fue diseñado para ejecutar cargas de trabajo de aplicaciones bien controladas, no entornos de desarrollo difíciles de manejar
- Administrar Kubernetes a gran escala es complejo
- Servicios administrados como GKE o EKS alivian parte del problema, pero traen sus propias restricciones y límites
- Muchos equipos que quieren operar CDE tienden a subestimar la complejidad de Kubernetes
- Esto llevó a una carga de soporte considerable en el producto autoadministrado anterior de Gitpod
Dificultades en la gestión de recursos
- La asignación de CPU y memoria ha sido el mayor reto
- Compartir entornos en un mismo nodo suena atractivo, pero en la práctica el efecto de noisy neighbor se vuelve muy fuerte
- Problemas de CPU
- Los entornos de desarrollo pasan de necesitar poca CPU a demandar mucha de forma repentina
- Se experimentó con soluciones basadas en CFS y controladores personalizados, pero era difícil predecir el comportamiento
- Incluso usando límites estáticos de CPU, aparecen problemas cuando varios procesos compiten
- Gestión de memoria
- Asignar memoria fija es simple, pero limitado
- El overbooking puede terminar en finalización de procesos
- La introducción de swap alivió en cierta medida la necesidad de overbooking
Optimización del rendimiento de almacenamiento
- Los IOPS y la latencia impactan la experiencia del entorno de desarrollo
- Se probaron varias configuraciones para encontrar un equilibrio entre velocidad, estabilidad, costo y rendimiento
- SSD RAID 0
- Almacenamiento en bloques como EBS o discos persistentes
- PVC
- El respaldo/restauración es una operación costosa
Autoscaling y optimización del tiempo de arranque
- Minimizar el tiempo de arranque era la prioridad número uno
- Se pensó que ejecutar múltiples workspaces en un mismo nodo mejoraría el arranque por la caché compartida, pero no fue así
- Kubernetes impone un límite inferior al tiempo de arranque
- Evolución del método de scale-out
- Se experimentó con scale-out usando ghost workspaces y ballast pods
- La introducción de plugins de autoscaler mejoró mucho la estrategia de escalado
- Autoscaling proporcional para manejar cargas pico
- Se inician pods vacíos para responder rápidamente a picos de demanda
- Diversos intentos para optimizar el image pull
- Pre-pull con DaemonSet, maximización de reutilización de capas, imágenes prehorneadas, Stargazer y lazy pulling, Registry-facade + IPFS
Complejidad de red
- Control de acceso a entornos de desarrollo
- Deben estar completamente aislados entre sí
- Las políticas de red ayudan, pero cuando aumenta el número de servicios aparecen problemas de confiabilidad
- Compartición del ancho de banda de red
- Algunos CNI soportan network shaping, pero eso agrega otro elemento más que controlar
Seguridad y aislamiento: equilibrio entre flexibilidad y protección
- El mayor desafío es ofrecer un entorno seguro sin quitar flexibilidad a los usuarios
- Dar privilegios root al usuario tiene muchos defectos
- Los user namespaces son una solución más fina
- Conversión de UID del filesystem, montajes
procenmascarados, soporte para FUSE, capacidades de red, habilitación de Docker
- Conversión de UID del filesystem, montajes
- Dificultades para implementar user namespaces
- Impacto en rendimiento, problemas de compatibilidad, complejidad y soporte para versiones de Kubernetes
[Experimentos con Micro VM]
- Al sentir los límites de Kubernetes, comenzaron a explorar tecnologías de micro VM (uVM) como Firecracker, Cloud Hypervisor y QEMU como un punto intermedio
- Esperaban mejorar el aislamiento de recursos, la compatibilidad con otras cargas de trabajo (como Kubernetes) y reforzar la seguridad, manteniendo a la vez las ventajas de la containerización
- Ventajas de las micro VM
- Ofrecen beneficios atractivos que encajan bien con los objetivos de los entornos de desarrollo en la nube
- Mejor aislamiento de recursos: aunque disminuye la capacidad de overbooking, el aislamiento de recursos mejora frente a los contenedores. Al desaparecer la contención de recursos del kernel compartido, la previsibilidad del rendimiento por entorno de desarrollo aumenta
- Snapshots de memoria y reanudación rápida: la función
userfaultfdde Firecracker soporta snapshots de memoria. Esto permite reanudar casi al instante toda la máquina, incluyendo procesos en ejecución. Desde la perspectiva del desarrollador, el arranque del entorno es mucho más rápido y se puede retomar justo donde se dejó el trabajo - Mejores límites de seguridad: las uVM pueden servir como una fuerte frontera de seguridad, haciendo innecesarios los complejos mecanismos de user namespaces implementados en Kubernetes. Esto permite compatibilidad total con una gama más amplia de cargas de trabajo, incluida la containerización anidada (ejecutar Docker o Kubernetes dentro del entorno de desarrollo)
- Dificultades de las micro VM
- Sin embargo, los experimentos con micro VM revelaron varios desafíos importantes
- Overhead: incluso siendo VM ligeras, las uVM generan más overhead que los contenedores. Esto afecta tanto el rendimiento como el uso de recursos, un factor clave en una plataforma de entornos de desarrollo en la nube
- Conversión de imágenes: convertir imágenes OCI en filesystems utilizables por uVM requiere soluciones personalizadas. Esto complica el pipeline de administración de imágenes y puede impactar el tiempo de arranque
- Restricciones según la tecnología
- Firecracker: falta de soporte para GPU (cada vez más importante en algunos flujos de trabajo de desarrollo) y falta de soporte para
virtiofs(lo que limita opciones eficientes para compartir filesystem) - Cloud Hypervisor: falta de soporte para
userfaultfd, lo que ralentiza el proceso de snapshot y restore (anulando una ventaja importante de las uVM)
- Firecracker: falta de soporte para GPU (cada vez más importante en algunos flujos de trabajo de desarrollo) y falta de soporte para
- Problema del movimiento de datos: con las uVM hay que manejar snapshots de memoria grandes, lo que complica más el movimiento de datos. Esto afecta tanto al scheduling como al tiempo de arranque, dos factores clave en la experiencia del usuario de entornos de desarrollo en la nube
- Consideraciones de almacenamiento: los experimentos conectando volúmenes EBS a micro VM abrieron nuevas posibilidades, pero también nuevas preguntas
- Almacenamiento persistente: guardar el contenido del workspace en volúmenes adjuntos evita tener que traer repetidamente los datos desde S3, con la expectativa de mejorar el tiempo de arranque y reducir el uso de red
- Consideraciones de rendimiento: compartir volúmenes de alto throughput entre workspaces podría mejorar el rendimiento de I/O, pero también plantea dudas sobre cómo implementar cuotas efectivas, controlar la latencia y garantizar escalabilidad
- Lecciones de los experimentos con micro VM
- Aunque las micro VM no terminaron siendo la solución principal de infraestructura, los experimentos dejaron aprendizajes valiosos
- Les gustó la experiencia de respaldo completo del workspace y de suspensión/reanudación del estado de ejecución para entornos de desarrollo
- Por primera vez empezaron a considerar salir de Kubernetes. Tras intentar integrar KVM y uVM en pods, comenzaron a explorar opciones fuera de Kubernetes
- El almacenamiento volvió a aparecer como un elemento clave para lograr las tres cosas a la vez: rendimiento de arranque estable, workspaces estables (prevención de pérdida de datos) y utilización óptima de las máquinas
Kubernetes es muy desafiante como plataforma para entornos de desarrollo
- Como se dijo antes, para los entornos de desarrollo se necesita un sistema que respete su naturaleza única y fuertemente stateful
- Debe otorgar los permisos que los desarrolladores necesitan para ser productivos, al mismo tiempo que garantiza límites de seguridad
- Y todo esto debe lograrse manteniendo bajo el overhead operativo y sin comprometer la seguridad
- Hoy es posible lograr todo esto con Kubernetes, pero a un costo considerable
- Aprendieron de la manera difícil la diferencia entre cargas de trabajo de aplicaciones y cargas de trabajo de sistema
- Kubernetes es increíblemente bueno
- Tiene el respaldo de una comunidad apasionada y ha construido un ecosistema realmente rico
- Si estás ejecutando cargas de trabajo de aplicaciones, Kubernetes sigue siendo una buena opción
- Pero para cargas de trabajo de sistema como los entornos de desarrollo, Kubernetes presenta enormes desafíos en seguridad y overhead operativo
- Las micro VM y presupuestos claros de recursos ayudan, pero el costo termina pesando más
- Por eso, después de años rediseñando a la fuerza los entornos de desarrollo para que encajaran en una plataforma Kubernetes, dieron un paso atrás para pensar cómo debía verse la arquitectura del futuro
- En enero de 2024 comenzaron a construir eso, y en octubre lanzaron Gitpod Flex
- Más de 6 años de aprendizajes extremadamente difíciles sobre cómo ejecutar de forma segura entornos de desarrollo a escala de internet quedaron incorporados en la base de su arquitectura
El futuro de los entornos de desarrollo
- En Gitpod Flex, retoman aspectos fundamentales de Kubernetes —la aplicación flexible de teoría de control y las API declarativas— mientras simplifican la arquitectura y mejoran la base de seguridad
- Orquestan los entornos de desarrollo con un control plane fuertemente inspirado en Kubernetes
- Introducen las capas de abstracción necesarias, específicas para entornos de desarrollo, y eliminan gran parte de la complejidad innecesaria de infraestructura
- Todo esto con la seguridad zero trust como máxima prioridad
- Gracias a esta nueva arquitectura, ahora pueden integrar devcontainers sin fricción
- También se abre la posibilidad de ejecutar entornos de desarrollo en desktop
- Como ya no cargan con el peso de una plataforma Kubernetes, Gitpod Flex puede desplegarse en self-hosted en menos de 3 minutos y en tantas regiones como se quiera
- Esto ofrece un control más fino sobre cumplimiento y mayor flexibilidad para modelar límites organizacionales y dominios
(Originalmente era otro artículo, pero como parecía mejor agruparlos, lo trasladé junto aquí.)
Gitpod Flex
- La primera plataforma de automatización para entornos de desarrollo zero trust
- Diseñada para ejecutarse en laptop, nube y on-premise, manteniendo el código fuente, los datos y la propiedad intelectual dentro de redes privadas
- Ofrece bloques base para automatizar el ciclo de vida del desarrollo de software, empezando por el entorno de desarrollo
- Automatizaciones (Automations)
- Tareas y servicios programables definidos a través de repositorios o APIs
- Ayudan a que los desarrolladores resuelvan por sí mismos y permiten que los equipos de productividad de desarrolladores centralicen mejoras del entorno de desarrollo
- Ofrecen mucho más que ejecutar scripts simples
- Permiten aprovisionamiento y seeding de bases de datos, personalización de flujos de trabajo de desarrolladores, ejecución de clústeres temporales, configuración de flujos de agentes basados en LLM, aplicación centralizada global/local de seguridad y compliance, etc.
- Entornos zero trust (Zero-trust environments)
- Verifican siempre y no confían nunca en ningún actor o servicio
- Bloquean por completo a actores maliciosos, reducen en gran medida la superficie de exposición a ataques y disminuyen el riesgo de malware o fuga de código
- Incluyen evaluación continua y verificación explícita, cifrado validado de nivel enterprise, control de acceso granular, control total sobre networking y registro completo de auditoría
- Lo más importante es mantener el código fuente, los datos y la propiedad intelectual dentro de redes privadas
- Gitpod Desktop
- Permite estandarizar y automatizar entornos de desarrollo locales
- Comienza con soporte para Apple Silicon
- Ofrece latencia cero, una alternativa más rápida, ligera y simple a Docker Desktop para desarrollo, optimización de costos usando cómputo local y soporte de recuperación ante desastres frente a caídas de la nube o de endpoints
- Soporte para Development Container
- Integra completamente la especificación Dev Container
- Se pueden usar configuraciones existentes de Dev Container sin cambios
- Ofrece compatibilidad con VS Code y otras herramientas compatibles
- Permite trabajar de forma consistente tanto en local como en la nube
- Adoptar el estándar Dev Container facilita definir, compartir y gestionar entornos de desarrollo
Será la base para los próximos 10 años de automatización del desarrollo de software
- Hemos pensado los entornos de desarrollo de forma demasiado estrecha
- Un entorno de desarrollo es más que un IDE, dependencias y herramientas: es el espacio fundamental donde se crea el software
- Es donde se hace prototipado de código, trabajo de humanos y máquinas, pruebas, refactorización, compilación, empaquetado, firmado y despliegue
- Su acceso sin comparación al contexto de desarrollo, flujos de trabajo e insights permite capacidades diferenciadas frente a otras plataformas de desarrollo
- Visión del producto
- La integración continua (CI) se fusiona con el entorno de desarrollo
- Actúa como system of record del desarrollo de software
- Será la plataforma para la próxima generación de herramientas para desarrolladores
- Más allá de solo mejorar las prácticas de codificación, busca construir la forma más rápida y segura para que las empresas —desde startups hasta Fortune 50— puedan escalar y tener éxito en los próximos 10 años
3 comentarios
Empresas nacionales que, con la excusa de la seguridad, obligan a usar escritorios virtuales con especificaciones de 8 GB de memoria. Qué amargo.
Ya es difícil encontrar gente que sepa bien de Kubernetes, así que me da la impresión de que será todavía más difícil encontrar personas que entiendan e intenten las alternativas que aquí se proponen.
Opiniones de Hacker News
Los desarrolladores deberían ser dueños del equipo de desarrollo que usan. Si se necesita un entorno consistente, el desarrollador debería ser dueño de su propio equipo y recibir imágenes de VM estables. Los intentos de mover el entorno de desarrollo a un host remoto casi siempre fracasan. Proporcionar hardware adecuado a los desarrolladores es más rentable que los recursos remotos. Se debe soportar la ejecución del stack local, y esto ayuda a mantener la consistencia mediante contenedores. Se necesitan herramientas que generen datos en el entorno local, y esto se puede automatizar. Aunque hay desventajas en la gestión de datos, en la mayoría de las empresas la capacidad de ejecución del equipo importa más que el código fuente.
Usar Kubernetes para cargas de trabajo de producción es un tema aparte; esto trata sobre cómo construir entornos de desarrollo en la nube. Es un artículo interesante sobre los trade-offs de ingeniería y la complejidad de Kubernetes.
Explica los problemas de Kubernetes y las soluciones que intentaron, pero al final falta una explicación de la alternativa que eligieron. Mencionan una nueva solución llamada Gitpod Flex, pero casi no hay información al respecto.
Kubernetes es adecuado para cargas sin estado, pero cuando hay estado LXC es más apropiado. LXC también puede agruparse en clústeres de forma similar a K8S y expone herramientas al plano de datos. Proporciona instancias de sistema similares a las VM y tiene un rendimiento parecido al de los contenedores Docker. Usa una sintaxis declarativa y puede utilizarse como capa base de un clúster de Kubernetes.
Elegir Kubernetes al construir una solución de CI demuestra que no se entendió bien el problema. Para fines de seguridad deberían usarse herramientas como Firecracker.
Kubernetes no es adecuado para entornos de desarrollo. Los entornos de desarrollo siempre están en un estado cambiante. No entiendo la necesidad de los entornos de desarrollo en la nube. El propósito de las apps containerizadas es evitar tener que sincronizar entornos de desarrollo entre equipos.
El paper de Kubernetes menciona como único caso de uso una combinación de flujos de trabajo de baja y alta latencia. Es difícil justificar considerar Kubernetes para el problema de Gitpod.
Trabajé en un proyecto similar a Gitpod, y no se entiende usar micro-VM para reemplazar Kubernetes. Kubernetes puede orquestar contenedores externos y podría usarse para ejecutar micro-VM. El problema más grande tiene que ver con el almacenamiento.
Construir entornos de desarrollo sobre Kubernetes es un desperdicio. Si el producto se autoalojará en la infraestructura del cliente, depurar y dar soporte se vuelve difícil. Es efectivo exponer a los ingenieros a problemas de red, memoria, cómputo y almacenamiento. Kubernetes es una mejora para equipos grandes.