2 pontos por GN⁺ 2024-01-24 | 1 comentários | Compartilhar no WhatsApp
  • Em ambientes como o Kubernetes, onde o número de alvos de configuração cresce, a abordagem de simplesmente aumentar a quantidade de arquivos YAML logo atinge seu limite, e uma abordagem de gerar dados de configuração passa a ser mais adequada do que usar templates de YAML
  • Helm chart injeta valores com values.yaml e templates Go, mas no momento em que entram em cena campos opcionais, arrays e mapas, o peso de condicionais e indentação aumenta bastante
  • O YAML tem regras rígidas de espaços em branco, mas o parser de templates do Helm não entende a estrutura do YAML, então a combinação de toYaml e indent facilmente leva a uma geração frágil de configuração
  • Como YAML é um superconjunto de JSON, a conversão entre os dois é simples, e o Jsonnet lida com geração de objetos de configuração como código, usando variáveis externas, campos condicionais, combinação de mapas e mesclagem de objetos
  • O kr8 usa um fluxo baseado em Jsonnet para criar e manipular configurações de vários clusters Kubernetes, optando por gerar e transformar objetos diretamente em vez de montar strings YAML complexas

A complexidade da configuração começa quando o número de arquivos YAML aumenta

  • Quando aplicações e infraestrutura passam de uma certa escala, a complexidade da configuração cresce rapidamente
  • Se há apenas 1 ou 2 alvos de deploy, escrever arquivos de configuração YAML manualmente ainda pode ser suficiente, mas quando isso aumenta, é preciso gerenciar a configuração de forma sistemática
  • O motivo de precisar de vários arquivos de configuração normalmente é que, mesmo para o mesmo alvo, alguns valores diferem entre si
    • Deploy por ambiente como dev, stg, prod
    • Deploy por região como Europa, América do Norte
  • Nem toda configuração é diferente, mas se as diferenças forem grandes o bastante, é preciso separar e gerenciar em comum o que é compartilhado e o que muda
  • A área de gerenciamento de configuração lida com esse tipo de problema há muito tempo, e várias ferramentas vêm usando YAML à sua maneira
  • O hiera, incluído no Puppet, permite consultar variáveis de forma hierárquica, sendo poderoso e flexível, e reduz bastante a necessidade de fazer templates do próprio YAML

Os problemas de templates de YAML que aparecem em Helm chart

  • Com computação em nuvem e Kubernetes, os alvos de configuração se expandiram para camadas acima do sistema operacional, e surgiram ferramentas como CloudFormation e Helm
  • Helm chart pode receber parâmetros externos definidos em values.yaml para renderização
  • Valores simples em forma de string são relativamente fáceis
image: "{{ .Values.image }}"
  • Se você definir o valor de image em values.yaml, esse valor entra no template
  • Os problemas crescem quando se começa a lidar com configurações mais complexas, como campos opcionais
{{- with .resourceGroup  }}
    resourceGroup: {{ .  }}
{{- end }}
  • Como valores opcionais não podem simplesmente ser deixados em branco, são necessários condicionais e loops, e o template fica facilmente confuso
  • Ao inserir arrays ou mapas, é preciso combinar toYaml com indent
{{- with .Values.podAnnotations  }}
      annotations:
{{ toYaml . | indent 8  }}
{{- end  }}
  • A chamada de função que converte YAML em YAML de novo com toYaml já soa estranha, mas o problema maior é o tratamento de espaços em branco

O choque entre as regras de espaços do YAML e o mecanismo de templates

  • O YAML tem regras rígidas de indentação e espaços em branco
  • O exemplo abaixo não é um YAML válido ou completo
something: nothing
  hello: goodbye
  • Se uma pessoa estiver escrevendo isso manualmente, pode corrigir apertando backspace algumas vezes, mas ao gerar YAML com um sistema de templates isso não é tão simples
  • Quando o número de arquivos de configuração passa de 5 a 10, torna-se necessário gerar configuração em vez de escrever tudo manualmente
  • Para colocar o valor de .Values.podAnnotations sob annotations, que já está indentado, o próprio valor também precisa estar indentado exatamente no nível correto
  • Como o parser de templates Go não entende YAML, problemas aparecem mesmo quando se tenta indentar a sintaxe do template para deixá-la visualmente mais bonita
{{- with .Values.podAnnotations }}
      annotations:
      {{ toYaml . | indent 6 }}
{{- end  }}
  • Quando um sistema de templates lida com espaços e condicionais sem conhecer a estrutura do YAML, gerar configurações complexas vai ficando cada vez mais difícil
  • Escrever JSON diretamente também não é uma boa opção por causa da ausência de comentários e de problemas como esquecer vírgulas, e foi justamente por esse desconforto que o YAML passou a ser usado

Jsonnet é uma linguagem de templates de dados para gerar configuração JSON

  • Como YAML é um superconjunto de JSON, a conversão entre JSON e YAML é simples
  • Várias aplicações e linguagens de programação conseguem fazer parsing ou conversão de JSON e YAML nativamente
  • Em Python também é possível ler YAML e imprimir JSON
python -c 'import json, sys, yaml ; y=yaml.safe_load(sys.stdin.read()) ; print(json.dumps(y))'
  • O Jsonnet se define como uma linguagem de templates de dados, e seu objetivo central é gerar configuração JSON
  • O contexto de design do Jsonnet pode ser visto no design rationale

Variáveis externas e tratamento de campos opcionais

  • O Jsonnet pode usar variáveis externas para injetar valores de configuração
{

  image: std.extVar('image'),

}
  • Ao passar uma variável externa pela CLI, é gerado o resultado em JSON
jsonnet image.jsonnet -V image="my-image"
{
   "image": "my-image"
}
  • Campos opcionais podem ser expressos como condições no código, sem enfiar condicionais de template dentro de strings
// define a variable - yes, jsonnet also has comments
local rg = null;
{

  image: std.extVar('image'),
  // if the variable is null, this will be blank
  [if rg != null then 'resourceGroup']: rg,

}
  • Se rg for null, o campo resourceGroup não será incluído no resultado
  • Se um valor for definido, esse campo será exibido

Manipular mapas e objetos é mais simples do que lidar com indentação em YAML

  • Quando se coloca um mapa na configuração, como no caso de anotações de pod no Kubernetes, no Jsonnet é possível definir o valor como uma variável e depois posicioná-lo no objeto
local annotations = {
  'nginx.ingress.kubernetes.io/app-root': '/',
  'nginx.ingress.kubernetes.io/enable-cors': true,
};

{
  metadata: { // annotations are nested under the metadata of a pod
    annotations: annotations,
  },

}
  • Essa abordagem é muito mais simples do que tentar acertar a indentação em templates YAML
  • O resultado gerado é um objeto JSON com o mapa de anotações dentro de metadata.annotations
{
   "metadata": {
      "annotations": {
         "nginx.ingress.kubernetes.io/app-root": "/",
         "nginx.ingress.kubernetes.io/enable-cors": true
      }
   }
}
  • Em Jsonnet, a tarefa de adicionar anotações a um objeto existente também pode ser feita com o operador +
local annotations = {
  'nginx.ingress.kubernetes.io/app-root': '/',
  'nginx.ingress.kubernetes.io/enable-cors': true,
};

{
  metadata: {
    annotations: annotations,
  },
} + { // this adds another JSON object
  metadata+: { // I'm using the + operator, so we'll append to the existing metadata
    annotations+: { // same as above
      something: 'nothing',
    },
  },
}
  • No objeto resultante, something: "nothing" é adicionado às anotações existentes
{
   "metadata": {
      "annotations": {
         "nginx.ingress.kubernetes.io/app-root": "/",
         "nginx.ingress.kubernetes.io/enable-cors": true,
         "something": "nothing"
      }
   }
}
  • Em exemplos simples, o código pode até parecer mais longo, mas conforme a configuração fica mais complexa, essa forma de manipular objetos se torna útil

O kr8 lida com configurações de Kubernetes no estilo Jsonnet

  • O kr8 usa esses métodos para criar e manipular de forma fácil e simples as configurações de vários clusters Kubernetes
  • O fluxo central é, em vez de montar templates YAML com espaços e condicionais, gerar objetos de configuração JSON e transformá-los da maneira necessária

1 comentários

 
GN⁺ 2024-01-24
Comentários do Hacker News
  • Já estou completamente de saco cheio de configurações escritas em YAML. É a parte que mais odeio no GitHub Actions, e é pior até do que questões de confiabilidade
    Quando vejo uma ferramenta legal exigindo um arquivo YAML para configuração, já fico apreensivo na hora. O mesmo vale para linguagens proprietárias de configuração como o HCL do Terraform e o ASL do AWS Step Functions
    Não tem problema querer uma API declarativa, mas eu queria que ela permitisse gerar essa declaração por meio de programação. Configurações declaradas e geradas em código sempre foram uma experiência muito melhor, e o AWS CDK fez isso muito bem
    Você pode definir a infraestrutura de nuvem em uma linguagem com segurança de tipos e bom suporte de IDE, sem depender de um plugin que não recebe atualização há 2 anos

    • A esta altura, sinto que JSON puro é melhor do que YAML. A gota d’água para mim foi que o deno fmt tem formatador de JSON, mas não tem formatador de YAML
      O formatador de JSON é um binário único que roda em milissegundos, enquanto a autoformatação de YAML na prática exige usar o Prettier, e o Prettier depende de metade do NPM e leva uns 2 segundos para iniciar e rodar
      Então converti para JSON todos os arquivos YAML do repositório da empresa que podiam ser trocados, e pelo menos eu estou muito mais satisfeito. Ninguém reclamou
      Vários editores também suportam a tag $schema do JSON. Adicionei esse recurso ao produto, e é ótimo poder criar arquivos de configuração só apertando Tab, sem precisar ler a documentação
      YAML também consegue isso com o YAML language server, mas como a tecla Tab também é necessária para indentação, a usabilidade fica ruim. JSON também não é perfeito, mas pelo menos o texto "no" não vira verdadeiro
    • Ouço muito que a vantagem de usar YAML é que o JSON não tem comentários, mas não entendo por que seria preciso mudar para uma linguagem completamente diferente
      Não daria para só colocar um filtro que removesse os comentários antes de ler a configuração? Não parece que isso seria mais difícil do que trocar tudo para YAML
      Também não entendo muito bem a ideia de que YAML é mais fácil de ler. A dor de lidar com configuração não vem de economizar alguns segundos ao interpretar chaves e colchetes, mas sim da dificuldade de descobrir o que está errado por causa de um espaço ou tab faltando em meio a centenas de linhas de configuração
    • O GitHub Actions teria sido ruim independentemente da linguagem de configuração. O problema é tentar descrever um programa como uma estrutura de dados
      O Ansible comete o mesmo erro, e inúmeras outras ferramentas também
    • Penso algo parecido desde a época do AWS CloudFormation. Há 4 anos, criei um gerador de CloudFormation experimental que gerava todos os recursos e type hints em Python a partir do arquivo JSON que a AWS publica, e funcionava bem até: https://github.com/weberc2/nimbus/blob/master/examples/src/n...
      Não sei ao certo se o CDK funciona dessa forma. Quando mexi um pouco nele, pareceu bem diferente da experiência de “gerar CloudFormation” que eu tinha criado, e acabei não entendendo direito qual era a grande vantagem do CDK
      Parecia trocar o problema de YAML/templates por um problema de herança/mágica. Gostaria de ouvir mais experiências de quem já usou AWS CDK, Terraform CDK e Pulumi
    • No GitHub Actions, é ainda mais doloroso porque ele não suporta âncoras YAML. Isso ao menos teria fornecido um nível mínimo de composição, o que faz falta
      https://github.com/actions/runner/issues/1182
  • Concordo que templates YAML são uma ideia meio maluca, mas nunca entendi por que não paramos de usar linguagens falsas e passamos a usar uma linguagem de programação de verdade
    Se você precisa de lógica complexa, basta gerar YAML/JSON/o que for com uma linguagem de programação. Ruby, Python ou qualquer outra já oferecem o que é necessário sem precisar de pseudolinguagens esquisitas como Jsonnet ou templates Go
    Basta escrever código, e você sofre muito menos com problemas estranhos e opacos de engines de template. Qualquer linguagem de verdade fica muito melhor

    • Já fui responsável por gerenciar playbooks do Ansible executados periodicamente para bootstrap e aplicação de patches em uma quantidade enorme de servidores
      Já usei Chef em trabalhos parecidos, e era bom por ser Ruby, então dava para definir facilmente a lógica desejada e usar loops e variáveis de verdade
      Entendo que o Ansible foi projetado para não programadores, mas para alguém acostumado ao básico de programação, não há inferno pior do que enfiar playbooks do Ansible cheios de condicionais e repetições dentro da sintaxe verbosa dos templates Jinja
    • Nas stacks atuais, a arquitetura de embutir uma linguagem parece quase esquecida. Antigamente, se um aplicativo fosse complexo o suficiente, o núcleo era feito em C/C++/Java etc., e, se fosse necessário scripting, embutia-se algo como LISP ou Lua por cima
      Hoje, porém, o normal é pegar um parser de JSON/TOML/YAML e criar uma função readConfig, inclusive em casos em que um interpretador embutido seria mais adequado
      Do ponto de vista do desenvolvedor, é mais fácil adicionar complexidade ao formato de configuração do que oferecer uma incorporação completa de linguagem e bindings da aplicação. Então parece que esqueceram esse caminho, ou nem consideram que ele seja possível
    • O Pulumi é atraente porque permite escrever na linguagem que você preferir e abandonar o HCL, mas pessoalmente acho claramente pior. Infraestrutura como código deveria ser declarativa para aumentar previsibilidade, reprodutibilidade e facilidade de manutenção
      Na época de Chef/Puppet, muitos lugares começaram a colocar lógica em IaC e isso virou uma bagunça gigantesca impossível de atualizar ou manter. O modelo Chef/Pulumi também funciona, mas exige alguém muito rigoroso com estilo e manutenção
      Para equipes grandes e manutenção de longo prazo, acho o modelo Terraform/Puppet melhor. HCL é irritante e usar Python/TypeScript etc. dá uma sensação de liberdade, mas código puramente declarativo evita muito espaguete
    • O problema é que fanáticos por linguagens fazem linguagens para outros fanáticos por linguagens
      Eles querem colocar os elementos de design de linguagem que estão na moda, querem self-hosting e também querem que dê para escrever um servidor web multithread rápido, então tudo fica conceitualmente complexo
      Precisamos de uma linguagem brinquedo simples, tipo Logo, para engenheiros de sistemas/DevOps. Originalmente ela deveria ser explicável em um livro do tamanho do K&R C
      Precisaria de tipagem dinâmica, estruturas de controle que se aprendem em um fim de semana, sem threading nem concorrência, sem orientação a objetos nem herança, com design funcional/modular e um modelo de FFI que possa ser facilmente chamado e chamar outras linguagens e frameworks
      O problema é que os fanáticos por linguagens não conseguem se controlar e continuam adicionando recursos, e isso acaba entrando na biblioteca padrão e no guia de estilo, de modo que até iniciantes precisam aprender tudo
      Eu mesmo ficaria tentado a adicionar funções do tipo each/map a arrays/hash maps e incluir funções de primeira classe e closures, mas isso talvez fosse um erro. Já existem linguagens funcionais imutáveis para configuração, mas mais de 95% de quem usa YAML com templates não quer aprender a programar desse jeito, então é difícil isso se popularizar
    • Quero enfatizar a ideia de gerar arquivos de configuração. Limitar a configuração em si a uma forma que possa ir para um arquivo JSON e similares é muito útil
      Isso simplifica a configuração, facilita o consumo e também a documentação. Mas, ao escrever arquivos de configuração, deveria-se usar uma linguagem de programação e, de preferência, uma linguagem estaticamente tipada que ofereça verificação de erros, autocompletar e documentação inline
      O AWS CDK é um bom exemplo. Escrever CloudFormation puro é doloroso, mas o CDK não adiciona recursos de programação ao CloudFormation; ele gera CloudFormation. A entrada que a AWS consome continua sendo o CloudFormation relativamente simples e estável
  • Assim que vi o título, achei que seria sobre Kubernetes
    A API do Kubernetes é bastante intuitiva e tem um esquema JSON bem definido. A maior parte do tempo gasto aprendendo k8s deveria ser usada para entender como usar a API, mas na prática acaba sendo gasta para descobrir como usar charts do Helm
    Não acho que Jsonnet, Ksonnet, Nu e CUE tenham ficado tão populares assim. Parece que a maioria usa Kustomize, porque é relativamente intuitivo e vem embutido no kubectl
    A ferramenta ideal deveria oferecer ao autor das definições verificação de tipos com base no esquema do k8s, validação e alertas de descontinuação de versões, dar ao usuário um único artefato de saída fácil de inspecionar, falhar atomicamente se o cluster não oferecer suporte a algum objeto/versão e estar embutida na cadeia de ferramentas padrão
    Um script TypeScript para Bun ou Deno que exporte uma função que receba argumentos e retorne uma lista de definições provavelmente combinaria bem com algo como deno compile, mas falha no requisito de estar embutido na cadeia de ferramentas padrão

    • Esse é um padrão em todo o software. Em vez de aprender os elementos primitivos e fundamentos nos quais o sistema se baseia, aprende-se um monte de abstrações por cima porque dizem que é difícil demais
      Isso protege dos detalhes de baixo nível, mas quando algo dá errado você precisa lidar com uma enorme pilha de abstrações que dificulta diagnóstico e depuração
      Fica muito mais difícil descobrir o que realmente está acontecendo, e você acaba dependente da camada de abstração, assumindo também as atualizações que o fornecedor lançar e outros problemas no grafo de dependências
    • No nosso sistema usamos jsonnet e ele não tem absolutamente nada a ver com k8s. Mais do que uma ferramenta muito popular, é uma ferramenta de nicho para configurações complexas, e nem é muito divulgada
      Ela faz quase tudo de que precisamos sem problemas, é multiplataforma e pode ser usada em várias linguagens. Já a embuti em executáveis C++, .NET e JVM
      A configuração final em JSON pode ser usada com um conjunto enorme de ferramentas que é difícil encontrar em alternativas como toml/yaml/hocon/ini etc. Tentei usar HOCON em linguagens que não eram da JVM, mas sempre esbarrava em algum caso de borda
    • O segundo requisito provavelmente não atende, e o terceiro com certeza não atende: https://cdk8s.io/docs/latest/
    • A ideia de manter as coisas simples é boa, e para instalação também tento usar o máximo possível kustomize ou yaml puro
      Mas quando você realmente vai administrar um sistema grande, no fim não dá para evitar as vantagens dos templates
    • kustomize e especialmente helm são confusos demais, enquanto os arquivos YAML do Kubernetes são muito fáceis de escrever e entender
  • É engraçado ver como os desenvolvedores pensam tão pouco em como lidar direito com configuração
    Parece só um conjunto de chaves e valores armazenado em arquivo ou gerado por código, mas na verdade isso é tudo. É a própria programação
    Tudo é configuração, e todo argumento de função também é um tipo de configuração. Toda configuração em arquivo externo acaba virando argumento de função de algum jeito
    O problema é a representação em texto simples do código. Arquivos de configuração declarativos parecem bons porque você consegue ver tudo em um só lugar, mas quando a configuração vira programa fica difícil achar onde mudar as coisas
    Não seria um problema se o código rodasse em tempo real mostrando a representação da configuração final e permitindo rastrear como cada valor final foi gerado. Essa funcionalidade é bem simples, mas não existem sistemas projetados assim. Configuração é sempre algo pensado depois
    Expandindo essa ideia para a programação como um todo, você deveria conseguir ver todo o código que depende de um valor de configuração específico e todas as suas transformações
    Além disso, a maior parte das configurações é relacional/em grafo, então talvez fosse melhor mantê-la em um banco de dados central. Valores de configuração diferentes se relacionam entre si. Então a configuração deveria ser visualizada em um editor de banco de dados/grafo
    Quando se sai do texto puro, as coisas começam a ficar bem mais simples, mas as funcionalidades de linguagem mencionadas antes ainda seriam necessárias

    • Um cliente que fez algo parecido está realmente tentando com muito empenho. Eles têm arquivos de “configuração” com mais de 1500 linhas por produto, e usam isso para gerar desenhos técnicos e arquivos de produção
      As configurações estão tentando usar convenções de nomes para agrupar variáveis relacionadas
      Querem uma estrutura de dados realmente aninhada, provavelmente gostariam de migrar para JSON, mas os engenheiros não querem escrever código de jeito nenhum, então configuração como código é inviável. E também há as desvantagens mencionadas antes
      A próxima ideia é que deve haver uma forma melhor de visualizar e editar a configuração. Pensei em uma UI visual que permita explorar a representação do produto final, selecionar peças e ajustar parâmetros dessa forma
      Queria saber se essa direção faz sentido. Se não, gostaria de uma explicação um pouco melhor. O núcleo dessa aplicação é configuração
  • Pior ainda é que, em lugares como CI/CD, YAML quase vira uma linguagem de programação. E uma muito verbosa, nada intuitiva, com especificação ruim e diferente conforme o fornecedor

    • É quase a mesma coisa que repetir os erros do Java do começo dos anos 2010. Naquela época, era comum a aplicação inteira ficar colada por um enorme bloco de XML configurando injeção de dependência
      Havia DTD e validação de XML, mas com aquela característica familiar de falhar tarde e emitir mensagens de erro difíceis de interpretar
      Naquela época muita frustração era direcionada ao XML, mas ao ver o inferno do YAML em meados dos anos 2020, fica claro que o problema não era a linguagem de marcação em si
    • Exatamente. Nós usamos ytt[0], que é “uma versão levemente modificada da linguagem de programação Starlark, um dialeto de Python”
      Eu realmente detesto enfiar lógica em algum canto de um template YAML
      [0] https://tanzu.vmware.com/developer/guides/ytt-gs/
    • Em alguns ambientes que lidam com Kubernetes, o termo engenheiro de YAML é usado sem ironia
    • YAML é como a Bradford Pear dos formatos de serialização. No começo parece boa, mas conforme o projeto envelhece e o YAML cresce, ele desaba sob o próprio peso
    • O pior é que cada geração repete esse erro. Não sei se S-expressions são a resposta, mas o Terraform HCL nunca deveria ter sido criado
  • É realmente triste que o Helm tenha vencido. Trabalho com coisas open source relacionadas a k8s na empresa, e 100% dos usuários pedem que a gente crie charts do Helm, então no fim precisamos fazer isso.
    É miserável trabalhar com isso. O nome do arquivo é algo como foo.yaml, mas na prática não é YAML, então o editor não consegue ajudar. Você precisa passar todos os dados por indent 4 para acertar a identação do YAML
    O mais deprimente é ter que reexpor todos os recursos do Kubernetes do seu próprio jeito. Se alguém quiser adicionar deployment.spec.template.spec.fooBars, você precisa adicionar deploymentFooBars em values.yaml e conectar tudo. Isso se repete para cada recurso
    É realmente um caso de “o ruim é bom” dando errado. Eu também já fiz horrores como tentar implementar templates com sed -e s/$FOO/foo/g, e imagino que o Helm também tenha começado assim. O resultado é um desastre
    Pessoalmente, eu usava Kustomize desde antes de entrar no kubectl e sempre fiquei bastante satisfeito. Tem muitas esquisitices, mas pelo menos ele entende o significado dos objetos que gera e economiza tempo
    Jsonnet é muito melhor. Como parte do nosso app de k8s, também distribuímos um deployment do Envoy para roteamento de tráfego complexo, e a configuração do Envoy é verbosa, mas fácil de lidar com Jsonnet: https://github.com/pachyderm/pachyderm/blob/master/etc/gener...
    Estou considerando seriamente transpilar jsonnet para a linguagem de templates do Go e implementar tudo em Jsonnet. Pelo menos seria um pouco mais sustentável, e como helm install simplesmente funcionaria, ninguém perceberia
    Mas acho que o Helm vai ser o fim do Kubernetes. Se alguma ferramenta concorrente de alocação de computação/execução de contêineres aparecer com uma linguagem decente para configuração, todo mundo migra de um dia para o outro

    • Quando der vontade de usar sed -e s/$FOO/foo/g, vale a pena olhar uma solução um pouco mais padrão e melhor: envsubst
      Se o assunto for gerar templates ou modificar charts do Helm com jsonnet, o Tanka também pode ajudar: https://tanka.dev/helm
    • Quero acreditar nessa previsão de que o Helm vai ser o fim do Kubernetes
      Só que os lugares onde trabalhei ainda têm tanto medo de mudança que continuam usando tf/hcl e helm do mesmo jeito. Pelo menos em projetos pessoais dá para respirar um pouco
  • Acho que existe um problema aqui. Só não sei se o tipo de pessoa que escolhe YAML como linguagem de configuração vê isso como problema
    Existe um conflito direto entre representação de dados centrada em humanos e representação de dados centrada em máquinas. Máquinas gostam de algo parecido com Lisp, pessoas gostam de algo parecido com Python
    Quem quer manipular configuração do Kubernetes por computador provavelmente vai se irritar discretamente com o fato de o Kubernetes usar YAML. Mas a comunidade de Kubernetes parece ser majoritariamente do lado do YAML, então imagino que não se importem muito com o fato de que, quando entra lógica de programação, trabalhar com arquivos de configuração vira um pesadelo
    Essa situação é justamente o ponto fraco do YAML, e acho que as pessoas de k8s em geral são inteligentes o bastante para esperar algo assim
    A afirmação “YAML é um superconjunto de JSON”, não importa o que o autor da especificação escreva na documentação, não me parece verdadeira na prática. Se você convertesse toda a configuração YAML em JSON, o time de DevOps ficaria irritado
    Os dois formatos de dados podem ter a mesma capacidade de expressar significado, mas o mesmo vale para todas as linguagens que compilam para a mesma arquitetura de CPU. JSON e YAML são coisas distintas no trabalho real, e misturar os dois não é uma boa ideia

    • Ironicamente, se bem me lembro, os manifestos do k8s desde o começo eram pensados para serem gerados por máquina, não para serem escritos manualmente
      Claro que as pessoas acabaram escrevendo na mão, e quando isso ficou insuportável começaram a colocar templates por cima. Parece que as coisas sempre acabam seguindo esse caminho
      Texto escrito à mão não é substituído por texto serializado de configuração gerada por máquina; em vez disso, acaba sendo substituído por texto ainda escrito à mão, só que agora com templates por cima
    • A afirmação “YAML é um superconjunto de JSON” só quer dizer que todo documento JSON é um documento YAML válido. Não quer dizer que YAML seja igual a JSON
  • Meu princípio pessoal é que não se deve usar interpolação de strings para gerar código legível por máquina. Linguagens de template são apenas uma interpolação de strings sofisticada
    Já vimos as consequências de injeção de SQL e cross-site scripting. Enquanto continuarmos jogando texto arbitrário em interpretadores, esse tipo de coisa vai continuar acontecendo
    Por isso também acho que não se deve usar arquivos de template para gerar HTML
    Como alternativas a linguagens de template para HTML, existem o Haml do Ruby e o Pug do JavaScript. Essas linguagens oferecem uma forma definida de especificar a árvore completa de tags, atributos e nós de texto
    Se você não gosta da indentação significativa ao estilo Python, no JavaScript existe o JSX. As partes com aparência de HTML no JSX são compiladas em expressões createElement que constroem uma árvore de documento web, e essa árvore pode ser emitida como HTML se necessário
    Haml, Pug e JSX não são linguagens de template, mesmo podendo produzir HTML. Da mesma forma, JSON.stringify(myObj) não é uma linguagem de template para JSON
    Código legível por máquina deve, sempre que possível, ser gerado por ferramentas que entendam e aproveitem a estrutura conhecida da linguagem de destino

    • Dizer que Haml, Pug e JSX não são linguagens de template não faz sentido, a menos que se use essa definição pessoal de linguagem de template como “interpolação de strings sofisticada”
      Haml é um sistema de templates para evitar código inline em documentos web e deixar o HTML mais limpo, e Pug é um mecanismo de templates rico em recursos para Node.js
      Posso concordar que JSX, estritamente falando, não é uma linguagem de template
      No fim, todos eles compilam para HTML. Só que, em vez de interpolação de strings, são analisados em árvores sintáticas e renderizados em HTML com base em um entendimento interno de estruturas válidas
      Templates de YAML são interpolação de strings sofisticada, e não uma linguagem de template, ou pelo menos uma linguagem de template pessimamente implementada
    • Nem toda linguagem de template é uma linguagem de template de strings. Por exemplo, se você considera PHP uma linguagem de template para texto, pela mesma lógica XQuery é uma linguagem de template para XML
    • Esse é o cerne do problema. YAML e templates são apenas distrações. No fim das contas, tudo se resume ao fato de que strings são um tipo genérico demais e nós as usamos com preguiça
      Minha regra pessoal é que, sempre que um valor entra em uma string, ele deve ser codificado corretamente
      Escrevi sobre esse tema no passado: https://kevincox.ca/2022/02/08/escape-everything/
      Em resumo, toda string tem um formato a ser respeitado, seja HTML, SQL ou saída de terminal legível por humanos. Sempre que você coloca um valor em uma string, precisa codificá-lo corretamente para esse formato, mas quase nunca fazemos isso
  • Estamos migrando para cuelang [1]. Pessoalmente, acho o design melhor do que o do Jsonette
    O Kubernetes já tem reconciliação de estado, então nesta configuração só faltava a exclusão, mas agora isso pode ser resolvido com o recurso de prune [2]
    [1] https://cuelang.org/docs/integrations/k8s/
    [2] https://kubernetes.io/blog/2023/05/09/introducing-kubectl-ap...

    • Posso recomendar cuelang. Começamos a usar na empresa e é muito bom
      Algumas mensagens de erro são um pouco difíceis de interpretar, mas ele detecta tanta coisa de antemão que isso é aceitável. Agora, as poucas vezes em que preciso escrever yaml diretamente parecem incrivelmente tediosas em comparação
  • Nessas horas eu normalmente entro com um “você já ouviu falar do nosso salvador CUELang?”: https://cuelang.org/
    Ainda não é Turing-completo, mas é expressivo o suficiente para eliminar duplicação, permite definir schema e dados na mesma linguagem, no mesmo arquivo ou em arquivos separados, e também tem union types
    Ele pode gerar YAML ou JSON, e pode validar a si próprio ou arquivos YAML/JSON
    A maior desvantagem é que a implementação atual só existe em Go, então pode ser necessário usar subprocessos ou FFI

    • Temos um pipeline que aceita arquivos cuelang bem concisos
      Depois disso, ele cria arquivos JSON para cada aplicação, alguma ferramenta gera definições XML, essas definições são aplicadas a uma planilha XLS mantida pelos arquitetos, e dali sai o YAML aplicado aos charts Helm
      Os charts implantam o cliente k8s, e esse cliente interage com o cluster principal em JSON via API
      Demorou um pouco, mas estamos usando a melhor ferramenta para cada tarefa
    • Como ele se compara ao dhall?