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

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

Nos complace anunciar que la empresa «Flant» está ampliando su contribución a las herramientas de código abierto para Kubernetes, lanzando la versión alfa del controlador CSI (Interfaz de Almacenamiento de Contenedores) para Yandex.Cloud.

Pero antes de entrar en los detalles de implementación, respondamos la pregunta: ¿por qué es necesario, si Yandex ya tiene el servicio Managed Service for Kubernetes.

Introducción

¿Por qué es esto?

Dentro de nuestra empresa, desde el comienzo de la explotación de Kubernetes en producción (es decir, ya hace varios años), hemos desarrollado una herramienta propia (deckhouse) que, por cierto, también planeamos hacer disponible como un proyecto de código abierto en el futuro cercano. Con ella, configuramos y ajustamos uniformemente todos nuestros clústeres, y en la actualidad ya son más de 100, utilizando diversas configuraciones de hardware y en todos los servicios en la nube disponibles.

Los clústeres que utilizan deckhouse tienen todos los componentes necesarios para su funcionamiento: balanceadores de carga, monitoreo con gráficos, métricas y alertas convenientes, autenticación de usuarios a través de proveedores externos para acceder a todos los dashboards, entre otros. No tiene sentido configurar un clúster 'mejorado' en una solución administrada, ya que a menudo esto es imposible o requerirá desactivar la mitad de los componentes.

NB: Esta es nuestra experiencia, y es bastante específica. De ninguna manera afirmamos que todos deban encargarse por su cuenta de implementar clústeres de Kubernetes en lugar de utilizar soluciones listas para usar. Por cierto, no tenemos experiencia real en la explotación de Kubernetes de Yandex y no vamos a emitir ningún juicio sobre este servicio en el presente artículo.

¿Qué es y para quién?

Así que ya hemos hablado sobre el enfoque moderno para el almacenamiento en Kubernetes: cómo está estructurado el CSI y cómo llegó la comunidad a este enfoque.

Actualmente, muchos grandes proveedores de servicios en la nube han desarrollado controladores para usar sus discos 'en la nube' como Volúmenes Persistentes en Kubernetes. Si un proveedor no tiene dicho controlador, pero ofrece todas las funciones necesarias a través de API, no hay nada que impida implementar un controlador por cuenta propia. Así fue como lo hicimos con Yandex.Cloud.

Basamos nuestro desarrollo en el controlador CSI para el cloud de DigitalOcean y algunas 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 tanto de GCP, como la de Yandex devuelven un objeto Operación para rastrear el estado de operaciones prolongadas (por ejemplo, la creación de un nuevo disco). Para interactuar con la API de Yandex.Cloud se utiliza Yandex.Cloud Go SDK.

El resultado del trabajo realizado se ha publicado en GitHub y puede ser útil para aquellos que, por alguna razón, utilizan una instalación propia de Kubernetes en máquinas virtuales de Yandex.Cloud (pero no un clúster gestionado listo para usar) y desean utilizar (solicitar) discos a través de CSI.

Implementación

Principales características

Por el momento, el controlador admite las siguientes funciones:

  • Solicitar discos en todas las zonas del clúster según la topología de los nodos en el clúster;
  • Eliminar discos solicitados anteriormente;
  • Redimensionamiento offline para discos (Yandex.Cloud no admite el aumento de los discos que están montados en la máquina virtual). Acerca de cómo se tuvo que modificar el controlador para realizar el redimensionamiento de la manera menos dolorosa posible, véase a continuación.

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

La principal dificultad y su superación

La falta de capacidad en la API de Yandex.Cloud para aumentar discos en tiempo real es una limitación que complica la operación de redimensionamiento para PV (Persistent Volume): porque en tal caso es necesario que el pod de la aplicación que utiliza el disco esté detenido, lo cual puede causar interrupción en la aplicación.

Según especificación CSI, si el controlador CSI informa que solo puede realizar el redimensionamiento de discos 'offline' (VolumeExpansion.OFFLINE), el proceso de aumento del disco debe llevarse a cabo de la siguiente manera:

Si el plugin solo tiene VolumeExpansion.OFFLINE capacidad de expansión y el volumen está actualmente publicado o disponible en un nodo, entonces ControllerExpandVolume DEBE ser llamado SOLO después de que:

  • El plugin tiene el controlador PUBLISH_UNPUBLISH_VOLUME capacidad y ControllerUnpublishVolume ha sido invocado con éxito.

O BIEN

  • El plugin NO tiene capacidad de controlador, el plugin tiene capacidad de nodo PUBLISH_UNPUBLISH_VOLUME STAGE_UNSTAGE_VOLUME y NodeUnstageVolume se ha completado con éxito. capacidad, ni nodo

O BIEN

  • El plugin NO tiene capacidad de controlador, el plugin tiene capacidad de nodo PUBLISH_UNPUBLISH_VOLUME NodeUnpublishVolume y NodeUnstageVolume se ha completado con éxito. En esencia, esto implica 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 de sidecars no cumple con estos requisitos: En el contenedor sidecar

  • csi-attacher , que debería ser responsable de asegurar el tiempo necesario entre los montajes, este funcionalidad simplemente no está implementada durante el redimensionamiento offline. La discusión sobre esto fue iniciada., que debe encargarse de mantener el intervalo necesario entre los montajes, ya que esta funcionalidad simplemente no está implementada durante el redimensionamiento offline. Se inició una discusión sobre esto aquí.
  • ¿Qué es exactamente un contenedor sidecar en este contexto? El plugin CSI en sí no interactúa con la API de Kubernetes, sino que solo responde a las llamadas gRPC que le envían los contenedores sidecar. Estos últimos son desarrollados por la comunidad de Kubernetes.

En nuestro caso (plugin CSI), la operación de aumentar el disco se presenta de la siguiente manera:

  1. Recibimos una llamada gRPC ControllerExpandVolume;
  2. Intentamos aumentar el disco en la API, pero recibimos un error de que no se puede realizar la operación, ya que el disco está montado;
  3. Guardamos el identificador del disco en un mapa que contiene los discos para los cuales se debe realizar la operación de aumento. Para abreviar, llamaremos a este mapa volumeResizeRequired;
  4. Eliminamos manualmente el pod que utiliza el disco. Kubernetes lo reiniciará. Para que el disco no se monte (ControllerPublishVolume) antes de que termine la operación de aumento durante el intento de montaje, verificamos que dicho disco aún esté en volumeResizeRequired y devolvemos un error;
  5. El controlador CSI intenta repetir la operación de redimensionamiento. Si la operación fue exitosa, eliminamos el disco de volumeResizeRequired;
  6. Dado que el identificador del disco no está presente en volumeResizeRequired, ControllerPublishVolume la operación se completa con éxito, el disco se monta, el pod se inicia.

Todo parece bastante simple, pero como siempre, hay trampas ocultas. El aumento de discos lo maneja external-resizer, que en caso de error al realizar la operación utiliza una cola con un aumento exponencial del tiempo de espera hasta 1000 segundos:

func DefaultControllerRateLimiter() RateLimiter {
  return NewMaxOfRateLimiter(
  NewItemExponentialFailureRateLimiter(5*time.Millisecond, 1000*time.Second),
  \/\/ 10 qps, 100 bucket size.  Esto es solo para la velocidad de reintento y es solo el factor general (no por elemento)
  &BucketRateLimiter{Limiter: rate.NewLimiter(rate.Limit(10), 100)},
  )
}

Esto puede llevar periódicamente a que la operación de aumento del disco se prolongue más de 15 minutos, y por lo tanto, a la indisponibilidad del pod correspondiente.

La única opción que nos permitió reducir fácilmente el tiempo de inactividad potencial fue usar nuestra propia versión de external-resizer con un límite máximo de tiempo de espera de 5 segundos:

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

No consideramos necesario iniciar urgentemente una discusión y parchear external-resizer, porque el redimensionamiento offline de discos es un vestigio que pronto desaparecerá en todos los proveedores de la nube.

¿Cómo empezar a usarlo?

El controlador es compatible con Kubernetes versión 1.15 y superior. Para el funcionamiento del controlador se deben cumplir los siguientes requisitos:

  • El flag --allow-privileged configurado en true para el servidor API y kubelet;
  • Activado --feature-gates=VolumeSnapshotDataSource=true,KubeletPluginsWatcher=true,CSINodeInfo=true,CSIDriverRegistry=true para el servidor API y kubelet;
  • La propagación de montaje (mount propagation) debe estar habilitada en el clúster. Al usar Docker, el demonio debe estar configurado de tal manera que se permitan los montajes compartidos (shared mounts).

Todos los pasos necesarios para la instalación se describen en README. La instalación implica la creación de objetos en Kubernetes a partir de manifestos.

Para que el controlador funcione, necesitarás lo siguiente:

  • Especificar en el manifiesto el ID del directorio (folder-id) de Yandex.Cloud (ve la documentación);
  • Para interactuar con la API de Yandex.Cloud en el controlador CSI se utiliza una cuenta de servicio. En el manifiesto Secret se deben proporcionar claves autorizadas de la cuenta de servicio. En la documentación descrito, cómo crear una cuenta de servicio y obtener las claves.

En resumen — prueba, y estaremos encantados de recibir tus comentarios y nuevos problemas, si te encuentras con algún problema!

Soporte adicional

Como conclusión, nos gustaría señalar que este controlador CSI no fue desarrollado por el deseo de experimentar escribiendo aplicaciones en Go, sino por la necesidad urgente dentro de la compañía. No nos parece razonable mantener nuestra propia implementación, por lo que, si Yandex muestra interés y decide continuar con el soporte del controlador, estaremos encantados de transferir el repositorio a su disposición.

Además, probablemente Yandex tenga su propia implementación del controlador CSI en el clúster Kubernetes administrado, que se puede liberar como Open Source. Esta opción de desarrollo también nos parece favorable: la comunidad podrá utilizar un controlador comprobado del proveedor de servicios, y no de una empresa externa.

P.D.

También puedes leer en nuestro blog:

Fuente: habr.com

Compra un hosting fiable para sitios web con protección contra DDoS, servidores VPS VDS 🔥 Compra un hosting fiable para sitios web con protección contra DDoS, servidores VPS VDS | ProHoster