Portaram o Kubernetes para o navegador
(ngrok.com)- webernetes é um projeto que levou partes do Kubernetes para TypeScript e tornou possível executar um cluster dentro do navegador; ele foi criado em 2 meses, com 552 commits, 629 arquivos e quase 100 mil linhas de código
- Em vez de compilar o Kubernetes diretamente para WebAssembly, ele reimplementa partes do kubelet, vários controladores, um CNI baseado em navegador, um runtime de contêineres no navegador e uma API para manipular o cluster
- Em vez de buscar imagens reais em registries, ele define imagens por meio de uma API em TypeScript, e o objetivo não é uma distribuição pronta para produção, mas sim criar conteúdo interativo sobre Kubernetes
- A maior parte do código foi escrita por LLM, mas cada linha foi revisada por humanos, e a validação foi feita com 204 testes de integração que executam os mesmos testes do k3s e 1.855 testes unitários portados da base Go do Kubernetes
- Durante a portabilidade, a LLM repetidamente fez abreviações, criou helpers arbitrários e omitiu testes, mostrando que, para obter o benefício da geração rápida de código, é preciso aplicar revisão e testes juntos
O que o webernetes executa no navegador
- webernetes é um projeto que faz uma portabilidade parcial do Kubernetes para TypeScript e permite executar um cluster no navegador
- O cluster de demonstração roda inteiramente dentro do navegador e realiza boa parte do que um cluster Kubernetes real faz
-
Ciclo de vida de Pods
- DNS e rede do cluster
- coleta de lixo de contêineres
- alocação de IP
- acompanhamento de
DeploymenteReplicaSet - os pontos azuis na demo mostram os Pods enviando requisições uns aos outros
-
Portabilidade parcial em vez de compilação para WebAssembly
- Não é o Kubernetes compilado para WebAssembly
- Mesmo um programa Go simples de
hello, world!compilado para WebAssembly tem cerca de 540KiB em gzip, enquanto o webernetes tem cerca de 140KiB em gzip - Compilar o Kubernetes inteiro para WebAssembly provavelmente exigiria transferências na casa dos megabytes e também geraria erros em tempo de compilação por causa de chamadas de API de nível de sistema que não podem ser usadas no navegador
- O webernetes é composto pelos seguintes elementos
- portabilidade parcial do binário kubelet do Kubernetes necessária para execução de Pods e probes
- portabilidade de vários controladores do Kubernetes, como scheduler de Pods, namespace controller, kube-proxy e deployment controller
- uma interface de rede de contêineres (CNI) baseada em navegador para comunicação entre Pods
- um runtime de contêineres baseado em navegador que permite ao kubelet executar contêineres via a interface de runtime de contêineres (CRI)
- a API do cluster webernetes para tarefas como aplicar manifests e observar recursos com watch
Como imagens são definidas e como a API é usada
- Para manter o tamanho reduzido, o webernetes não baixa imagens reais de registries como o Docker Hub
- Em vez disso, ele tem um registry baseado em navegador, e as imagens são definidas com uma API em TypeScript
- A imagem de exemplo
HelloWorldherda dew8s.BaseImagee, dentro deexec, retorna"Hello, world!"para requisições HTTP na porta 8080 - O fluxo de uso do cluster é o seguinte
- criar um cluster com
new w8s.Cluster() - registrar a imagem com
cluster.registerImage(HelloWorld) - aplicar um manifest
Deploymentdeapps/v1comcluster.apply() - consultar a lista de Pods com
cluster.api.corev1.listNamespacedPod() - observar mudanças em Pods com
cluster.informer("pods", ...) - observar eventos de requisição e resposta entre Pods com
cluster.on("request")ecluster.on("response") - enviar requisições HTTP para IPs de Pods pela rede do cluster com
cluster.fetch()
- criar um cluster com
- Há mais exemplos em webernetes repository examples
Uso pretendido e limitações atuais
- O objetivo do webernetes é criar conteúdo interativo sobre Kubernetes
- Ele não é uma distribuição Kubernetes pronta para produção, nem precisa executar imagens reais
- Basta que criadores de conteúdo consigam configurar workloads específicos para mostrar os conceitos de Kubernetes que querem explicar
- Entre os recursos ainda não suportados estão
- ConfigMaps
- Secrets
- recursos de Pod
- volumes persistentes
- várias outras funcionalidades do Kubernetes que ainda não foram necessárias
- A ideia é implementar mais funcionalidades do Kubernetes conforme elas forem sendo necessárias no processo de criação de conteúdo
Foi feito com LLM, mas não foi deixado por conta dela
- Quase todo o código do webernetes foi escrito por LLM
- Para garantir a confiabilidade do projeto, duas práticas foram adotadas em paralelo
- revisar manualmente cada linha de código
- criar centenas de testes para verificar se o webernetes se comporta como um cluster real
- A revisão manual trouxe confiança de que grande parte do código era idêntica linha a linha à base Go do Kubernetes
- Os testes servem para verificar se essa similaridade lexical realmente se traduz em equivalência de comportamento
- Erros que permaneceram após a revisão são de responsabilidade do autor do projeto, que pede para abrirem uma issue se encontrarem problemas
Por que o código portado precisou de revisão
- Em casos como escrever um compilador C com LLM ou portar o Bun de Zig para Rust, havia formas automáticas de verificar a correção
- a Anthropic tinha compiladores C existentes para comparação
- o Bun tinha uma suíte de testes grande o suficiente para permitir confiar a ponto de mesclar mais de 1 milhão de linhas de novo código Rust sem revisão manual
- O webernetes não tinha essa base
- se fosse necessário uma suíte de testes, ela teria de ser escrita manualmente
- se fosse comparar com o Kubernetes real, também seria preciso montar o método de comparação por conta própria
- A maior parte do código do webernetes foi portada da base Go do Kubernetes, e a LLM foi usada por ser mais rápida do que digitar tudo à mão
- Durante a portabilidade, a LLM cometeu erros repetidamente
- abreviação: caches como LRU cache, expiring cache, FIFO cache e transforming cache do Kubernetes podiam ser substituídos incorretamente por
Map, gerando comportamento errado - limpeza excessiva: podia criar funções helper que não existiam no código Go original, dificultando a revisão ou introduzindo diferenças sutis
- omissão: ao portar table tests de Go, frequentemente deixava casos de teste de fora por conta própria
- abreviação: caches como LRU cache, expiring cache, FIFO cache e transforming cache do Kubernetes podiam ser substituídos incorretamente por
- Para confiar no resultado da portabilidade feita por LLM, é preciso revisar a saída, e o autor do projeto considera que ela não sabe quais atalhos ele pode ou não aceitar
Testes comparando com um cluster real
- Mesmo que o código pareça semelhante lado a lado com o original, os runtimes de Go e JavaScript são diferentes, então o comportamento pode divergir
- O webernetes também precisou de versões em JavaScript de channels, mutexes, da instrução
selectde Go e de outros comportamentos típicos da linguagem - O mesmo código de teste foi executado tanto no webernetes quanto em um cluster k3s para comparar o comportamento
- Como alvo de compatibilidade de API, foi escolhido o cliente oficial JavaScript de Kubernetes com tipos TypeScript, kubernetes-client/javascript
- O test harness alterna o ambiente de execução via
kubernetes.describe(..)pnpm test:nodeexecuta os testes contra o k3s em ambiente Nodepnpm test:browserexecuta os testes contra o webernetes em um navegador headless
- Os testes de integração verificam não só o código portado, mas também se o container runtime e a cluster network personalizados e baseados em navegador se comportam como em um cluster real
- Ao encontrar um bug, primeiro é criado um teste que passa no k3s e falha no webernetes; depois, esse loop de feedback é usado com ajuda da LLM para entender a causa e corrigir o problema
- No momento da escrita, o webernetes tem 204 testes de integração e 1.855 testes unitários
Por que revisão e testes precisam ser usados juntos
- Código feito por LLM também precisa de bons testes e de bom código, assim como um PR feito por humanos
- A diferença em 2026 é que, com colegas humanos, ainda se podia esperar algum nível de qualidade, mas com LLM é mais seguro partir do pressuposto de que ela não fará um bom trabalho
- Se nem o código de teste for revisado, fica difícil saber com qual critério de sucesso a LLM está trabalhando
- Mesmo revisando todo o código, sem testes é difícil acreditar que um humano consiga inferir todas as possibilidades
- Como a LLM não se cansa e digita rápido, é útil fazê-la sugerir edge cases que a pessoa não pensou e, se fizerem sentido, pedir que ela escreva testes para eles
- A combinação entre o gosto e a compreensão humana com a capacidade rápida de escrita da LLM foi vista como a maior mudança desde o início da carreira do autor, em 2012
Escala do projeto e uso de tokens
- O primeiro commit entrou no repositório webernetes atual em 21 de abril
- Parte do trabalho inicial foi feita em um branch do repositório por trás deste site de blog, então o gráfico não representa toda a realidade com perfeição
- O gráfico de linhas de código mostra 126.642 linhas na semana de 15 de junho
- As cerca de 100 mil linhas mencionadas no começo excluem código que não é TypeScript, comentários e o demo app
- O total de linhas por semana cresceu da seguinte forma
- semana de 20 de abril: 11.640 linhas
- semana de 27 de abril: 20.660 linhas
- semana de 4 de maio: 25.048 linhas
- semana de 11 de maio: 30.417 linhas
- semana de 18 de maio: 42.301 linhas
- semana de 25 de maio: 54.155 linhas
- semana de 1º de junho: 79.704 linhas
- semana de 8 de junho: 98.532 linhas
- semana de 15 de junho: 126.642 linhas
- No uso de tokens das sessões de Codex e Claude, os cached input tokens foram muito maiores que os demais, especialmente quando janelas de contexto longas eram preenchidas com frequência
- Na semana de 15 de junho, foram usados 104.155.857 uncached input tokens, 2.196.467.968 cached input tokens e 6.420.826 output tokens
A disparada da última semana e o custo
- Na última semana, a tentativa de adicionar suporte a Deployments no demo app acabou dando mais trabalho do que o esperado
- A primeira tentativa de portabilidade da LLM deixou de fora muitas funcionalidades dos componentes necessários
- Depois disso, vários agentes foram usados para identificar a cadeia de dependências, portar cada componente com mais subagentes e fazer revisões com outros subagentes
- Essa abordagem concluiu o trabalho mais rápido do que seria manualmente, mas foi muito ineficiente em termos de tokens, e no fim ainda exigiu revisão manual
- O custo equivalente em API dos tokens de LLM subiu semana a semana e chegou a $1.811,64 na semana de 15 de junho
- Em todo o projeto, o tempo do autor continuou sendo o item mais caro até o fim
Materiais finais e como participar
- Também existe uma série de vídeos registrando o processo de criação
- Nos vídeos, também dá para ver o otimismo equivocado do início e a forma de trabalho quase totalmente hands-free, com controle por voz e rastreamento ocular
- O autor pede para experimentarem o projeto e abrirem issues, ou entrarem em contato por
s.rose@ngrok.comse tiverem criado algo ou encontrado algum bloqueio
1 comentários
Opiniões no Hacker News
Por exemplo, eu criei isto: https://kubernetes-made-simple.vercel.app/ — agora acho que dá para adicionar isso lá
Ainda assim, o site é legal
Seria interessante expandir mais o Gateway e, se possível, mencionar também CRD
Se você tivesse que apontar uma coisa que a maioria das pessoas entende errado sobre k8s e que torna o aprendizado desnecessariamente difícil, qual seria?
Pelo que lembro, no começo usávamos Katacoda e depois outra plataforma parecida; ela subia na hora uma nova instância com uma configuração específica para cada usuário, o que era muito útil
Mas agora isso parece mais adequado para ensinar conceitos ou arquitetura. A diversão de verdade começa quando você passa a dominar o kubectl
Outras plataformas parecidas parecem ter desaparecido porque ninguém mais bancava os custos, o que é uma pena
Espero que isto vire uma alternativa. Há o risco de ficar desatualizado ao divergir da realidade, mas ainda assim o essencial quase sempre continuará válido
Parece a forma correta de encarar a engenharia assistida por LLMs. A IA consegue gerar uma quantidade surpreendente de código, mas o valor real está na disciplina de revisão e nos testes em torno disso
O ângulo de rodar Kubernetes no navegador também é legal, mas o mais interessante é o workflow, especialmente a parte de testar o comportamento contra k8s em vez de confiar em “parece plausível”. Fico curioso para saber quantas equipes já fazem esse nível de validação em código escrito por IA, e talvez seja para onde todo mundo vá nos próximos anos
Infelizmente, nem toda tarefa de programação tem essa oportunidade
https://youtu.be/t7L2iROVaRg?is=xoV4aiCXcYMVvVDL
A complexidade adicional ou a perda de desempenho precisariam de alguma justificativa, mas em alguns casos de uso parece que pode compensar bem
É parecido com a distinção de Fred Brooks entre complexidade essencial e complexidade acidental
Claro que, se você usa kube para algo que poderia ser feito de forma mais simples, kube rapidamente vira complexidade acidental
Fazendo uma analogia: se alguém porta DOOM para o navegador, isso significa que agora você pode jogar no navegador. Mas os bancos de dados que aparecem nas abas não podem realmente ser executados no navegador, certo?
Se eu abrir ruby2d, não dá para dizer de repente que há suporte a Ruby no lado do cliente. Para rodar de fato em uma aba do navegador, é preciso todo tipo de trabalho customizado
Por outro lado, um serviço de contêiner backend comum realmente pode ser movido para vários lugares e executado em qualquer ambiente
Então não entendi bem o ponto; se eu estiver errado, me corrijam. Também não parece bater com a própria afirmação
Ele não executa imagens de contêiner reais. Talvez fosse melhor chamá-lo de “Kubernetes simulado”
O que foi portado é o plano de controle. O scheduler, kube-proxy, deployment controller etc. foram migrados a partir do código-fonte real em Go, e usam a mesma API de cliente para testar a equivalência de comportamento com o k3s. A “renderização” é o app de demonstração que visualiza requisições entre Pods como pontos em movimento
Foi divertido