2 puntos por GN⁺ 2024-01-24 | 1 comentarios | Compartir por WhatsApp
  • En entornos donde crecen los destinos de configuración, como Kubernetes, aumentar manualmente la cantidad de archivos YAML pronto llega a un límite, y se vuelve más adecuado un enfoque que genere datos de configuración en vez de usar plantillas YAML
  • Los Helm charts inyectan valores con values.yaml y plantillas de Go, pero en cuanto aparecen campos opcionales, arrays o maps, aumenta la carga de manejar condicionales e indentación
  • YAML tiene reglas estrictas de espacios, pero el parser de plantillas de Helm no entiende la estructura de YAML, por lo que la combinación de toYaml e indent puede derivar fácilmente en una generación de configuración frágil
  • YAML es un superconjunto de JSON, así que la conversión entre ambos es sencilla; Jsonnet trata la generación de objetos de configuración como código, con variables externas, campos condicionales, combinación de maps y merge de objetos
  • kr8 usa un flujo basado en Jsonnet para crear y manipular configuraciones de varios clústeres de Kubernetes, y elige generar y transformar objetos directamente en lugar de ensamblar strings YAML complejos

La complejidad de la configuración empieza cuando aumenta la cantidad de archivos YAML

  • Cuando las aplicaciones y la infraestructura superan cierta escala, la complejidad de la configuración crece rápidamente
  • Si los destinos de despliegue son 1 o 2, escribir archivos de configuración YAML directamente puede ser suficiente, pero si aumentan más allá de eso, hay que gestionar la configuración de forma sistemática
  • La razón por la que se necesitan varios archivos de configuración suele ser que, aun para el mismo destino, algunos valores difieren entre sí
    • Despliegues por entorno como dev, stg, prod
    • Despliegues por región como Europe o North America
  • No toda la configuración es distinta, pero si las diferencias son lo bastante grandes, hay que separar y gestionar las partes comunes y las partes diferentes
  • El campo de la gestión de configuración lleva mucho tiempo tratando estos problemas, y varias herramientas han usado YAML a su manera
  • hiera, incluido en Puppet, permite consultar variables de forma jerárquica, por lo que es potente y flexible, y reduce mucho la necesidad de usar plantillas sobre el propio YAML

Los problemas de las plantillas YAML que aparecen en Helm charts

  • Con el cloud computing y Kubernetes, los destinos de configuración se expandieron hasta capas por encima del sistema operativo, y surgieron herramientas como CloudFormation y Helm
  • Un Helm chart puede renderizarse recibiendo parámetros externos definidos en values.yaml
  • Los valores de string simples son relativamente sencillos
image: "{{ .Values.image }}"
  • Si se especifica el valor image en values.yaml, ese valor entra en la plantilla
  • El problema crece cuando se empiezan a manejar configuraciones más complejas, como campos opcionales
{{- with .resourceGroup  }}
    resourceGroup: {{ .  }}
{{- end }}
  • Como los valores opcionales no pueden dejarse vacíos, se necesitan condicionales y loops, y la plantilla se ensucia fácilmente
  • Al insertar arrays o maps, hay que combinar toYaml e indent
{{- with .Values.podAnnotations  }}
      annotations:
{{ toYaml . | indent 8  }}
{{- end  }}
  • La llamada a una función que vuelve a convertir YAML en YAML con toYaml ya resulta extraña, pero el problema mayor es el manejo de espacios

El choque entre las reglas de espacios de YAML y el motor de plantillas

  • YAML tiene reglas estrictas de indentación y espacios
  • El siguiente ejemplo no es YAML válido ni completo
something: nothing
  hello: goodbye
  • Si una persona lo escribiera directamente, podría corregirlo presionando Backspace algunas veces, pero al generar YAML con un sistema de plantillas no es tan simple
  • Si se supera el nivel de 5 a 10 archivos de configuración, se vuelve necesaria la generación de configuración en vez de escribirlos directamente
  • Para poner el valor de .Values.podAnnotations debajo de annotations, que ya está indentado, el propio valor también debe indentarse al nivel exacto
  • Como el parser de plantillas de Go no entiende YAML, surgen problemas incluso al intentar indentar la sintaxis de la plantilla para que sea legible
{{- with .Values.podAnnotations }}
      annotations:
      {{ toYaml . | indent 6 }}
{{- end  }}
  • Cuando un sistema de plantillas maneja espacios y condicionales sin conocer la estructura de YAML, generar configuraciones complejas se vuelve cada vez más difícil
  • Escribir JSON directamente tampoco es adecuado por la ausencia de comentarios y los problemas de comas faltantes; por estas incomodidades se terminó usando YAML

Jsonnet es un lenguaje de plantillas de datos para generar configuración JSON

  • YAML es un superconjunto de JSON, así que la conversión entre JSON y YAML es simple
  • Muchas aplicaciones y lenguajes de programación pueden parsear o convertir JSON y YAML de forma nativa
  • En Python también se puede leer YAML y emitir JSON
python -c 'import json, sys, yaml ; y=yaml.safe_load(sys.stdin.read()) ; print(json.dumps(y))'
  • Jsonnet se define a sí mismo como un lenguaje de plantillas de datos, y su objetivo principal es generar configuración JSON
  • El contexto de diseño de Jsonnet se puede consultar en su design rationale

Variables externas y manejo de campos opcionales

  • Jsonnet puede inyectar valores de configuración usando variables externas
{

  image: std.extVar('image'),

}
  • Si se pasan variables externas desde la CLI, se genera el resultado JSON
jsonnet image.jsonnet -V image="my-image"
{
   "image": "my-image"
}
  • Los campos opcionales pueden expresarse como condiciones de código, sin insertar condicionales de plantilla 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,

}
  • Si rg es null, el campo resourceGroup no se incluye en el resultado
  • Si se especifica un valor, ese campo se emite

Manipular maps y objetos es más simple que lidiar con la indentación YAML

  • En casos donde se inserta un map en la configuración, como una annotation de un pod de Kubernetes, en Jsonnet se puede definir el valor como variable y ubicarlo dentro del 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,
  },

}
  • Este enfoque es mucho más simple que ajustar la indentación en una plantilla YAML
  • El resultado generado es un objeto JSON con el map de annotations debajo de metadata.annotations
{
   "metadata": {
      "annotations": {
         "nginx.ingress.kubernetes.io/app-root": "/",
         "nginx.ingress.kubernetes.io/enable-cors": true
      }
   }
}
  • Agregar annotations a un objeto existente también puede manejarse en Jsonnet con el 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',
    },
  },
}
  • En el objeto resultante se agrega something: "nothing" a las annotations existentes
{
   "metadata": {
      "annotations": {
         "nginx.ingress.kubernetes.io/app-root": "/",
         "nginx.ingress.kubernetes.io/enable-cors": true,
         "something": "nothing"
      }
   }
}
  • En ejemplos simples, el código puede parecer más largo, pero a medida que la configuración se vuelve más compleja, la capacidad de manipular objetos de esta manera se vuelve útil

kr8 maneja la configuración de Kubernetes al estilo Jsonnet

  • kr8 usa estos métodos para crear y manipular de forma fácil y simple la configuración de varios clústeres de Kubernetes
  • El flujo central consiste en generar objetos de configuración JSON y transformarlos de la manera necesaria, en lugar de ensamblar plantillas YAML con espacios y condicionales

1 comentarios

 
GN⁺ 2024-01-24
Comentarios de Hacker News
  • Ya estoy completamente harto de la configuración escrita en YAML. Es la parte que más odio de GitHub Actions, y es peor que solo un problema de confiabilidad
    Cuando veo que una herramienta interesante exige archivos YAML para configurarse, de inmediato me da mala espina. Me pasa lo mismo con lenguajes de configuración propietarios como HCL de Terraform o ASL de AWS Step Functions
    Está bien querer una API declarativa, pero ojalá permitieran generar esa declaración con un programa. La configuración declarada y generada con código me ha dado una experiencia mucho mejor, y AWS CDK hizo esto realmente bien
    Puedes definir infraestructura en la nube con un lenguaje con seguridad de tipos y buen soporte de IDE, sin depender de plugins que no se actualizan desde hace 2 años

    • A estas alturas siento que JSON puro es mejor que YAML. Lo decisivo fue que deno fmt tiene formateador para JSON, pero no para YAML
      El formateador de JSON es un solo binario que corre en milisegundos, mientras que para autoformatear YAML en la práctica hay que usar Prettier, y Prettier depende de media NPM y tarda como 2 segundos en arrancar y ejecutarse
      Por eso, en el repositorio de la empresa pasé a JSON todos los archivos YAML que se podían convertir, y al menos yo estoy mucho más satisfecho. Nadie se quejó
      Varios editores también soportan la etiqueta $schema de JSON. Le agregué esta función al producto y quedó muy bien poder crear archivos de configuración solo presionando tab, sin leer la documentación
      En YAML también se puede con el YAML language server, pero como la tecla tab también se necesita para la indentación, la experiencia de uso no es muy buena. JSON tampoco es perfecto, pero al menos el texto "no" no significa verdadero
    • A menudo escucho que la ventaja de usar YAML es que JSON no tiene comentarios, pero no entiendo por qué habría que cambiarse a un lenguaje completamente distinto
      ¿No bastaría con poner un filtro que elimine los comentarios antes de leer la configuración? No puede ser más difícil que convertirlo todo a YAML
      Tampoco entiendo mucho eso de que YAML es más fácil de leer. El dolor de trabajar con configuración no viene de ahorrarse unos segundos al interpretar llaves y corchetes, sino de lo difícil que es saber qué salió mal dentro de cientos de líneas por culpa de un espacio o tabulación faltante
    • GitHub Actions habría sido malo sin importar con qué se configurara. Porque está intentando describir un programa como una estructura de datos
      Ansible comete el mismo error, y muchísimas herramientas también
    • Pienso algo parecido desde la época de AWS CloudFormation. Hace 4 años hice un generador de CloudFormation experimental que tomaba los archivos JSON que AWS publicaba y generaba todos los recursos y type hints de Python, y funcionaba bastante bien: https://github.com/weberc2/nimbus/blob/master/examples/src/n...
      No sé bien si CDK funciona de esa manera. Cuando lo probé un poco, se sintió bastante distinto de la experiencia de “generar CloudFormation” que yo había hecho, y no terminé de captar bien las ventajas de CDK
      Se sentía como cambiar el problema de YAML/plantillas por un problema de herencia/magia. Me gustaría escuchar más experiencias de gente que haya usado AWS CDK, Terraform CDK o Pulumi
    • En GitHub Actions es aún más doloroso porque no soporta YAML anchors. Eso al menos habría dado un mínimo de composabilidad, y se echa de menos
      https://github.com/actions/runner/issues/1182
  • Aunque estoy de acuerdo en que las plantillas YAML son una locura bastante grande, nunca he entendido por qué no dejan de usar lenguajes falsos y usan lenguajes de programación de verdad
    Si necesitas lógica compleja, simplemente puedes generar YAML/JSON/lo que sea con un lenguaje de programación. Ruby, Python o cualquier otro lenguaje te da lo que necesitas sin seudolenguajes raros como Jsonnet o las plantillas de Go
    Si solo escribes código, te metes mucho menos en problemas raros y opacos de los motores de plantillas. Cualquier lenguaje real es mucho mejor

    • Hace tiempo me tocó hacerme cargo de playbooks de Ansible que se ejecutaban periódicamente para bootstrap y parches en una cantidad enorme de servidores
      He usado Chef para trabajos parecidos, y me gustaba que, al ser Ruby, era fácil definir la lógica que quería y usar bucles y variables de verdad
      Entiendo que Ansible fue diseñado para gente no programadora, pero para alguien con nociones básicas de programación no hay infierno peor que encerrar un playbook de Ansible con muchas condiciones e iteraciones dentro de la sintaxis verbosa de las plantillas Jinja
    • En los stacks actuales, la arquitectura de lenguaje embebido parece estar casi olvidada. Antes, si una aplicación era lo bastante compleja, el núcleo se hacía en C/C++/Java o algo similar, y si hacía falta scripting, se embebía encima algo como LISP o Lua
      Pero ahora lo normal es traer un parser de JSON/TOML/YAML y hacer una función readConfig, incluso en lugares donde un intérprete embebido sería más apropiado
      Desde la perspectiva del desarrollador, es más fácil meterle complejidad a un formato de configuración que ofrecer un lenguaje embebido completo con bindings para la aplicación. Así que da la impresión de que se olvidaron del método, o ni siquiera consideran que sea posible
    • Pulumi resulta atractivo porque te deja escribir en el lenguaje que prefieras y tirar HCL, pero personalmente me parece claramente peor. La infraestructura como código debería ser declarativa para tener más previsibilidad, reproducibilidad y mantenibilidad
      En la época de Chef/Puppet hubo muchos lugares donde empezaron a meter lógica en IaC y eso terminó convertido en un desorden gigantesco imposible de actualizar o mantener. El enfoque de Chef/Pulumi también funciona, pero necesitas gente muy estricta con el estilo y el mantenimiento
      Para equipos grandes y mantenimiento a largo plazo, me parece mejor el modelo de Terraform/Puppet. Aunque HCL sea molesto y usar Python/TypeScript y similares se sienta liberador, el código puramente declarativo evita muchísimo espagueti
    • El problema es que los fanáticos de los lenguajes crean lenguajes para otros fanáticos de los lenguajes
      Quieren meter los elementos de diseño de lenguajes que están de moda, quieren self-hosting, y además que también sirva para escribir servidores web rápidos y multihilo, así que termina siendo algo conceptualmente complejo
      Hace falta un lenguaje juguete simple, tipo Logo, para ingenieros de sistemas/DevOps. Idealmente debería poder explicarse en un solo libro del tamaño del K&R de C
      Necesita tipado dinámico, estructuras de control que puedas aprender en un fin de semana, nada de threading ni concurrencia, nada de orientación a objetos ni herencia, diseño funcional/modular, y un modelo de FFI que pueda llamar y ser llamado fácilmente desde otros lenguajes y frameworks
      El problema es que los fanáticos de los lenguajes no saben contenerse, así que siguen agregando funciones, y eso termina metido en la librería estándar y en la guía de estilo, obligando también a la gente principiante a aprenderlo todo
      A mí mismo me darían ganas de agregar funciones tipo each/map a arrays/hash maps y meter funciones de primera clase y closures, pero eso podría ser un error. Ya existen lenguajes funcionales inmutables para configuración, pero a más del 95% de quienes usan YAML con plantillas no les interesa aprender a programar de esa manera, así que es difícil que se vuelvan masivos
    • Quiero enfatizar la idea de generar archivos de configuración. Es muy útil limitar la configuración en sí a una forma que pueda vivir dentro de un archivo JSON o similar
      Eso hace que la configuración sea más simple, más fácil de consumir y también más fácil de documentar. Pero al momento de escribir esos archivos de configuración, deberías usar un lenguaje de programación, idealmente uno de tipado estático que ofrezca validación de errores, autocompletado y documentación inline
      AWS CDK es un buen ejemplo. Escribir CloudFormation puro es doloroso, pero CDK no le agrega capacidades de programación a CloudFormation, sino que genera CloudFormation. La entrada que AWS consume sigue siendo un CloudFormation relativamente simple y estable
  • Apenas vi el título, pensé que sería sobre Kubernetes.
    La API de Kubernetes es bastante intuitiva y tiene un esquema JSON bien definido. La mayor parte del tiempo al aprender k8s debería dedicarse a entender cómo usar la API, pero en la práctica se va en descifrar cómo usar los charts de Helm.
    No diría que Jsonnet, Ksonnet, Nu o CUE hayan alcanzado tanta popularidad. Parece que la mayoría usa Kustomize, probablemente porque es relativamente intuitivo y viene integrado en kubectl.
    La herramienta ideal debería ofrecer verificación de tipos contra el esquema de k8s, validación y alertas de deprecación de versiones para quien escribe las definiciones, producir un único artefacto fácil de inspeccionar para el usuario, fallar de forma atómica si el clúster no soporta algún objeto o versión, y estar integrada en la cadena de herramientas por defecto.
    Algo como un script de TypeScript en Bun o Deno que exporte una función que reciba argumentos y devuelva una lista de definiciones encajaría bien con deno compile y similares, pero no cumpliría la condición de estar integrado en la cadena de herramientas por defecto.

    • Este es un patrón general en el software. En vez de aprender los elementos primitivos y fundamentos sobre los que se construye un sistema, se aprende un montón de abstracciones por encima porque lo base parece demasiado difícil.
      Uno queda protegido de los detalles de bajo nivel, pero cuando algo falla tiene que lidiar con una enorme pila de abstracciones que dificulta el diagnóstico y la depuración.
      Se vuelve mucho más difícil averiguar qué está pasando en realidad, y terminas dependiendo de capas de abstracción, cargando además con las actualizaciones del proveedor y otros problemas dentro del grafo de dependencias.
    • En nuestro sistema usamos jsonnet y no tiene absolutamente nada que ver con k8s. Más que un éxito masivo, es una herramienta de nicho para configuraciones complejas, y tampoco es algo que se haya promocionado mucho.
      Hace casi todo lo que necesitamos sin problemas, es multiplataforma y puede usarse desde varios lenguajes. Lo he integrado en ejecutables de C++, .NET y la JVM.
      La configuración JSON resultante puede aprovechar una enorme cantidad de herramientas que cuesta encontrar con alternativas como toml/yaml/hocon/ini, etc. Intenté usar HOCON fuera de la JVM, pero siempre aparecía algún caso límite.
    • Probablemente no cumpla el segundo requisito, y seguro que no cumple el tercero: https://cdk8s.io/docs/latest/
    • La idea de mantenerlo simple me parece buena, y en cuanto a instalación trato de usar kustomize o yaml puro siempre que se puede.
      Pero cuando realmente administras sistemas grandes, al final no puedes evitar las ventajas de las plantillas.
    • kustomize y especialmente helm son demasiado confusos, mientras que los archivos YAML de Kubernetes son muy fáciles de escribir y entender.
  • Da risa ver lo poco que los desarrolladores piensan en cómo manejar bien la configuración.
    Parece solo un conjunto de claves y valores guardados en un archivo o generados por código, pero en realidad eso lo es todo. Es programación en sí misma.
    Todo es configuración, y todos los argumentos de funciones también son una forma de configuración. Toda configuración en archivos externos termina convirtiéndose en argumentos de función de una forma u otra.
    El problema es su representación como texto plano del código. Los archivos de configuración declarativos parecen buenos porque puedes ver todo en un solo lugar, pero cuando conviertes la configuración en un programa, se vuelve difícil encontrar qué hay que cambiar.
    Si el código pudiera ejecutarse en tiempo real para mostrar la representación de la configuración final, y además permitiera rastrear cómo se generó cada valor final, no habría problema. Esa función es bastante sencilla, pero no existen sistemas diseñados así. La configuración siempre es algo que se considera al final.
    Si extiendes esta idea a toda la programación, deberías poder ver todo el código y sus transformaciones que dependen de un único valor de configuración.
    Además, la mayor parte de la configuración es relacional o de tipo grafo, así que quizá sería mejor ponerla en una base de datos central. Distintos valores de configuración están relacionados entre sí. Por eso la configuración debería verse en un editor de base de datos o de grafos.
    En cuanto sales del texto plano, todo empieza a simplificarse bastante, aunque todavía hacen falta las funciones de lenguaje mencionadas antes.

    • Un cliente que hace algo parecido lo está intentando con muchísimo empeño. Tiene archivos de “configuración” de más de 1500 líneas por producto, y los usa para generar planos técnicos y archivos de producción.
      Están intentando usar convenciones de nombres para agrupar variables relacionadas dentro de las configuraciones.
      Quieren una estructura de datos realmente anidada, probablemente moverlo a JSON, pero como los ingenieros se niegan por completo a escribir código, la configuración como código no es posible. También están las desventajas ya mencionadas.
      La siguiente idea fue que debería existir una mejor manera de mostrar y editar la configuración. Pensé en una UI visual donde se pueda explorar la representación del producto final, seleccionar piezas y modificar así los parámetros.
      Me pregunto si esa dirección tiene sentido. Si no, me gustaría que lo explicaras un poco más. El núcleo de esta aplicación es la configuración.
  • Peor aún, en entornos como CI/CD YAML casi se convierte en un lenguaje de programación. Y además uno muy verboso, poco intuitivo, mal especificado y distinto según el proveedor.

    • Es casi igual a repetir los errores de Java de principios de la década de 2010. En esa época, muchas aplicaciones enteras estaban pegadas por una enorme masa de XML que configuraba la inyección de dependencias.
      Incluso con DTD y validación XML, tenía ese comportamiento ya conocido de fallar tarde y dar mensajes de error difíciles de interpretar.
      En aquel entonces mucha frustración se dirigía al XML, pero viendo el infierno YAML de mediados de los 2020, queda claro que el problema no era el lenguaje de marcado en sí.
    • Exacto. Nosotros usamos ytt[0], que es “una versión ligeramente modificada del lenguaje de programación Starlark, un dialecto de Python”.
      De verdad odio enterrar lógica en alguna parte dentro de una plantilla YAML.
      [0] https://tanzu.vmware.com/developer/guides/ytt-gs/
    • En algunos entornos donde se trabaja con Kubernetes, en serio usan el término ingeniero de YAML.
    • YAML es como el Bradford Pear de los formatos de serialización. Al principio se ve bien, pero cuando el proyecto envejece y el YAML crece, colapsa bajo el peso de sus propias ramas.
    • Y peor aún, cada generación vuelve a repetir este error. No sé si las expresiones S sean la respuesta, pero Terraform HCL nunca debió existir.
  • Es realmente triste que Helm haya ganado. Trabajo en una empresa haciendo cosas open source relacionadas con k8s, y el 100% de los usuarios nos pedía que hiciéramos charts de Helm, así que al final tuvimos que hacerlo
    Es miserable trabajar con eso. El archivo se llama algo como foo.yaml, pero en realidad no es YAML, así que el editor no te puede ayudar. Hay que pasar todos los datos por indent 4 para que la alineación de YAML quede bien
    Lo más deprimente es que hay que volver a exponer todas las funciones de Kubernetes a su manera. Si alguien quiere agregar deployment.spec.template.spec.fooBars, tienes que agregar deploymentFooBars a values.yaml y conectarlo. Se repite para cada función
    Es un caso clarísimo de “lo malo es bueno” saliendo mal. Yo también llegué a intentar implementar plantillas haciendo horrores como sed -e s/$FOO/foo/g, y probablemente Helm empezó así. El resultado es un desastre
    Personalmente, he usado Kustomize desde antes de que entrara en kubectl, y siempre he quedado bastante satisfecho. Tiene muchas rarezas, pero al menos entiende el significado de los objetos que genera y te ahorra tiempo
    Jsonnet es mucho mejor. Como parte de nuestra app de k8s, también distribuimos despliegues de Envoy para enrutamiento de tráfico complejo, y la configuración de Envoy es verbosa, pero fácil de manejar con Jsonnet: https://github.com/pachyderm/pachyderm/blob/master/etc/gener...
    Estoy considerando seriamente transpilar jsonnet al lenguaje de plantillas de Go e implementar todo en Jsonnet. Al menos sería un poco mantenible, y como helm install simplemente funcionaría, nadie se daría cuenta
    Pero creo que Helm será el fin de Kubernetes. Si alguna herramienta competidora de asignación de cómputo/ejecución de contenedores aparece con un lenguaje decente para la configuración, la gente se cambiará de un día para otro

    • Cuando te den ganas de usar sed -e s/$FOO/foo/g, quizá te convenga revisar envsubst como una solución un poco más estándar y mejor
      Si el tema es plantillar o modificar charts de Helm con jsonnet, Tanka también puede ayudar: https://tanka.dev/helm
    • Quiero creer en la predicción de que Helm será el fin de Kubernetes
      Pero los lugares donde he trabajado siguen usando tf/hcl y helm tal cual, porque todavía le tienen miedo al cambio. Al menos en proyectos personales uno puede respirar un poco más
  • Creo que aquí sí hay un problema. Solo que no estoy seguro de que el tipo de persona que elige YAML como lenguaje de configuración lo vea como un problema
    Hay un choque directo entre la representación de datos centrada en humanos y la representación de datos centrada en computadoras. A las computadoras les gusta algo parecido a Lisp, y a las personas algo parecido a Python
    Si quieres manipular la configuración de Kubernetes con computadoras, probablemente te va a irritar en silencio que Kubernetes use YAML. Pero la comunidad de Kubernetes parece estar compuesta sobre todo por gente del lado de YAML, así que supongo que no les importa por qué el trabajo con archivos de configuración se vuelve terrible cuando metes lógica de programación
    Justamente esa es la desventaja de YAML, y creo que la gente de k8s en general es lo bastante inteligente como para haberlo anticipado
    La frase “YAML es un superconjunto de JSON” no me parece cierta en la práctica, sin importar lo que el autor de la especificación haya escrito en los documentos. Si convirtieras toda la configuración YAML a JSON, el equipo de DevOps se enojaría
    Los dos formatos de datos pueden tener la misma capacidad de expresar significado, pero lo mismo pasa con todos los lenguajes que compilan a la misma arquitectura de CPU. JSON y YAML son cosas distintas en la práctica, y mezclarlos no es buena idea

    • Irónicamente, si no recuerdo mal, los manifiestos de k8s desde el principio asumían que serían generados por máquinas, no escritos a mano por personas
      Claro, la gente terminó escribiéndolos a mano de todos modos, y cuando se volvió insoportable empezaron a pegarles plantillas. Parece que las cosas siempre terminan así
      El texto escrito a mano no es reemplazado por texto de serialización de configuración generado por máquinas, sino por texto que originalmente seguía siendo escrito a mano pero ahora con plantillas encima
    • La frase “YAML es un superconjunto de JSON” solo significa que todo documento JSON válido también es un documento YAML válido. No significa que YAML sea igual a JSON
  • Mi principio personal es que no se debe usar interpolación de cadenas para generar código que leen las máquinas. Un lenguaje de plantillas no es más que una interpolación de cadenas elegante
    He visto los resultados de la inyección SQL y del cross-site scripting. Mientras se siga metiendo texto arbitrario en un intérprete, estas cosas van a seguir pasando
    Por eso también creo que no se deberían usar archivos de plantilla para crear HTML
    Como alternativas a los lenguajes de plantilla para HTML, están Haml de Ruby y Pug de JavaScript. Estos lenguajes ofrecen una forma definida de especificar el árbol completo de etiquetas, atributos y nodos de texto
    Si no te gusta la indentación significativa al estilo Python, en JavaScript está JSX. La parte con apariencia de HTML en JSX se compila a expresiones createElement que construyen un árbol de documento web, y ese árbol luego puede renderizarse como HTML si hace falta
    Haml, Pug y JSX no son lenguajes de plantilla aunque puedan producir HTML. Del mismo modo, JSON.stringify(myObj) no es un lenguaje de plantilla para JSON
    El código que leen las máquinas, cuando sea posible, debería generarse con herramientas que entiendan y aprovechen la estructura conocida del lenguaje de destino

    • Decir que Haml, Pug y JSX no son lenguajes de plantilla no tiene sentido, salvo que se use una definición personal de lenguaje de plantilla como “interpolación de cadenas elegante”
      Haml es un sistema de plantillas para evitar código inline en documentos web y hacer que el HTML sea más limpio, y Pug es un motor de plantillas con muchas funciones para Node.js
      Puedo aceptar que, estrictamente hablando, JSX no sea un lenguaje de plantilla
      Al final, todos se compilan a HTML. Solo que no mediante interpolación de cadenas, sino como lenguajes que se parsean a árboles sintácticos y se renderizan como HTML con base en una comprensión interna de la estructura válida
      Las plantillas de YAML sí son interpolación de cadenas elegante, y no son un lenguaje de plantilla, o al menos son un lenguaje de plantilla pésimamente implementado
    • No todos los lenguajes de plantilla son lenguajes de plantillas de cadenas. Por ejemplo, si ves PHP como un lenguaje de plantilla para texto, con la misma lógica XQuery es un lenguaje de plantilla para XML
    • Ese es el verdadero núcleo del problema. YAML y las plantillas solo distraen. Al final todo se reduce a que string es un tipo demasiado general y lo usamos con pereza
      Mi regla personal es que cada vez que un valor entra en una cadena, debe codificarse correctamente
      Antes escribí sobre este tema: https://kevincox.ca/2022/02/08/escape-everything/
      En resumen, toda cadena tiene un formato que debe respetar, ya sea HTML, SQL o salida de terminal legible por humanos. Cada vez que metes un valor en una cadena, deberías codificarlo correctamente para ese formato, pero casi nunca lo hacemos
  • Nos estamos pasando a cuelang [1]. Personalmente me parece mejor diseñado que Jsonette
    Kubernetes ya tiene reconciliación de estado, así que lo único que faltaba en esta configuración era la eliminación, y ahora eso se puede resolver con la función de prune [2]
    [1] https://cuelang.org/docs/integrations/k8s/
    [2] https://kubernetes.io/blog/2023/05/09/introducing-kubectl-ap...

    • Puedo recomendar cuelang. Empezamos a usarlo en la empresa y es realmente bueno
      Algunos mensajes de error son un poco difíciles de interpretar, pero compensa por la enorme cantidad de errores que detecta de antemano. Las pocas veces que ahora tengo que escribir yaml directamente se sienten demasiado tediosas en comparación
  • En estos casos normalmente me meto con un “¿han oído hablar de nuestro salvador CUELang?”: https://cuelang.org/
    Todavía no es Turing completo, pero es lo bastante expresivo para eliminar duplicación, permite definir esquemas y datos en el mismo archivo o en archivos separados, y también tiene tipos unión
    Puede generar YAML o JSON, y puede validar tanto a sí mismo como archivos YAML/JSON
    Su mayor desventaja es que la implementación actual solo existe en Go, así que puede requerir subprocesos o FFI

    • Tenemos un pipeline que acepta archivos de cuelang muy concisos
      Luego crea archivos JSON para cada aplicación, alguna herramienta genera definiciones XML, esas definiciones se aplican a un XLS que manejan los arquitectos, y de ahí sale YAML para aplicarlo a charts de Helm
      Los charts despliegan el cliente de k8s, y ese cliente interactúa con el clúster principal en JSON mediante la API
      Tomó algo de tiempo, pero estamos usando la mejor herramienta para cada trabajo
    • ¿Cómo se compara con dhall?