Nota perev. : Con este artículo abrimos una serie de publicaciones sobre el administrador de paquetes para Kubernetes, que utilizamos activamente en el trabajo diario, - Helm. El autor original del material es Matt Butcher, uno de los fundadores del proyecto Helm, que trabaja en proyectos de código abierto en Microsoft y escribe 8 libros técnicos (en particular, "Go in Practice"). Sin embargo, el artículo se complementa con nuestros comentarios (a veces extensos), y pronto se ampliará con nuevas notas sobre Helm con un enfoque más práctico. ACTUALIZACIÓN (03/09/2018): salió la secuela - " Conocimiento práctico con el administrador de paquetes para Kubernetes - Helm ".
En junio, Helm se
mudó del estado del proyecto principal de Kubernetes a la Cloud Native Computing Foundation (CNCF). CNCF se está convirtiendo en la organización matriz de las mejores herramientas nativas de código abierto en la nube. Por lo tanto, es un gran honor para Helm formar parte de esa base. Y nuestro primer proyecto significativo bajo los auspicios de CNCF es verdaderamente a gran escala: creamos Helm 3.
Una breve historia de Helm
Helm apareció originalmente como un proyecto de código abierto de Deis. Fue modelado a partir de
Homebrew (el administrador de paquetes para macOS - aprox. Transl. ) , Y la tarea que Helm 1 tenía fue una oportunidad facilitada para que los usuarios instalaran rápidamente sus primeras cargas de trabajo en Kubernetes. El anuncio oficial de Helm tuvo lugar en la primera conferencia KubeCon San Francisco en 2015.
Nota trans.: Desde la primera versión, que se llamó dm (Deployment Manager), se eligió la sintaxis YAML para describir los recursos de Kubernetes, y las plantillas Jinja y los scripts de Python fueron compatibles al escribir configuraciones.Una plantilla de aplicación web simple podría verse así:Yamlresources: - name: frontend type: github.com/kubernetes/application-dm-templates/common/replicatedservice:v1 properties: service_port: 80 container_port: 80 external_service: true replicas: 3 image: gcr.io/google_containers/example-guestbook-php-redis:v3 - name: redis type: github.com/kubernetes/application-dm-templates/storage/redis:v1 properties: null
Al describir los componentes de la aplicación implementada, se indican el nombre, la plantilla utilizada y también los parámetros necesarios de esta plantilla. En el ejemplo anterior, los redis
frontend
y redis
usan plantillas del repositorio oficial.Ya en esta versión, puede usar recursos de una base de conocimiento común, crear sus propios repositorios de plantillas y crear aplicaciones complejas debido a los parámetros y el anidamiento de las plantillas.La arquitectura Helm 1 consta de tres componentes. El siguiente diagrama ilustra la relación entre ellos:
Manager
realiza la función de un servidor web (la comunicación con los clientes se produce a través de la API REST), administra las implementaciones en el clúster de Kubernetes y se utiliza como un almacén de datos.- El componente
expandybird
lleva las configuraciones del usuario a una forma plana, es decir aplica plantillas Jinja y ejecuta scripts Python. - Después de recibir una configuración plana,
resourcifier
realiza las llamadas necesarias a kubectl y devuelve mensajes de estado y error, si los hay, al manager
.
Para comprender las capacidades de la primera versión de Helm, brindaré ayuda sobre el comando dm
:
Salida de ayuda de dm Usage: ./dm [<flags>] <command> [(<template-name> | <deployment-name> | (<configuration> [<import1>...<importN>]))] Commands: expand Expands the supplied configuration(s) deploy Deploys the named template or the supplied configuration(s) list Lists the deployments in the cluster get Retrieves the supplied deployment manifest Lists manifests for deployment or retrieves the supplied manifest in the form (deployment[/manifest]) delete Deletes the supplied deployment update Updates a deployment using the supplied configuration(s) deployed-types Lists the types deployed in the cluster deployed-instances Lists the instances of the named type deployed in the cluster templates Lists the templates in a given template registry (specified with --registry) registries Lists the registries available describe Describes the named template in a given template registry getcredential Gets the named credential used by a registry setcredential Sets a credential used by a registry createregistry Creates a registry that holds charts Flags: -apitoken string Github api token that overrides GITHUB_API_TOKEN environment variable -binary string Path to template expansion binary (default "../expandybird/expansion/expansion.py") -httptest.serve string if non-empty, httptest.NewServer serves on this address and blocks -name string Name of deployment, used for deploy and update commands (defaults to template name) -password string Github password that overrides GITHUB_PASSWORD environment variable -properties string Properties to use when deploying a template (eg, --properties k1=v1,k2=v2) -regex string Regular expression to filter the templates listed in a template registry -registry string Registry name (default "application-dm-templates") -registryfile string File containing registry specification -service string URL for deployment manager (default "http://localhost:8001/api/v1/proxy/namespaces/dm/services/manager-service:manager") -serviceaccount string Service account file containing JWT token -stdin Reads a configuration from the standard input -timeout int Time in seconds to wait for response (default 20) -username string Github user name that overrides GITHUB_USERNAME environment variable --stdin requires a file name and either the file contents or a tar archive containing the named file. a tar archive may include any additional files referenced directly or indirectly by the named file.
Y ahora volviendo al texto original sobre la historia de Helm ...Unos meses después, unimos fuerzas con el equipo de Kubernetes Deployment Manager de Google y comenzamos a trabajar en Helm 2. El objetivo era mantener Helm fácil de usar agregando lo siguiente:
- plantillas de gráficos ("gráfico" - un análogo de un paquete en el ecosistema Helm - traducción aprox. ) para personalización;
- gestión de clústeres para equipos;
- repositorio de gráficos completo;
- formato de paquete estable y firmado;
- fuerte compromiso con las versiones semánticas y el mantenimiento de la compatibilidad con versiones anteriores de una versión a otra.
Para lograr estos objetivos, se ha agregado un segundo componente al ecosistema Helm. Se convirtió en el clúster Tiller interno, que proporcionó la instalación de cartas Helm y su gestión.
Nota perev.: Por lo tanto, en la segunda versión de Helm, el único componente que queda en el clúster es responsable del ciclo de vida de la instalación ( lanzamiento ), y la preparación de la configuración se envía al cliente de Helm.Si reiniciar el clúster al usar la primera versión de Helm condujo a una pérdida completa de datos de servicio (ya que se almacenaron en la RAM), entonces en Helm 2 todos los datos se almacenan en ConfigMaps
, es decir. recursos dentro de Kubernetes. Otro paso importante fue la transición de una API síncrona (donde se bloqueaba cada solicitud) al uso de gRPC asíncrono.Desde el lanzamiento de Helm 2 en 2016, el proyecto Kubernetes ha experimentado un crecimiento explosivo y nuevas oportunidades significativas. Se ha agregado el control de acceso basado en roles (RBAC). Se introducen muchos nuevos tipos de recursos. Recursos de terceros inventados (definiciones de recursos personalizados, CRD). Y lo más importante, hay mejores prácticas. Al pasar por todos estos cambios, Helm continuó atendiendo las necesidades de los usuarios de Kubernetes. Pero nos quedó claro que era hora de hacer cambios importantes para que las necesidades de este ecosistema en desarrollo siguieran siendo satisfechas.
Así que llegamos a Helm 3. A continuación, hablaré sobre algunas de las innovaciones presentadas en la hoja de ruta del proyecto.
Saludos lua
En Helm 2, presentamos plantillas. En la primera etapa del desarrollo de Helm 2, admitimos plantillas Go, Jinja, código Python limpio e incluso teníamos un prototipo de soporte de ksonnet. Pero la presencia de muchos motores para plantillas dio lugar a más problemas de los que resolvió. Por lo tanto, hemos llegado al punto de elegir uno.
Las plantillas Go tenían cuatro ventajas:
- la biblioteca está integrada en Go ;
- las plantillas se ejecutan en un entorno de sandbox estrictamente limitado;
- podríamos insertar funciones y objetos arbitrarios en el motor;
- Funcionaron bien con YAML.
Aunque conservamos la interfaz en Helm para admitir otros motores de plantillas, las plantillas Go se han convertido en nuestro estándar predeterminado. Y los próximos años de experiencia mostraron cómo los ingenieros de muchas compañías crearon miles de gráficos utilizando plantillas Go.
Y nos enteramos de sus decepciones:
- La sintaxis es difícil de leer y está mal documentada.
- Los problemas de lenguaje, como las variables inmutables, los tipos de datos complejos y las reglas de visibilidad restrictivas, han convertido las cosas simples en complejas.
- La incapacidad para definir funciones dentro de las plantillas hizo que la creación de bibliotecas reutilizables fuera aún más difícil.
Lo más importante, utilizando el lenguaje de plantilla, "truncamos" los objetos de Kubernetes a su representación lineal. (En otras palabras, los desarrolladores de plantillas tuvieron que administrar los recursos de Kubernetes como documentos de texto en formato YAML).
Trabaja en objetos, no en piezas de YAML
Una y otra vez, escuchamos de los usuarios una solicitud de la capacidad de inspeccionar y modificar los recursos de Kubernetes como objetos, no como cadenas. Al mismo tiempo, insistieron en que no importa qué forma de implementación elijamos para esto, debería ser fácil de aprender y mantener en el ecosistema.
Después de meses de investigación, decidimos proporcionar un lenguaje de secuencias de comandos incorporado que se pueda empaquetar en un entorno limitado y personalizar. Entre los 20 idiomas principales, solo había un candidato que cumplía con los requisitos:
Lua .
En 1993, un grupo de ingenieros brasileños de TI creó un lenguaje de secuencias de comandos ligero para incrustar en sus herramientas. Lua tiene una sintaxis simple, es ampliamente compatible y ha aparecido en la lista de
los 20 idiomas principales durante mucho tiempo. Es compatible con IDE y editores de texto, hay muchos manuales y tutoriales. En un ecosistema tan existente, nos gustaría desarrollar nuestra solución.
Nuestro trabajo en Helm Lua aún se encuentra en la etapa de prueba conceptual, y esperamos una sintaxis que sea familiar y flexible. Al comparar los enfoques antiguos y los nuevos, puede ver hacia dónde nos estamos moviendo.
Aquí hay
un ejemplo de una plantilla de hogar con Alpine en Helm 2:
apiVersion: v1 kind: Pod metadata: name: {{ template "alpine.fullname" . }} labels: heritage: {{ .Release.Service }} release: {{ .Release.Name }} chart: {{ .Chart.Name }}-{{ .Chart.Version }} app: {{ template "alpine.name" . }} spec: restartPolicy: {{ .Values.restartPolicy }} containers: - name: waiter image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" imagePullPolicy: {{ .Values.image.pullPolicy }} command: ["/bin/sleep", "9000"]
En esta plantilla sencilla, puede ver de inmediato todas las directivas de plantilla integradas, como
{{ .Chart.Name }}
.
Y aquí está la definición del mismo hogar en la versión preliminar del código Lua:
unction create_alpine_pod(_) local pod = { apiVersion = "v1", kind = "Pod", metadata = { name = alpine_fullname(_), labels = { heritage = _.Release.Service or "helm", release = _.Release.Name, chart = _.Chart.Name .. "-" .. _.Chart.Version, app = alpine_name(_) } }, spec = { restartPolicy = _.Values.restartPolicy, containers = { { name = waiter, image = _.Values.image.repository .. ":" .. _.Values.image.tag, imagePullPolicy = _.Values.image.pullPolicy, command = { "/bin/sleep", "9000" } } } } } _.resources.add(pod) end
No es necesario mirar cada línea de este ejemplo para comprender lo que está sucediendo. Es inmediatamente obvio que en el código se define en. Pero en lugar de usar cadenas YAML con directivas de plantilla incorporadas, lo definimos como un objeto en Lua.
Acortemos este código
Como trabajamos directamente con objetos (en lugar de manipular una gran cantidad de texto), podemos aprovechar al máximo los scripts. Las oportunidades para crear bibliotecas compartidas que aparecen aquí parecen realmente atractivas. Y esperamos que al introducir bibliotecas especializadas (o permitir que la comunidad las cree), podamos reducir el código anterior a algo como esto:
local pods = require("mylib.pods"); function create_alpine_pod(_) myPod = pods.new("alpine:3.7", _) myPod.spec.restartPolicy = "Always"
En este ejemplo, usamos la capacidad de trabajar con la definición de un recurso como un objeto, que es fácil de establecer propiedades, mientras se mantiene la concisión y la legibilidad del código.
Plantillas ... Lua ... ¿Por qué no todos juntos?
Aunque las plantillas no son tan maravillosas para todas las tareas, aún tienen ciertas ventajas. Templates in Go es una tecnología estable con una base de usuarios establecida y muchos gráficos existentes. Muchos desarrolladores de gráficos afirman que les gusta escribir plantillas. Por lo tanto, no vamos a eliminar el soporte de plantillas.
En cambio, queremos permitir que ambas plantillas y Lua se usen al mismo tiempo. Los scripts de Lua tendrán acceso a las plantillas de Helm antes y después de que se procesen, lo que permitirá a los desarrolladores de gráficos avanzados realizar transformaciones complejas en los gráficos existentes, al tiempo que conserva la capacidad simple de crear gráficos de Helm con plantillas.
Estamos muy animados por el soporte de scripts en Lua, pero al mismo tiempo nos estamos deshaciendo de una parte significativa de la arquitectura Helm ...
Decir adiós a Tiller
Durante el desarrollo de Helm 2, presentamos Tiller como un componente de integración con Deployment Manager. Tiller jugó un papel importante para los equipos que trabajan en el mismo clúster: permitió interactuar con el mismo conjunto de lanzamientos para muchos administradores diferentes.
Sin embargo, Tiller actuó como un servidor de sudo gigante, otorgando una amplia gama de derechos a todos los que tienen acceso a Tiller. Y nuestro esquema de instalación predeterminado era la configuración permisiva. Por lo tanto, los ingenieros de DevOps y SRE tuvieron que aprender los pasos adicionales para instalar Tiller en clústeres de múltiples inquilinos.
Además, con el advenimiento de CRD, ya no podíamos confiar de manera confiable en Tiller para mantener el estado o funcionar como un centro central para la información de lanzamiento de Helm. Solo podríamos almacenar esta información como entradas separadas en Kubernetes.
El objetivo principal de Tiller se puede lograr sin el mismo Tiller. Por lo tanto, una de las primeras decisiones tomadas durante la fase de planificación de Helm 3 fue abandonar por completo a Tiller.
Mejora de seguridad
Sin Tiller, el modelo de seguridad de Helm se simplifica radicalmente. La autenticación del usuario es delegada por Kubernetes. Y autorización también. Los derechos de timón se definen como derechos de Kubernetes (a través de RBAC), y los administradores del clúster pueden restringir los derechos de timón en cualquier nivel de detalle requerido.
Lanzamientos, versiones de lanzamiento y almacenamiento estatal
En ausencia de Tiller, para mantener el estado de varias versiones dentro del clúster, necesitamos una nueva forma para que todos los clientes interactúen (en la gestión de versiones).
Para hacer esto, presentamos dos nuevas entradas:
Release
: para una instalación específica de un gráfico en particular. Si ejecutamos helm install my-wordpress stable/wordpress
, se creará y mantendrá una versión llamada my-wordpress
durante toda la vida de esta instalación de WordPress.ReleaseVersion
: cada vez que actualice el gráfico Helm, debe tener en cuenta qué ha cambiado y si el cambio fue exitoso. ReleaseVersion
vinculado a un lanzamiento y solo almacena registros con información sobre actualizaciones, ReleaseVersion
. Cuando ejecutamos helm upgrade my-wordpress stable/wordpress
, el objeto Release
original permanece igual, pero ReleaseVersion
objeto ReleaseVersion
secundario con información sobre la operación de actualización.
Releases
y
ReleaseVersions
se almacenarán en los mismos espacios de nombres que los objetos del gráfico.
Con estas características, los equipos de usuarios de Helm podrán rastrear los registros de las instalaciones de Helm en el clúster sin la necesidad de Tiller.
¡Pero espera, eso no es todo!
En este artículo intenté hablar sobre algunos de los principales cambios en Helm 3. Sin embargo, esta lista no está completa.
El plan Helm 3 también incluye otros cambios, como mejoras en el formato del gráfico, mejoras de rendimiento para los repositorios de gráficos y un nuevo sistema de eventos que los desarrolladores de gráficos pueden utilizar. También estamos haciendo que Eric Raymond llame a la
arqueología del código limpiando la base del código y actualizando los componentes que han perdido relevancia en los últimos tres años.
Nota perev. : Es una paradoja, pero el administrador de paquetes de Helm 2, cuando la install
o upgrade
exitosa, es decir tener la versión en estado de success
no garantiza que los recursos de la aplicación se hayan implementado correctamente (por ejemplo, no hay errores como ImagePullError
). Quizás el nuevo modelo de evento le permitirá agregar ganchos adicionales para recursos y controlar mejor el proceso de implementación; lo descubriremos pronto.Con la adhesión de Helm a CNCF, no solo Helm 3, sino también
Chart Museum , la maravillosa utilidad
Chart Testing , el
repositorio oficial de gráficos y otros proyectos bajo los auspicios de Helm en CNCF nos inspiran. Confiamos en que la buena administración de paquetes para Kubernetes es tan importante para el ecosistema nativo de la nube como los buenos administradores de paquetes para Linux.
PD del traductor
Lea también en nuestro blog: