This article explores the motivations and challenges behind development of the CEL Playground with WebAssembly.

Software Engineer
Matheus Faria

Introdução
Em postagens recentes no blog, discutimos sobre ValidatingAdmissionPolicy, a nova API do Kubernetes para aplicação de políticas, e apresentamos o CEL Playground, um ambiente web que desenvolvemos para testar rapidamente a linguagem Common Expression Language (CEL).
Você pode acessar os artigos anteriores para obter mais informações:
Este artigo explora as motivações e os desafios por trás do desenvolvimento do CEL Playground com WebAssembly.
Motivação
Houve dois principais fatores motivadores que levaram ao desenvolvimento do CEL Playground. O primeiro foi a necessidade de um ambiente interativo para testar e experimentar o CEL, e o segundo é a crescente popularidade do CEL, especialmente depois que foi adotado e se tornou parte do ecossistema do Kubernetes.
Necessidade
Quando começamos a adotar o CEL para as verificações do Marvin, e também porque ele já era usado no Kubernetes na API ValidatingAdmissionPolicy, pudemos perceber que havia uma falta de um ambiente onde as expressões CEL pudessem ser facilmente testadas e experimentadas. Linguagens de propósito semelhante, como Rego e CUE, já possuíam playgrounds web para essa finalidade.
Um playground simplifica o teste e a experimentação com uma linguagem, pois não requer instalações ou configurações prévias. Os usuários podem escrever e executar expressões diretamente de seus navegadores, inspirar-se em exemplos pré-existentes e também compartilhar seus experimentos.
Popularidade
Como mencionado anteriormente, outra motivação significativa para a criação do CEL Playground foi a crescente popularidade do CEL, especialmente após ser adotado pelo Kubernetes, uma das plataformas de tecnologia mais influentes e amplamente utilizadas, contendo um vasto ecossistema.
O CEL é usado nas APIs do Kubernetes para declarar regras de validação, regras de políticas e outras restrições ou condições. Um dos objetivos do Kubernetes é fornecer essa funcionalidade como uma biblioteca para que outros projetos possam executar as mesmas expressões CEL que o API Server (o componente do Kubernetes responsável por isso).
Já é possível observar novos projetos, como o Marvin e o Kyverno, que adotaram o CEL.
Como o CEL Playground funciona?
Uma das principais preocupações durante o desenvolvimento do CEL Playground era evitar custos com servidores, e é aí que o WebAssembly (WASM) desempenhou um papel crucial, permitindo a execução de código Go diretamente no navegador. Como resultado, as expressões CEL são executadas usando o cel-go.
Sempre que o botão Run é clicado, a função JavaScript run() é chamada. Esta função chama outra função JavaScript eval(exp, data) fornecendo a expressão CEL e os dados de entrada como argumentos.
Observe que você pode inspecionar e ler o código-fonte da função run(). No entanto, não consegue ver a função eval(exp, data) porque ela faz parte do binário WASM, que não é visível diretamente no navegador.

Ao carregar o CEL Playground, um arquivo binário WASM é carregado e executado, com a ajuda do arquivo de suporte JavaScript do Go SDK: $(go env GOROOT)/misc/wasm/wasm_exec.js.
Em sua essência, trata-se de um programa em Go que está em execução desde que o binário WASM foi compilado com o Go.
O programa Go define a função JavaScript eval(exp, data) e continua rodando. Dessa forma, a função permanece disponível para ser acionada quando o botão Run é clicado (através da função run() mostrada acima).
A função evalWrapper, como o nome sugere, é um wrapper que permite executar uma expressão CEL dentro do contexto de um ambiente JavaScript/WASM. Para mais detalhes, verifique o repositório no GitHub.
Por fim, o comando abaixo é usado para compilar um programa Go em WebAssembly.
Tamanho do binário WASM
De acordo com a documentação do Go, atualmente, arquivos WASM grandes são gerados pelo Go, com o menor tamanho possível em torno de ~2MB. Esse tamanho pode aumentar drasticamente ao importar bibliotecas, sendo comuns tamanhos de mais de 10MB.
No caso do CEL Playground, o tamanho do binário WASM chegou a impressionantes 70MB.
Uma das maneiras recomendadas para reduzir o tamanho do arquivo WASM é usar o TinyGo para a compilação.
No entanto, não tivemos sucesso ao tentar usar o TinyGo com duas versões diferentes.
A primeira tentativa foi com a versão v0.27.0, e o problema foi com o uso do pacote reflect pelo cel-go:
A versão v0.28.0 melhorou o suporte ao pacote reflect e resolveu o problema que tivemos na versão anterior.
Mas desta vez, enfrentamos um problema diferente:
A dependência indireta k8s.io/utils utiliza o pacote net da biblioteca padrão, que não está disponível no TinyGo. Esse módulo é importado indiretamente devido a algumas bibliotecas CEL do Kubernetes disponíveis no Playground.
Considerando que este código não é utilizado, tentamos criar um fork, remover o código desnecessário e utilizar o replace no go.mod. No entanto, ainda enfrentamos problemas com dependências indiretas do Kubernetes:
Quando comentamos o código que importa as bibliotecas CEL do Kubernetes, foi possível compilar com o TinyGO, resultando em um binário de apenas 1.6MB.
Neste ponto, enfrentamos um dilema: manter as bibliotecas CEL do Kubernetes disponíveis no playground ou carregar um binário (muito) menor?
A decisão não foi difícil e escolhemos a primeira opção, permitindo que os usuários testem no Playground as mesmas expressões que são usadas nas APIs do Kubernetes.
Você pode encontrar os testes com o TinyGo no repositório do GitHub na ramo tinygo.
Se você tiver alguma sugestão quanto ao desafio de reduzir o tamanho do binário e/ou usar o TinyGo, sinta-se à vontade para abrir uma issue.
Embora o uso do TinyGo não tenha sido possível, outras ações foram tomadas para reduzir o tamanho do binário.
Conseguimos obter um arquivo de 10.8MB compactando o binário com gzip e usando algumas ldflags no comando de build:
Por fim, o front-end teve que ser adaptado para descompactar o arquivo antes de instanciar o WASM, o que foi feito usando a biblioteca pako.
Compartilhando Experimentos
Compartilhar experimentos é um recurso útil e comum em playgrounds web.
A primeira versão do CEL Playground não tinha essa opção. Mas foi, na verdade, a primeira sugestão de melhoria que surgiu juntamente com o desafio de evitar custos com servidores.
Muitos playgrounds salvam experimentos para serem compartilhados no lado do servidor. Como nosso objetivo é manter a aplicação estática, a primeira ideia que testamos foi codificar as informações a serem compartilhadas em base64 e colocá-las na URL. Isso funcionou muito bem.
Também adicionamos compactação com gzip para encurtar o tamanho da URL. Não encontramos informações claras sobre o limite de tamanho de URLs nos navegadores. Por isso, o CEL Playground não o limita.
Conclusão
O objetivo deste artigo foi compartilhar as experiências e desafios que enfrentamos no desenvolvimento do CEL Playground com WebAssembly e Go. Também queríamos compartilhar um pouco sobre as motivações por trás e que levaram à criação deste projeto.
Esperamos que este conteúdo contribua de alguma forma com a comunidade. O código-fonte do projeto está disponível no GitHub, e qualquer contribuição é muito bem-vinda.
Além disso, não deixe de visitar nossos outros projetos de código aberto para Kubernetes: Zora e Marvin.
Newsletter Getup.
Atualizações sobre Kubernetes e Software Supply Chain Security todos os meses.
Operating Kubernetes in production for more than 13 years. With Quor, this experience extends to software supply chain security as well.
GET UP
© Getup · 2026

