
Me llamo Dmitry Sugrobov, soy desarrollador en 'Leroy Merlin'. En este artículo explicaré por qué necesitamos Helm, cómo simplifica el trabajo con Kubernetes, qué ha cambiado en la tercera versión y cómo actualizar aplicaciones en producción sin tiempo de inactividad.
Este es un resumen basado en una presentación en la conferencia by — si no quieres leer, mira el video.

Por qué usamos Kubernetes en producción
'Leroy Merlin' es líder en el mercado minorista de bricolaje en Rusia y Europa. En nuestra empresa hay más de cien desarrolladores, 33,000 empleados internos y una enorme cantidad de personas que visitan nuestros hipermercados y sitio web. Para hacerlos felices, decidimos seguir enfoques estándar en la industria. Desarrollamos nuevas aplicaciones utilizando arquitectura de microservicios; para la aislamiento de entornos y entrega adecuada usamos contenedores; y para la orquestación utilizamos Kubernetes. El costo de usar orquestadores está disminuyendo rápidamente: hay cada vez más ingenieros en el mercado que dominan la tecnología y surgen proveedores que ofrecen Kubernetes como servicio.
Todo lo que hace Kubernetes, por supuesto, se puede hacer de otras maneras, por ejemplo, con scripts en algún Jenkins y docker-compose, pero ¿por qué complicar la vida si hay una solución lista y confiable? Por eso llegamos a Kubernetes y ya lo estamos utilizando en producción desde hace un año. Actualmente tenemos veinticuatro clústeres de Kubernetes, el más antiguo tiene más de un año, y contiene alrededor de doscientos pods.
La maldición de la gran cantidad de archivos YAML en Kubernetes
Para ejecutar un microservicio en Kubernetes crearemos al menos cinco archivos YAML: para Deployment, Service, Ingress, ConfigMap, Secrets, y los enviaremos al clúster. Para la siguiente aplicación escribiremos el mismo paquete de YAMLs, y para la tercera, otro más, y así sucesivamente. Multiplicamos el número de documentos por la cantidad de entornos, y ya tenemos cientos de archivos, sin contar los entornos dinámicos.

Adam Reese, mantenedor principal de Helm, introdujo el concepto de “”, que se ve así:
- Copiar YAML — copiar el archivo YAML.
- Pegar YAML — pegarlo.
- Arreglar sangrías — corregir las sangrías.
- Repetir — repetir nuevamente.
Es una opción válida, pero hay que copiar los archivos YAML muchas veces. Para cambiar este ciclo, se inventó Helm.
Qué es Helm
Primero, Helm es gestor de paquetes, que ayuda a encontrar e instalar los programas necesarios. Para instalar, por ejemplo, MongoDB, no es necesario ir al sitio oficial y descargar los binarios, solo se debe ejecutar el comando helm install stable/mongodb.
En segundo lugar, Helm — un motor de plantillas, ayuda a parametrizar archivos. Regresando a la situación con los archivos YAML en Kubernetes. Es más fácil escribir el mismo archivo YAML, agregarle algunos marcadores de posición, donde Helm insertará valores. Es decir, en lugar de un gran conjunto de archivos YAML, habrá un conjunto de plantillas, en las que en el momento adecuado se insertarán los valores necesarios.
En tercer lugar, Helm — un maestro de despliegue. Con su ayuda, se pueden instalar, revertir y actualizar aplicaciones. Veamos cómo hacerlo.

Cómo usar Helm para desplegar sus propias aplicaciones
Instalaremos el cliente Helm en la computadora, siguiendo el oficial . Luego crearemos un conjunto de archivos YAML. En lugar de especificar valores concretos, dejaremos marcadores de posición que Helm llenará con información en el futuro. Este conjunto de archivos se llama chart de Helm. Se puede enviar al cliente de consola de Helm de tres maneras:
- especificar la carpeta con las plantillas;
- empaquetar en un archivo .tar y referenciarlo;
- colocar la plantilla en un repositorio remoto y agregar un enlace al repositorio en el cliente de Helm.
También se necesita un archivo de valores — values.yaml. Los datos de allí se insertarán en la plantilla. Vamos a crearlo.

En la segunda versión de Helm hay una aplicación de servidor adicional — Tiller. Esta se ejecuta fuera de Kubernetes y espera solicitudes del cliente de Helm, y al ser invocada, inserta los valores necesarios en la plantilla y los envía a Kubernetes.

Helm 3 es más simple: en lugar de procesar las plantillas en el servidor, la información ahora se procesa completamente del lado del cliente de Helm y se envía directamente a la API de Kubernetes. Esta simplificación aumenta la seguridad del clúster y facilita el proceso de despliegue.
Cómo funciona todo esto
Ejecutamos el comando helm install. Especificaremos el nombre de la liberación de la aplicación, daremos la ruta a values.yaml. Al final, indicaremos el repositorio donde se encuentra el chart y el nombre del chart. En el ejemplo, esto es «lmru» y «bestchart» respectivamente.
helm install --name bestapp --values values.yaml lmru/bestchart
La ejecución del comando solo es posible una vez, al ejecutarlo de nuevo en lugar de install debería utilizarse upgrade. Por simplicidad, en lugar de dos comandos, se puede ejecutar el comando upgrade con una clave adicional --install. Al ejecutar Helm por primera vez, enviará un comando para instalar la versión, y luego la actualizará.
helm upgrade --install bestapp --values values.yaml lmru/bestchart
Desafíos al desplegar nuevas versiones de la aplicación con Helm
En este punto de la historia, estoy jugando con la audiencia en '¿Quién quiere ser millonario?', y estamos tratando de averiguar cómo hacer que Helm actualice la versión de la aplicación. .
Cuando estuve estudiando el funcionamiento de Helm, me sorprendió el comportamiento extraño al intentar actualizar versiones de aplicaciones en ejecución. El código de la aplicación se actualizó, se subió una nueva imagen al registro de Docker, envié el comando para el despliegue – y no ocurrió nada. A continuación, algunos métodos no muy exitosos para actualizar aplicaciones. Al explorar cada uno de ellos más en detalle, comienzas a comprender la estructura interna de la herramienta y las razones de su comportamiento poco evidente.
Método 1. No cambiar la información desde el último lanzamiento
Como dice Helm, 'Los charts de Kubernetes pueden ser grandes y complejos, por lo que Helm intenta no tocar nada innecesariamente'. Por lo tanto, si actualizas la versión latest de la imagen de la aplicación en el registro de Docker y ejecutas el comando helm upgrade, no sucederá nada. Helm pensará que no ha habido cambios y no enviará el comando para actualizar la aplicación a Kubernetes.
Aquí y más adelante, la etiqueta latest se muestra únicamente como un ejemplo. Al especificar esta etiqueta, Kubernetes descargará la imagen del registro de Docker cada vez, independientemente del parámetro imagePullPolicy. Usar latest en producción es indeseable y puede causar efectos secundarios.
Método 2. Actualizar LABEL en la imagen
Como se indica en el mismo , 'Helm actualizará la aplicación solo si ha cambiado desde el último lanzamiento'. Una opción lógica para esto parecería ser actualizar la etiqueta LABEL en la propia imagen de Docker. Sin embargo, Helm no inspecciona las imágenes de las aplicaciones y no tiene conocimiento de ningún cambio en ellas. Por lo tanto, al actualizar las etiquetas en la imagen, Helm no se enterará, y no se enviará el comando para actualizar la aplicación en Kubernetes.
Método 3. Usar la opción --force

Consultemos los manuales y busquemos la opción que necesitamos. La que más se ajusta al significado es la opción --force. A pesar del nombre que tiene, el comportamiento es diferente de lo que se esperaba. En lugar de forzar la actualización de la aplicación, su verdadero propósito es restaurar una versión de estado FALLIDO. Si no se utiliza esta clave, es necesario ejecutar los comandos secuencialmente. helm delete && helm install --replace. En su lugar, se propone usar la clave --force, que automatiza la ejecución secuencial de estos comandos. Más información en este . Para decirle a Helm que actualice la versión de la aplicación, desafortunadamente, esta clave no servirá.
Método 4. Cambiar directamente las etiquetas en Kubernetes.

Actualizar la etiqueta directamente en el clúster usando el comando kubectl edit — es una mala idea. Esta acción llevará a una inconsistencia entre la información de la aplicación en funcionamiento y lo que originalmente se envió para el despliegue. El comportamiento de Helm al desplegar en este caso difiere de su versión: Helm 2 no hará nada, mientras que Helm 3 desplegará una nueva versión de la aplicación. Para entender la razón, es necesario comprender cómo funciona Helm.
Cómo funciona Helm.
Para determinar si la aplicación ha cambiado desde la última versión, Helm puede aprovechar:
- la aplicación en ejecución en Kubernetes;
- un nuevo values.yaml y el chart actual;
- información interna de Helm sobre las versiones.
Para los más curiosos: ¿dónde guarda Helm la información interna sobre las versiones?Al ejecutar el comando helm history, obtendremos toda la información sobre las versiones instaladas usando Helm.

También hay información detallada sobre las plantillas y valores enviados. Podemos solicitarla:

En la segunda versión de Helm, esta información se encuentra en el mismo namespace donde se ejecuta Tiller (por defecto, kube-system), en un ConfigMap marcado con la etiqueta "OWNER=TILLER":

Con la aparición de la tercera versión de Helm, la información se trasladó a los secretos, en el mismo namespace donde se ejecuta la aplicación. Gracias a esto, se volvió posible ejecutar varias aplicaciones simultáneamente en diferentes namespaces con el mismo nombre de versión. En la segunda versión, esto era un gran dolor de cabeza, ya que los namespaces están aislados, pero pueden influenciarse entre sí.

El segundo Helm, al intentar entender si necesita una actualización, utiliza únicamente dos fuentes de información: lo que se le proporcionó en ese momento y la información interna sobre las versiones, que reside en el ConfigMap.

El tercer Helm utiliza una estrategia de fusión en tres pasos: además de la información existente, considera también la aplicación que está funcionando en Kubernetes en este momento.

Por esta razón, la versión anterior de Helm no hará nada, ya que no tiene en cuenta la información de la aplicación en el clúster, mientras que Helm 3 recibirá los cambios y desplegará la nueva aplicación.
Método 5. Usar la clave --recreate-pods
Con la clave --recreate-pods se puede lograr lo que se pretendía alcanzar inicialmente con la clave --force. Los contenedores se reiniciarán y, de acuerdo con la política imagePullPolicy: Always para la etiqueta latest (de esto se habló en la nota anterior), Kubernetes descargará y ejecutará una nueva versión de la imagen. Esto no se llevará a cabo de la mejor manera: ignorando el StrategyType del despliegue, apagará repentinamente todas las instancias antiguas de la aplicación y comenzará a lanzar nuevas. Durante el reinicio, el sistema no funcionará y los usuarios sufrirán.
La misma problemática en Kubernetes también existió durante un largo periodo. Y así, después de 4 años desde la apertura de , el problema fue solucionado, y a partir de la versión 1.15 de Kubernetes se introdujo la posibilidad de reinicio continuo de pods.
Helm simplemente apaga todas las aplicaciones y lanza nuevos contenedores al lado. Esto no se puede hacer en producción para no provocar un tiempo de inactividad en la aplicación. Esto solo debe hacerse para propósitos de desarrollo, y se puede realizar solo en entornos de staging.
¿Cómo actualizar la versión de la aplicación utilizando Helm?
Vamos a cambiar los valores enviados a Helm. Por lo general, son los valores que se insertan en lugar de la etiqueta de la imagen. En el caso de latest, que se usa a menudo para entornos no productivos, la información modificable es una anotación que, para Kubernetes, es inútil, pero para Helm indicará la necesidad de actualizar la aplicación. Las opciones para completar el valor de la anotación son:
- Valor aleatorio usando la función estándar —
{{ randAlphaNum 6 }}.
Hay un matiz: después de cada despliegue utilizando un chart con esta variable, el valor de la anotación será único, y Helm asumirá que hay cambios. Por lo tanto, siempre estaremos reiniciando la aplicación, incluso si no hemos cambiado su versión. Esto no es crítico, ya que no habrá tiempo de inactividad, pero sigue siendo desagradable. - Insertar la fecha y hora actuales —
{{ .Release.Date }}.
Esta opción es similar al valor aleatorio, pero con una variable siempre única. - Una forma más correcta es utilizar sumas de verificación. Es el SHA de la imagen o el SHA del último commit en git —
{{ .Values.sha }}.
Deben ser calculadas y enviadas al cliente de Helm en el lado que llama, por ejemplo, en Jenkins. Si la aplicación cambia, la suma de verificación también cambiará. Por lo tanto, Helm actualizará la aplicación solo cuando sea necesario.
Resumamos nuestros intentos
- Helm realiza cambios de la manera menos invasiva, por lo que cualquier cambio a nivel de imagen de la aplicación en Docker Registry no resultará en una actualización: después de ejecutar el comando, no sucederá nada.
- Clave
--forcese utiliza para restaurar lanzamientos problemáticos y no está relacionado con una actualización forzada. - Clave
--recreate-podsactualizará forzosamente las aplicaciones, pero lo hará de manera perjudicial: apagará abruptamente todos los contenedores. Los usuarios se verán afectados, no se debe hacer esto en producción. - No se deben realizar cambios directamente en el clúster de Kubernetes con el comando
kubectl edit: romperemos la consistencia y el comportamiento variará según la versión de Helm. - Con el lanzamiento de una nueva versión de Helm han surgido muchos matices. Los temas en el repositorio de Helm están descritos en un lenguaje comprensible, ayudarán a entender los detalles.
- Agregar una anotación modificable al chart lo hará más flexible. Esto permitirá implementar la aplicación correctamente, sin tiempo de inactividad.
Un concepto del tipo 'paz en todo el mundo', que funciona en todas las áreas de la vida: lea las instrucciones antes de usar, no después. Solo con información completa se pueden construir sistemas confiables y hacer felices a los usuarios.
Otros enlaces sobre el tema:
Esta presentación se pronunció por primera vez en por Mail.ru Cloud Solutions. Vea otras presentaciones y suscríbase a los anuncios de eventos en Telegram .
Fuente: habr.com
