Nuestra experiencia en el desarrollo de un controlador CSI en Kubernetes para Yandex.Cloud



Nos complace anunciar que la compañía Flant está reponiendo su contribución a las herramientas de código abierto de Kubernetes al lanzar una versión alfa del controlador CSI (Interfaz de almacenamiento de contenedores) para Yandex.Cloud.

Pero antes de pasar a los detalles de la implementación, responderemos a la pregunta de por qué esto es necesario cuando Yandex ya tiene el Servicio administrado para el servicio de Kubernetes .

Introducción


¿Por qué es esto?


Dentro de nuestra empresa, desde el comienzo de la operación de Kubernetes en producción (es decir, durante varios años), se está desarrollando nuestra propia herramienta (deckhouse), que, por cierto, también planeamos poner a disposición como un proyecto de Código Abierto en el futuro cercano. Con su ayuda, configuramos y configuramos de manera uniforme todos nuestros clústeres, y en este momento hay más de 100 de ellos, además, en las configuraciones de hardware más diversas y en todos los servicios en la nube disponibles.

Los clústeres en los que se utiliza deckhouse tienen todos los componentes necesarios para el trabajo: equilibradores, monitoreo con gráficos, métricas y alertas convenientes, autenticación de usuarios a través de proveedores externos para acceder a todos los paneles, etc. No tiene sentido poner un clúster "bombeado" en una solución administrada, ya que a menudo es imposible o dará lugar a la necesidad de desactivar la mitad de los componentes.

NB : Esta es nuestra experiencia, y es bastante específica. De ninguna manera afirmamos que todos deberían participar de manera independiente en la implementación del clúster de Kubernetes en lugar de utilizar soluciones ya preparadas. Por cierto, no tenemos experiencia real en la operación de Kubernetes de Yandex y no daremos ninguna evaluación de este servicio en este artículo.

¿Qué es y para quién?


Entonces, ya hablamos sobre el enfoque moderno del almacenamiento en Kubernetes: cómo funciona CSI y cómo la comunidad llegó a este enfoque.

Actualmente, muchos proveedores importantes de servicios en la nube han desarrollado controladores para usar sus unidades en la nube como un volumen persistente en Kubernetes. Si el proveedor no tiene dicho controlador, pero al mismo tiempo se proporcionan todas las funciones necesarias a través de la API, entonces nada le impide implementar el controlador por su cuenta. Y así sucedió con Yandex.Cloud.

Como base para el desarrollo, tomamos el controlador CSI para la nube DigitalOcean y un par de ideas del controlador para GCP , ya que la interacción con la API de estas nubes (Google y Yandex) tiene varias similitudes. En particular, la API yGCP y Yandex devuelven un objeto Operationpara rastrear el estado de las operaciones a largo plazo (por ejemplo, crear un nuevo disco). Para interactuar con la API Yandex.Cloud , se utiliza el SDK Yandex.Cloud Go .

El resultado del trabajo realizado se publica en GitHub y puede ser útil para aquellos que por alguna razón usan su propia instalación de Kubernetes en máquinas virtuales Yandex.Cloud (pero no un clúster administrado listo) y les gustaría usar (ordenar) discos a través de CSI.

Implementación


Características clave


Actualmente, el controlador admite las siguientes funciones:

  • Ordenar discos en todas las zonas del clúster de acuerdo con la topología de los nodos en el clúster;
  • Eliminar discos previamente ordenados;
  • Cambiar el tamaño de los discos sin conexión (Yandex. Cloud no admite el aumento de discos que se montan en una máquina virtual). Sobre cómo modificar el controlador para cambiar el tamaño de la manera más sencilla posible, vea a continuación.

En el futuro, está previsto implementar soporte para la creación y eliminación de discos de instantáneas.

La dificultad principal y su superación


La falta de la capacidad de expandir discos en tiempo real en la API Yandex.Cloud es una limitación que complica la operación de cambio de tamaño para PV (volumen persistente): en este caso, es necesario detener el pod de la aplicación que usa el disco, y esto puede causar una simple aplicaciones.

De acuerdo con la especificación CSI , si el controlador CSI informa que solo puede cambiar el tamaño de los discos "fuera de línea" ( VolumeExpansion.OFFLINE), entonces el proceso de aumentar el disco debería ser así:

Si el complemento solo tiene VolumeExpansion.OFFLINEcapacidad de expansión y el volumen está actualmente publicado o disponible en un nodo, ControllerExpandVolumeDEBE llamarse SOLO después de:

  • El complemento tiene PUBLISH_UNPUBLISH_VOLUMEcapacidad de controlador y ControllerUnpublishVolumese ha invocado con éxito.

SI NO

  • El complemento NO tiene PUBLISH_UNPUBLISH_VOLUMEcapacidad de controlador , el complemento tiene STAGE_UNSTAGE_VOLUMEcapacidad de nodo y NodeUnstageVolumese ha completado con éxito.

SI NO

  • El complemento NO tiene PUBLISH_UNPUBLISH_VOLUMEcapacidad de controlador , ni STAGE_UNSTAGE_VOLUMEcapacidad de nodo , y se NodeUnpublishVolumeha completado con éxito.

En esencia, esto significa la necesidad de desconectar el disco de la máquina virtual antes de aumentarlo.

Sin embargo, desafortunadamente, la implementación de la especificación CSI a través del sidecar no cumple con estos requisitos:

  • En el contenedor de sidecar csi-attacher, que debería ser responsable de la presencia del espacio necesario entre los montajes, esta funcionalidad simplemente no se implementa con el cambio de tamaño fuera de línea. Aquí se inició una discusión sobre esto .
  • ¿Qué es un contenedor de sidecar en este contexto? El complemento CSI en sí no interactúa con la API de Kubernetes, sino que solo responde a las llamadas de gRPC que los contenedores de sidecar le envían. Estos últimos están siendo desarrollados por la comunidad de Kubernetes.

En nuestro caso (complemento CSI), la operación para aumentar el disco es la siguiente:

  1. Recibimos una llamada de gRPC ControllerExpandVolume;
  2. Estamos intentando aumentar el disco en la API, pero tenemos un error sobre la imposibilidad de realizar la operación, ya que el disco está montado;
  3. Guardamos el identificador de disco en el mapa que contiene los discos para los que necesita realizar una operación de aumento. Además, por brevedad, llamaremos a este mapa como volumeResizeRequired;
  4. Elimine manualmente el pod que usa el disco. Kubernetes lo reiniciará. Para que el disco no tenga tiempo para montar ( ControllerPublishVolume) antes de completar la operación de aumento cuando intente montar, verificamos que este disco todavía está en funcionamiento volumeResizeRequiredy devuelve un error;
  5. El controlador CSI está intentando volver a ejecutar la operación de cambio de tamaño. Si la operación fue exitosa, elimine el disco de volumeResizeRequired;
  6. Porque falta el identificador de disco volumeResizeRequired, ControllerPublishVolumees exitoso, el disco está montado, el pod se inicia.

Todo parece bastante simple, pero como siempre hay dificultades. El redimensionador externo participa en la expansión del disco , que, en caso de error durante la operación, utiliza una cola con un aumento exponencial en el tiempo de espera de hasta 1000 segundos:

func DefaultControllerRateLimiter() RateLimiter {
  return NewMaxOfRateLimiter(
  NewItemExponentialFailureRateLimiter(5*time.Millisecond, 1000*time.Second),
  // 10 qps, 100 bucket size.  This is only for retry speed and its only the overall factor (not per item)
  &BucketRateLimiter{Limiter: rate.NewLimiter(rate.Limit(10), 100)},
  )
}

Esto puede llevar periódicamente al hecho de que la operación de aumentar el disco se alarga durante más de 15 minutos y, por lo tanto, la inaccesibilidad del pod correspondiente.

La única opción que nos permitió reducir el tiempo de inactividad potencial con bastante facilidad y sin dolor fue utilizar nuestra versión de redimensionador externo con un límite de tiempo de espera máximo de 5 segundos :

workqueue.NewItemExponentialFailureRateLimiter(5*time.Millisecond, 5*time.Second)

No consideramos necesario iniciar con urgencia una discusión y parchear el cambio de tamaño externo, porque los discos de cambio de tamaño sin conexión es un atavismo que pronto desaparecerá de todos los proveedores de la nube.

¿Cómo empezar a usar?


El controlador es compatible con Kubernetes versión 1.15 y superior. Para que el conductor funcione, se deben cumplir los siguientes requisitos:

  • El indicador se --allow-privilegedestablece en el valor truepara el servidor API y el kubelet;
  • Incluido --feature-gates=VolumeSnapshotDataSource=true,KubeletPluginsWatcher=true,CSINodeInfo=true,CSIDriverRegistry=truepara el servidor API y kubelet;
  • El montaje de propagación ( propagación de montaje ) debe incluirse en el clúster. Cuando se usa Docker, el demonio debe configurarse de modo que se permitan los montajes compartidos.

Todos los pasos necesarios para la instalación en sí se describen en README . La instalación es la creación de objetos en Kubernetes a partir de manifiestos.

Para que el controlador funcione, necesitará lo siguiente:

  • Indique el identificador del directorio de catálogo Yandex.Cloud ( folder-id) en el manifiesto ( consulte la documentación );
  • Para interactuar con la API Yandex.Cloud en el controlador CSI, se utiliza una cuenta de servicio. En el manifiesto secreto, debe pasar las claves autorizadas a la cuenta de servicio. La documentación describe cómo crear una cuenta de servicio y obtener las claves.

En general, pruébelo y estaremos encantados de recibir comentarios y nuevos problemas si encuentra algún problema.

Soporte adicional


Como resultado, nos gustaría señalar que implementamos este controlador CSI no por un gran deseo de divertirnos escribiendo aplicaciones en Go, sino por la necesidad urgente dentro de la empresa. No parece aconsejable apoyar nuestra propia implementación, por lo tanto, si Yandex muestra interés y decide continuar apoyando el controlador, con mucho gusto transferiremos el repositorio a su disposición.

Además, probablemente, Yandex en el clúster administrado de Kubernetes tiene su propia implementación del controlador CSI, que se puede lanzar en código abierto. Esta opción de desarrollo también nos parece favorable: la comunidad podrá utilizar el controlador comprobado del proveedor de servicios y no de una empresa de terceros.

PD


Lea también en nuestro blog:

Source: https://habr.com/ru/post/undefined/


All Articles