
Si está trabajando con el entorno Kubernetes, entonces probablemente utilice varias herramientas de plantillas existentes, algunas de las cuales forman parte de administradores de paquetes como Helm o Ksonnet , o simplemente idiomas de plantillas (Jinja2, plantilla Go, etc.). Todos ellos tienen sus propios inconvenientes y ventajas, y los revisaremos y escribiremos nuestra propia herramienta que intentará combinar las mejores características.
Entonces, ¿por qué no Helm?
Hay varios artículos que critican a Helm (por ejemplo, solo uno de ellos: piénselo dos veces antes de usar Helm ). El problema principal con Helm es que funciona con representaciones de cadenas y los manifiestos de Kubernetes son objetos (json) . El verdadero infierno para un desarrollador de gráficos Helm comienza cuando necesita calcular las sangrías para un manifiesto yaml
, a veces se ve así (es un ejemplo real de mi gráfico):
spec: jobTemplate: spec: template: spec: containers: - name: my-awesome-container resources: {{ toYaml .Values.resources | indent 14 }}

Pero Helm hoy es de hecho el estándar para el empaquetado de aplicaciones Kubernetes. La principal ventaja de Helm es una gran comunidad y una gran cantidad de repositorios públicos con gráficos. Y recientemente los desarrolladores de Helm han anunciado un centro de Helm . Así que Helm hoy es como Docker: no es el único, pero tiene comunidad y apoyo.
Hay cambios prometedores con el lanzamiento de Helm 3, pero nadie sabe cuándo podría ser.
Para concluir, las ventajas de Helm:
- Gran comunidad y varias listas públicas.
- (Relativamente) sintaxis amigable para los humanos. Al menos es plantilla yaml + go;)
Inconvenientes:
- Trabajar con cadenas y no con objetos.
- Número limitado de operadores y funciones que puede usar
OK, entonces tal vez Ksonnet?
Si está comparando Helm con Ksonnet, este último tiene una gran ventaja, es decir, funciona con objetos. Ksonnet es una herramienta basada en el lenguaje de plantillas JSON Jsonnet. Otra característica interesante de Ksonnet es que tiene bibliotecas Jsonnet compatibles con Kubernetes-API que puede importar a su plantilla y trabajar con objetos Kubernetes como en cualquier lenguaje OOP:
local k = import "k.libsonnet"; local deployment = k.apps.v1beta1.deployment; local appDeployment = deployment .new( params.name, params.replicas, container .new(params.name, params.image) .withPorts(containerPort.new(targetPort)), labels);
Se ve impresionante, ¿no?
Es un poco menos ordenado cuando no está trabajando con objetos API sino solo con objetos json importados del archivo yaml
/ json
:
{ global: {}, components: { "deployment-nginx-deployment-dkecx"+: { spec+: { replicas: 10, template+: { spec+: { containers+: [ { name: "nginx", image: "nginx:latest", ports: [ { containerPort: 80, }, ], }, ], }, }, }, }, }, }
Pero aún así es algo y es mejor que trabajar con cadenas en Helm. La desventaja de Ksonnet es que tiene una comunidad más pequeña y menos paquetes que Helm (aunque puede importar gráficos Helm en su proyecto Ksonnet, pero trabajará con ellos como objetos json, no como objetos de biblioteca jsonnet). Y como resultado de una comunidad y contribución más pequeñas, faltan algunas características cuando se intenta escribir su propio cuadro. Uno de ellos lo experimenté yo mismo: sabes que en Helm puedes construir un ConfigMap
desde un directorio que contiene varios archivos de configuración de esta manera:
apiVersion: v1 kind: ConfigMap metadata: name: conf data: {{- (.Files.Glob "foo/*").AsConfig | nindent 2 }}
Puedes imaginar mi frustración cuando descubrí que no hay tal característica en Ksonnet. Sin embargo, hay soluciones alternativas. Pero el punto es que es solo un ejemplo de la situación en la que escribe felizmente su gráfico y luego, de repente, la falta de alguna característica lo detiene a la mitad.
En total, ventajas de Ksonnet:
- Trabajando con objetos
- Bibliotecas Jsonnet compatibles con API de Kubernetes
- Soporte de importación de gráfico de timón
Inconvenientes:
- Comunidad más pequeña y menor número de paquetes nativos de Ksonnet
- Falta de alguna funcionalidad que pueda usar en Helm
- Nueva sintaxis => mayor tiempo de aprendizaje => mayor factor de bus
- La sintaxis a veces puede volverse fea y menos legible para los humanos (especialmente al hacer soluciones por falta de funciones)
Aquí hay algunos criterios para la herramienta de plantillas "ideal":
- Debería funcionar con objetos, no cadenas
- Debe tener la capacidad de trabajar con objetos compatibles con Kubernetes-API
- Debe tener un conjunto de funciones decente para trabajar con cadenas
- Debería funcionar bien con los formatos json y yaml
- Debe ser amigable con los humanos
- Debe ser simple
- Debe tener la capacidad de importar cartas Helm existentes (porque esto es realidad y queremos hacer uso de la comunidad Helm)
Eso es suficiente por ahora. Revisé esta lista en mi cabeza y pensé para mí mismo: está bien, ¿por qué no probar Python? Veamos si se ajusta a nuestros criterios:
- Trabajar con objetos, no cadenas . Sí, podemos usar
dict
y tipos de list
para eso. - Tener la capacidad de trabajar con objetos compatibles con Kubernetes-API . Sí,
from kubernetes import client
- Tener un conjunto de funciones decente para trabajar con cadenas . ¡Mucho!
- Trabaja bien con los formatos json y yaml . Muy bien
- Amigable con los humanos No mierda
- Simple Si
- Capacidad para importar cartas Helm existentes . Eso, vamos a agregarnos a nosotros mismos.
Ok, parece prometedor. Decidí escribir una herramienta de plantilla simple en la parte superior de la biblioteca de cliente oficial de Python para kubernetes y ahora déjame mostrarte lo que salió de ella.
Conoce a karavel
No hay nada especial o complicado sobre esta herramienta. Acabo de tomar la biblioteca de Kubernetes (que me dio la capacidad de trabajar con objetos de Kubernetes) y escribí algunas funcionalidades básicas para los gráficos Helm existentes (para que uno pudiera buscarlos y agregarlos a su propio gráfico). Entonces, hagamos un recorrido.
En primer lugar, esta herramienta es accesible en el repositorio de Github y puede encontrar un directorio con ejemplos allí.
Inicio rápido con la imagen de Docker
Si quieres probarlo, la forma más sencilla es usar esta imagen acoplable :
$ docker run greegorey/karavel -h usage: karavelcli.py [-h] subcommand ... optional arguments: -h, --help show this help message and exit list of subcommands: subcommand template generates manifests from template ensure ensure helm dependencies
Por supuesto, si desea crear plantillas de gráficos, debe montar el directorio de su gráfico:
$ cd example $ docker run -v $PWD:/chart greegorey/karavel template .
Entonces, echemos un vistazo a la estructura del gráfico. Es muy similar a uno de Helm:
$ cd example $ tree . . ├── dependencies ├── prod.yaml ├── requirements.yaml ├── templates │ ├── custom-resource.py │ ├── deployment.py │ └── service-helm.py └── values.yaml 2 directories, 6 files
Al igual que Helm, tiene el archivo require.yaml con el mismo diseño:
dependencies: - name: mysql version: 0.13.1 repository: https://kubernetes-charts.storage.googleapis.com/
Aquí solo enumera las dependencias de Helm que desea importar en su gráfico. Las dependencias van al directorio de dependencies
. Para buscarlos o actualizarlos, use el comando ensure
:
$ karavel ensure .
Después de eso, su directorio de dependencies
se verá así:
$ tree dependencies dependencies └── mysql-0.13.1 └── mysql ├── Chart.yaml ├── README.md ├── templates │ ├── NOTES.txt │ ├── _helpers.tpl │ ├── configurationFiles-configmap.yaml │ ├── deployment.yaml │ ├── initializationFiles-configmap.yaml │ ├── pvc.yaml │ ├── secrets.yaml │ ├── svc.yaml │ └── tests │ ├── test-configmap.yaml │ └── test.yaml └── values.yaml 4 directories, 13 files
Ahora, después de asegurar nuestras dependencias, echemos un vistazo a las plantillas. Primero, creamos una implementación simple de nginx:
from kubernetes import client from karavel.helpers import Values def template(): values = Values().values
Por lo tanto, para que la plantilla sea válida, debe tener la función template()
que devuelve un solo objeto Kubernetes o una list
/ tuple
de ellos. Puede encontrar la lista de objetos API para el cliente Python aquí .
Como puede ver, el código es limpio, simple, legible. ¿Puede preguntarse de values.nginx.image.repository
proviene values.nginx.image.repository
? Obtiene valores de los archivos de valores que pasa al crear la plantilla del gráfico, al igual que en Helm: karavel template -f one.yaml --values two.yaml
. Los veremos más tarde.
Bien, ¿qué pasa con las cartas de Helm?
Ahora, creamos nuestro propio Despliegue. Pero, ¿qué pasa si queremos importar Helm chart o una parte de un gráfico? Echemos un vistazo a templates/service-helm.py
:
from kubernetes import client from karavel.helm import HelmChart from karavel.helpers import Values def template(): values = Values().values
Simple, ¿eh? Tenga en cuenta esta línea: service = chart.get(name='svc', obj_class=client.V1Service)
: creamos un objeto de la clase V1Service
form Helm yaml
file. Si no quiere / necesita hacer eso, siempre puede trabajar con solo dict
.
¿Qué sucede si quiero crear un recurso personalizado?
Bueno, hay un pequeño problema con eso. La API de Kubernetes no agrega objetos CRD en la definición de swagger json en /openapi/v2
, y los objetos de cliente Python se basan en esta definición. Pero aún puede trabajar fácilmente con objetos dict
. Así:
from kubernetes import client def template(): resource = { 'apiVersion': 'stable.example.com/v1', 'kind': 'Whale', 'metadata': client.V1ObjectMeta( name='my-object', ), 'spec': { 'image': 'my-whale-image:0.0.1', 'tail': 1, 'fins': 4, } } return resource
Todavía se ve bien, ¿no?
¿Puedo tener valores para diferentes entornos, por ejemplo, dev / prod?
Si puedes!
Veamos values.yaml
primero:
nginx: image: repository: nginx tag: 1.15-alpine mysql: port: 3307 protocol: TCP helm: releaseName: my-release namespace: prod imageTag: '5.7.14' service: type: NodePort
Tenga en cuenta la clave de helm
dentro de mysql
dict: la usamos al especificar valores para el gráfico de chart = HelmChart(name='mysql', version='0.13.1', values=values.mysql.helm)
de timón chart = HelmChart(name='mysql', version='0.13.1', values=values.mysql.helm)
. Algunos gráficos de Helm necesitan releaseName
para nombrar aplicaciones y namespace
de namespace
para políticas RBAC. Estos dos valores se pasan a Helm como --namespace
y argumentos NAME
en la helm template
.
Ahora, puede especificar un archivo adicional para prod env y modelar todos nuestros ejemplos:
$ karavel template -f values.yaml -f prod.yaml . --- # Source: templates/custom-resource.py apiVersion: stable.example.com/v1 kind: Whale metadata: name: my-object spec: fins: 4 image: my-whale-image:0.0.1 tail: 1 --- # Source: templates/deployment.py apiVersion: extensions/v1beta1 kind: Deployment metadata: name: nginx-deployment spec: replicas: 3 template: metadata: labels: app: nginx spec: containers: - image: nginx:1.14-alpine name: nginx ports: - containerPort: 80 --- # Source: templates/service-helm.py apiVersion: v1 kind: Service metadata: annotations: null labels: app: prod-release-mysql chart: mysql-0.13.1 release: prod-release-suffix name: prod-release-mysql spec: ports: - name: my-custom-port port: 3308 protocol: TCP targetPort: 39000 selector: app: prod-release-mysql type: NodePort
Después de eso, puede hacer que kubeclt apply
e implemente estos objetos en el clúster.
Genial! ¿Qué pasa con la codificación y base64?
import base64
¿Qué pasa con el uso de Vault para secretos?
import hvac
¿Buscando urls?
import importlib
¿Funciones hash seguras?
import Crypto
Lo tienes Con Python puedes hacer muchas cosas con tus manifiestos de Kubernetes.
¿Es el síndrome NIH?
No :)
Yo soy felizmente usando Helm en mis proyectos actuales. Sin embargo, hay cosas que extraño. También utilicé Ksonnet en algunos de mis proyectos.
Me gustaría pensar en esta herramienta como una prueba de concepto de que podemos tener herramientas de plantillas mejores que Helm y que no es muy difícil desarrollarlas usando Python. Si existe un interés / necesidad de la comunidad en dicha herramienta, juntos podemos continuar desarrollándola. O podemos esperar el lanzamiento de Helm 3;)
Conclusión
Le mostré una herramienta de plantillas basada en Python para Kubernetes que tiene soporte para objetos compatibles con Kubernetes-API y soporte para importar gráficos Helm. Cualquier comentario y discusión de la comunidad son bienvenidos, y nuevamente bienvenidos al repositorio .
¡Gracias por leer esto y que tengas un buen día!
Referencias