
Nos complace anunciar que la empresa «Flant» está ampliando su contribución a las herramientas de código abierto para Kubernetes, lanzando (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 .
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: y 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 y algunas ideas del , ya que la interacción con la API de estas nubes (Google y Yandex) tiene varias similitudes. En particular, la API tanto de , como la de 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 .
El resultado del trabajo realizado 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 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 , 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.OFFLINEcapacidad de expansión y el volumen está actualmente publicado o disponible en un nodo, entoncesControllerExpandVolumeDEBE ser llamado SOLO después de que:
- El plugin tiene el controlador
PUBLISH_UNPUBLISH_VOLUMEcapacidad yControllerUnpublishVolumeha sido invocado con éxito.O BIEN
- El plugin NO tiene capacidad de controlador, el plugin tiene capacidad de nodo
PUBLISH_UNPUBLISH_VOLUMESTAGE_UNSTAGE_VOLUMEyNodeUnstageVolumese ha completado con éxito.capacidad, ni nodoO BIEN
- El plugin NO tiene capacidad de controlador, el plugin tiene capacidad de nodo
PUBLISH_UNPUBLISH_VOLUMENodeUnpublishVolumeyNodeUnstageVolumese 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 . - ¿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 por la comunidad de Kubernetes.
En nuestro caso (plugin CSI), la operación de aumentar el disco se presenta de la siguiente manera:
- Recibimos una llamada gRPC
ControllerExpandVolume; - 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;
- 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; - 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é envolumeResizeRequiredy devolvemos un error; - El controlador CSI intenta repetir la operación de redimensionamiento. Si la operación fue exitosa, eliminamos el disco de
volumeResizeRequired; - Dado que el identificador del disco no está presente en
volumeResizeRequired,ControllerPublishVolumela 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 , que en caso de error al realizar la operación 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 :
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-privilegedconfigurado entruepara el servidor API y kubelet; - Activado
--feature-gates=VolumeSnapshotDataSource=true,KubeletPluginsWatcher=true,CSINodeInfo=true,CSIDriverRegistry=truepara el servidor API y kubelet; - La propagación de montaje () 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 . 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 (); - 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 de la cuenta de servicio. En la documentación , cómo crear una cuenta de servicio y obtener las claves.
En resumen — , y estaremos encantados de recibir tus comentarios y , 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
