Operador en Kubernetes para la gestión de clústeres de bases de datos. Vladislav Klimenko (Altinidad, 2019)

Operador en Kubernetes para la gestión de clústeres de bases de datos. Vladislav Klimenko (Altinidad, 2019)

El informe está dedicado a cuestiones prácticas sobre el desarrollo de un operador en Kubernetes, el diseño de su arquitectura y los principios operativos básicos.

En la primera parte del informe consideraremos:

  • ¿Qué es un operador en Kubernetes y por qué es necesario?
  • cómo el operador simplifica exactamente la gestión de sistemas complejos;
  • lo que el operador puede y no puede hacer.

A continuación, pasemos a analizar la estructura interna del operador. Veamos la arquitectura y el funcionamiento del operador paso a paso. Veámoslo en detalle:

  • interacción entre el operador y Kubernetes;
  • qué funciones asume el operador y qué funciones delega a Kubernetes.

Veamos la gestión de fragmentos y réplicas de bases de datos en Kubernetes.
A continuación, analizaremos los problemas de almacenamiento de datos:

  • cómo trabajar con Almacenamiento Persistente desde el punto de vista de un operador;
  • Riesgos del uso del almacenamiento local.

En la parte final del informe, consideraremos ejemplos prácticos de aplicación. operador-clickhouse de Amazon o Google Cloud Service. El informe se basa en el ejemplo de la experiencia de desarrollo y operación de un operador de ClickHouse.

Vídeo:

Mi nombre es Vladislav Klimenko. Hoy quería hablar sobre nuestra experiencia en el desarrollo y operación de un operador, y este es un operador especializado en la gestión de clusters de bases de datos. Por ejemplo Operador ClickHouse para administrar el clúster ClickHouse.

Operador en Kubernetes para la gestión de clústeres de bases de datos. Vladislav Klimenko (Altinidad, 2019)

¿Por qué tenemos la oportunidad de hablar sobre el operador y ClickHouse?

  • Apoyamos y desarrollamos ClickHouse.
  • En este momento estamos intentando contribuir poco a poco al desarrollo de ClickHouse. Y ocupamos el segundo lugar después de Yandex en términos de volumen de cambios realizados en ClickHouse.
  • Estamos intentando crear proyectos adicionales para el ecosistema ClickHouse.

Me gustaría contarles sobre uno de estos proyectos. Se trata del operador ClickHouse para Kubernetes.

En mi informe me gustaría abordar dos temas:

  • El primer tema es cómo funciona nuestro operador de gestión de bases de datos ClickHouse en Kubernetes.
  • El segundo tema es cómo funciona cualquier operador, es decir, cómo interactúa con Kubernetes.

Sin embargo, estas dos preguntas se cruzarán a lo largo de mi informe.

Operador en Kubernetes para la gestión de clústeres de bases de datos. Vladislav Klimenko (Altinidad, 2019)

¿A quién le interesaría escuchar lo que intento contar?

  • Será de gran interés para quienes operan operadores.
  • O para aquellos que quieran crear el suyo propio para comprender cómo funciona internamente, cómo interactúa el operador con Kubernetes y qué dificultades pueden surgir.

Operador en Kubernetes para la gestión de clústeres de bases de datos. Vladislav Klimenko (Altinidad, 2019)

Para comprender mejor lo que discutiremos hoy, es una buena idea saber cómo funciona Kubernetes y tener alguna capacitación básica en la nube.

Operador en Kubernetes para la gestión de clústeres de bases de datos. Vladislav Klimenko (Altinidad, 2019)

¿Qué es ClickHouse? Se trata de una base de datos en columnas con características específicas para el procesamiento en línea de consultas analíticas. Y es completamente de código abierto.

Y es importante para nosotros saber sólo dos cosas. Debes saber que se trata de una base de datos, por lo que lo que te diré será aplicable a casi cualquier base de datos. Y el hecho de que ClickHouse DBMS se escale muy bien proporciona una escalabilidad casi lineal. Y por tanto, el estado del clúster es un estado natural para ClickHouse. Y lo que más nos interesa es discutir cómo servir el clúster ClickHouse en Kubernetes.

Operador en Kubernetes para la gestión de clústeres de bases de datos. Vladislav Klimenko (Altinidad, 2019)

¿Por qué lo necesitan allí? ¿Por qué no podemos seguir utilizándolo nosotros mismos? Y las respuestas son en parte técnicas y en parte organizativas.

  • En la práctica, nos encontramos cada vez más con una situación en la que en las grandes empresas casi todos los componentes ya están en Kubernetes. Las bases de datos permanecen afuera.
  • Y cada vez más surge la pregunta: “¿Se puede colocar esto dentro?” Por ello, las grandes empresas están intentando conseguir la máxima unificación de la gestión para poder gestionar rápidamente sus almacenes de datos.
  • Y esto ayuda especialmente si necesita la máxima oportunidad de repetir lo mismo en un lugar nuevo, es decir, máxima portabilidad.

Operador en Kubernetes para la gestión de clústeres de bases de datos. Vladislav Klimenko (Altinidad, 2019)

¿Qué tan fácil o difícil es? Por supuesto, esto se puede hacer a mano. Pero no es tan simple, porque tenemos la complejidad añadida de gestionar el propio Kubernetes, pero al mismo tiempo se superponen las particularidades de ClickHouse. Y el resultado es tal agregación.

Y en conjunto, esto da como resultado un conjunto bastante grande de tecnologías, que se vuelve bastante difícil de administrar, porque Kubernetes pone en funcionamiento sus propios problemas cotidianos y ClickHouse trae sus propios problemas al funcionamiento cotidiano. Sobre todo si tenemos varias ClickHouses y necesitamos hacer algo con ellas constantemente.

Operador en Kubernetes para la gestión de clústeres de bases de datos. Vladislav Klimenko (Altinidad, 2019)

Con una configuración dinámica, ClickHouse tiene una cantidad bastante grande de problemas que crean una carga constante en DevOps:

  • Cuando queremos cambiar algo en ClickHouse, por ejemplo, agregar una réplica o un fragmento, entonces debemos administrar la configuración.
  • Luego cambie el esquema de datos, porque ClickHouse tiene un método de fragmentación específico. Allí debe diseñar el diagrama de datos, diseñar las configuraciones.
  • Necesita configurar el monitoreo.
  • Recopilación de registros para nuevos fragmentos y nuevas réplicas.
  • Ocúpate de la restauración.
  • Y reiniciar.

Estas son tareas rutinarias que realmente me gustaría que fueran más fáciles de usar.

Operador en Kubernetes para la gestión de clústeres de bases de datos. Vladislav Klimenko (Altinidad, 2019)

El propio Kubernetes ayuda bien en el funcionamiento, pero en aspectos básicos del sistema.

Kubernetes es bueno para facilitar y automatizar cosas como:

  • Recuperación.
  • Reiniciar.
  • Gestión del sistema de almacenamiento.

Eso es bueno, esa es la dirección correcta, pero no tiene ni idea de cómo operar un grupo de bases de datos.

Queremos más, queremos que toda la base de datos funcione en Kubernetes.

Operador en Kubernetes para la gestión de clústeres de bases de datos. Vladislav Klimenko (Altinidad, 2019)

Me gustaría tener algo así como un botón rojo mágico grande que al presionarlo se implemente y mantenga un clúster con tareas cotidianas que deben resolverse durante todo su ciclo de vida. Clúster ClickHouse en Kubernetes.

Y tratamos de crear una solución que ayudara a facilitar el trabajo. Este es un operador ClickHouse para Kubernetes de Altinity.

Operador en Kubernetes para la gestión de clústeres de bases de datos. Vladislav Klimenko (Altinidad, 2019)

Un operador es un programa cuya tarea principal es gestionar otros programas, es decir, es un administrador.

Y contiene patrones de comportamiento. Puede llamar a esto conocimiento codificado sobre el área temática.

Y su tarea principal es hacer la vida de DevOps más fácil y reducir la microgestión, para que él (DevOps) ya piense en términos de alto nivel, es decir, para que él (DevOps) no se dedique a la microgestión, para que no configure. todos los detalles manualmente.

Y solo el operador es un asistente robótico que se ocupa de microtareas y ayuda a DevOps.

Operador en Kubernetes para la gestión de clústeres de bases de datos. Vladislav Klimenko (Altinidad, 2019)

¿Por qué necesitas un operador? Se desempeña particularmente bien en dos áreas:

  • Cuando el especialista que trabaja con ClickHouse no tiene suficiente experiencia, pero ya necesita operar ClickHouse, el operador facilita la operación y le permite operar un clúster de ClickHouse con una configuración bastante compleja, sin entrar en demasiados detalles sobre cómo funciona todo. adentro. Simplemente le das tareas de alto nivel y funciona.
  • Y la segunda tarea en la que se desempeña mejor es cuando es necesario automatizar una gran cantidad de tareas típicas. Elimina microtareas de los administradores del sistema.

Operador en Kubernetes para la gestión de clústeres de bases de datos. Vladislav Klimenko (Altinidad, 2019)

Esto es más necesario para aquellos que recién están comenzando su viaje o para aquellos que necesitan mucha automatización.

Operador en Kubernetes para la gestión de clústeres de bases de datos. Vladislav Klimenko (Altinidad, 2019)

¿En qué se diferencia el enfoque basado en operadores de otros sistemas? Ahí está Yelmo. También ayuda instalar ClickHouse; puede dibujar gráficos de timón, que incluso instalarán un clúster ClickHouse completo. ¿Cuál es entonces la diferencia entre el operador y el mismo, por ejemplo, Helm?

La principal diferencia fundamental es que Helm es gestión de paquetes y Operador va un paso más allá. Este es un soporte para todo el ciclo de vida. Esto no es solo instalación, son tareas cotidianas que incluyen escalado, fragmentación, es decir, todo lo que debe hacerse durante el ciclo de vida (si es necesario, luego también eliminarlo); todo esto lo decide el operador. Intenta automatizar y mantener todo el ciclo de vida del software. Ésta es su diferencia fundamental con otras soluciones que se presentan.

Operador en Kubernetes para la gestión de clústeres de bases de datos. Vladislav Klimenko (Altinidad, 2019)

Esa fue la parte introductoria, sigamos adelante.

¿Cómo construimos nuestro operador? Estamos intentando abordar el problema de gestionar el clúster de ClickHouse como un recurso único.

Aquí tenemos datos de entrada en el lado izquierdo de la imagen. Este es YAML con una especificación de clúster, que se pasa a Kubernetes de la forma clásica a través de kubectl. Allí nuestro operador lo recoge y hace su magia. Y en la salida obtenemos el siguiente esquema. Esta es una implementación de ClickHouse en Kubernetes.

Y luego veremos lentamente cómo trabaja exactamente el operador, qué tareas típicas se pueden resolver. Solo consideraremos tareas típicas porque tenemos tiempo limitado. Y no se discutirá todo lo que el operador pueda decidir.

Operador en Kubernetes para la gestión de clústeres de bases de datos. Vladislav Klimenko (Altinidad, 2019)

Empecemos por la práctica. Nuestro proyecto es completamente de código abierto, por lo que puedes ver cómo funciona en GitHub. Y puede partir de la consideración de que si solo desea iniciarlo, puede comenzar con la Guía de inicio rápido.

Si desea comprenderlo en detalle, intentamos mantener la documentación en una forma más o menos decente.

Operador en Kubernetes para la gestión de clústeres de bases de datos. Vladislav Klimenko (Altinidad, 2019)

Comencemos con un problema práctico. La primera tarea, donde todos queremos comenzar, es ejecutar el primer ejemplo de alguna manera. ¿Cómo puedo iniciar ClickHouse usando el operador, incluso si no sé realmente cómo funciona? Estamos escribiendo un manifiesto, porque... Toda comunicación con k8 es comunicación a través de manifiestos.

Operador en Kubernetes para la gestión de clústeres de bases de datos. Vladislav Klimenko (Altinidad, 2019)

Este es un manifiesto muy complejo. Lo que hemos resaltado en rojo es en lo que debemos centrarnos. Le pedimos al operador que cree un clúster llamado demo.

Estos son ejemplos básicos por ahora. El almacenamiento aún no se ha descrito, pero volveremos a él un poco más tarde. Por ahora, observaremos la dinámica del desarrollo del cluster.

Creamos este manifiesto. Se lo entregamos a nuestro operador. Trabajó, hizo magia.

Operador en Kubernetes para la gestión de clústeres de bases de datos. Vladislav Klimenko (Altinidad, 2019)

Miramos la consola. Son de interés tres componentes: un Pod, dos Servicios y un StatefulSet.

El operador ha trabajado y podemos ver qué creó exactamente.

Operador en Kubernetes para la gestión de clústeres de bases de datos. Vladislav Klimenko (Altinidad, 2019)

Él crea algo como esto. Tenemos un StatefulSet, Pod, ConfigMap para cada réplica y ConfigMap para todo el clúster. Los servicios son necesarios como puntos de entrada al clúster.

Los servicios son el servicio central de Load Balancer y también se pueden usar para cada réplica, para cada fragmento.

Nuestro grupo básico se parece a esto. Es de un solo nodo.

Operador en Kubernetes para la gestión de clústeres de bases de datos. Vladislav Klimenko (Altinidad, 2019)

Vayamos más allá y compliquemos las cosas. Necesitamos fragmentar el clúster.

Operador en Kubernetes para la gestión de clústeres de bases de datos. Vladislav Klimenko (Altinidad, 2019)

Nuestras tareas crecen, comienza la dinámica. Queremos agregar un fragmento. Seguimos el desarrollo. Estamos cambiando nuestra especificación. Indicamos que queremos dos fragmentos.

Este es el mismo archivo que se desarrolla dinámicamente con el crecimiento del sistema. Almacenamiento no, el almacenamiento se discutirá más a fondo, este es un tema aparte.

Alimentamos al operador YAML y vemos qué sucede.

Operador en Kubernetes para la gestión de clústeres de bases de datos. Vladislav Klimenko (Altinidad, 2019)

El operador pensó e hizo las siguientes entidades. Ya tenemos dos Pods, tres Servicios y, de repente, 2 StatefulSets. ¿Por qué 2 StatefulSets?

Operador en Kubernetes para la gestión de clústeres de bases de datos. Vladislav Klimenko (Altinidad, 2019)

En el diagrama era así: este es nuestro estado inicial, cuando teníamos una cápsula.

Operador en Kubernetes para la gestión de clústeres de bases de datos. Vladislav Klimenko (Altinidad, 2019)

Se volvió así. Hasta ahora todo es sencillo, está duplicado.

Operador en Kubernetes para la gestión de clústeres de bases de datos. Vladislav Klimenko (Altinidad, 2019)

¿Y por qué surgieron dos StatefulSets? Aquí debemos hacer una digresión y discutir la cuestión de cómo se gestionan los Pods en Kubernetes.

Hay un objeto llamado StatefulSet que te permite crear un conjunto de Pods a partir de una plantilla. El factor clave aquí es la plantilla. Y puedes iniciar muchos Pods usando una plantilla en un StatefulSet. Y la frase clave aquí es "muchos Pods para una plantilla".

Y surgió la gran tentación de crear el clúster completo, empaquetándolo en un StatefulSet. Funcionará, no hay ningún problema con ello. Pero hay una advertencia. Si queremos montar un cluster heterogéneo, es decir, a partir de varias versiones de ClickHouse, entonces empiezan a surgir dudas. Sí, StatefulSet puede realizar una actualización continua y allí puede implementar una nueva versión; explique que no necesita probar más de tantos nodos al mismo tiempo.

Pero si extrapolamos la tarea y decimos que queremos crear un clúster completamente heterogéneo y no queremos cambiar de la versión anterior a una nueva mediante una actualización continua, sino que simplemente queremos crear un clúster heterogéneo tanto en términos de diferentes versiones de ClickHouse y en términos de diferente almacenamiento. Queremos, por ejemplo, hacer algunas réplicas en discos separados, en discos lentos, en general, para construir un clúster completamente heterogéneo. Y debido al hecho de que StatefulSet crea una solución estandarizada a partir de una plantilla, no hay forma de hacerlo.

Después de pensarlo un poco, decidimos que lo haríamos de esta manera. Tenemos cada réplica en su propio StatefulSet. Esta solución tiene algunos inconvenientes, pero en la práctica todo está completamente encapsulado por el operador. Y hay muchas ventajas. Podemos construir el cluster exacto que queramos, por ejemplo uno absolutamente heterogéneo. Por lo tanto, en un clúster en el que tenemos dos fragmentos con una réplica, tendremos 2 StatefulSets y 2 Pods precisamente porque elegimos este enfoque por las razones expuestas anteriormente para poder construir un clúster heterogéneo.

Operador en Kubernetes para la gestión de clústeres de bases de datos. Vladislav Klimenko (Altinidad, 2019)

Volvamos a los problemas prácticos. En nuestro cluster necesitamos configurar usuarios, es decir necesita realizar alguna configuración de ClickHouse en Kubernetes. El operador ofrece todas las posibilidades para ello.

Operador en Kubernetes para la gestión de clústeres de bases de datos. Vladislav Klimenko (Altinidad, 2019)

Podemos escribir lo que queramos directamente en YAML. Todas las opciones de configuración se asignan directamente desde este YAML a las configuraciones de ClickHouse, que luego se distribuyen por todo el clúster.

Puedes escribirlo así. Esto es por ejemplo. La contraseña se puede cifrar. Se admiten absolutamente todas las opciones de configuración de ClickHouse. Aquí hay sólo un ejemplo.

La configuración del clúster se distribuye como ConfigMap. En la práctica, la actualización de ConfigMap no ocurre instantáneamente, por lo que si el clúster es grande, el proceso de impulsar la configuración lleva algún tiempo. Pero todo esto es muy cómodo de usar.

Operador en Kubernetes para la gestión de clústeres de bases de datos. Vladislav Klimenko (Altinidad, 2019)

Compliquemos la tarea. El grupo se está desarrollando. Queremos replicar datos. Es decir, ya tenemos dos shards, una réplica cada uno, y los usuarios están configurados. Estamos creciendo y queremos replicar.

Operador en Kubernetes para la gestión de clústeres de bases de datos. Vladislav Klimenko (Altinidad, 2019)

¿Qué necesitamos para la replicación?

Necesitamos ZooKeeper. En ClickHouse, la replicación se crea utilizando ZooKeeper. ZooKeeper es necesario para que las diferentes réplicas de ClickHouse tengan un consenso sobre qué bloques de datos se encuentran en cada ClickHouse.

Cualquiera puede utilizar ZooKeeper. Si la empresa tiene un ZooKeeper externo, entonces se puede utilizar. Si no, puedes instalarlo desde nuestro repositorio. Hay un instalador que facilita todo esto.

Operador en Kubernetes para la gestión de clústeres de bases de datos. Vladislav Klimenko (Altinidad, 2019)

Y el diagrama de interacción de todo el sistema resulta así. Tenemos Kubernetes como plataforma. Ejecuta el operador ClickHouse. Me imaginé a ZooKeeper aquí. Y el operador interactúa tanto con ClickHouse como con ZooKeeper. Es decir, resultados de interacción.

Y todo esto es necesario para que ClickHouse pueda replicar datos con éxito en k8s.

Operador en Kubernetes para la gestión de clústeres de bases de datos. Vladislav Klimenko (Altinidad, 2019)

Veamos ahora la tarea en sí, cómo se verá el manifiesto para la replicación.

Estamos agregando dos secciones a nuestro manifiesto. La primera es dónde conseguir ZooKeeper, que puede ser dentro de Kubernetes o externo. Esto es sólo una descripción. Y encargamos réplicas. Aquellos. Queremos dos réplicas. En total, deberíamos tener 4 pods en la salida. Recordamos el almacenamiento, volveremos un poco más tarde. El almacenamiento es una historia aparte.

Operador en Kubernetes para la gestión de clústeres de bases de datos. Vladislav Klimenko (Altinidad, 2019)

Fue así.

Operador en Kubernetes para la gestión de clústeres de bases de datos. Vladislav Klimenko (Altinidad, 2019)

Se vuelve así. Se añaden réplicas. El 4º no encajaba, creemos que podría haber muchos allí. Y ZooKeeper se agrega al costado. Los esquemas son cada vez más complejos.

Operador en Kubernetes para la gestión de clústeres de bases de datos. Vladislav Klimenko (Altinidad, 2019)

Y es hora de agregar la siguiente tarea. Agregaremos almacenamiento persistente.

Operador en Kubernetes para la gestión de clústeres de bases de datos. Vladislav Klimenko (Altinidad, 2019)Para el Almacenamiento Persistente tenemos varias opciones.

Si trabajamos con un proveedor de nube, por ejemplo, usando Amazon, Google, entonces existe una gran tentación de utilizar el almacenamiento en la nube. Es muy conveniente, es bueno.

Y hay una segunda opción. Esto es para almacenamiento local, cuando tenemos discos locales en cada nodo. Esta opción es mucho más difícil de implementar, pero al mismo tiempo es más productiva.

Operador en Kubernetes para la gestión de clústeres de bases de datos. Vladislav Klimenko (Altinidad, 2019)

Veamos qué tenemos respecto al almacenamiento en la nube.

Hay ventajas. Es muy fácil de configurar. Simplemente pedimos al proveedor de la nube que nos brinde almacenamiento de tal o cual capacidad, de tal o cual clase. Las clases las programan los proveedores de forma independiente.

Y hay un inconveniente. Para algunos, este es un inconveniente que no es crítico. Por supuesto, habrá algunos problemas de rendimiento. Es muy cómodo de usar y fiable, pero existen algunos posibles inconvenientes de rendimiento.

Operador en Kubernetes para la gestión de clústeres de bases de datos. Vladislav Klimenko (Altinidad, 2019)

Y porqué ClickHouse se centra específicamente en la productividad, incluso se podría decir que exprime todo lo que puede, razón por la cual muchos clientes intentan exprimir la máxima productividad.

Operador en Kubernetes para la gestión de clústeres de bases de datos. Vladislav Klimenko (Altinidad, 2019)

Y para aprovecharlo al máximo, necesitamos almacenamiento local.

Kubernetes proporciona tres abstracciones para utilizar el almacenamiento local en Kubernetes. Este:

  • VacíoDir
  • Ruta de host.
  • Local

Veamos en qué se diferencian y en qué se parecen.

En primer lugar, en los tres enfoques tenemos almacenamiento: son discos locales que se encuentran en el mismo nodo físico de k8s. Pero tienen algunas diferencias.

Operador en Kubernetes para la gestión de clústeres de bases de datos. Vladislav Klimenko (Altinidad, 2019)

Comencemos con el más simple, es decir, vacíoDir. ¿Qué es esto en la práctica? En nuestra especificación, le pedimos al sistema de contenedorización (normalmente Docker) que nos proporcione acceso a una carpeta en el disco local.

En la práctica, Docker crea una carpeta temporal en algún lugar de sus propias rutas y la llama hash largo. Y proporciona una interfaz para acceder a él.

¿Cómo funcionará esto en términos de rendimiento? Esto funcionará a la velocidad del disco local, es decir. Este es acceso completo a su tornillo.

Pero este caso tiene su inconveniente. Persistent es bastante dudoso en este asunto. La primera vez que Docker se mueve con contenedores, se pierde Persistent. Si Kubernetes quiere mover este Pod a otro disco por algún motivo, los datos se perderán.

Este enfoque es bueno para las pruebas, porque ya muestra una velocidad normal, pero para algo serio esta opción no es adecuada.

Operador en Kubernetes para la gestión de clústeres de bases de datos. Vladislav Klimenko (Altinidad, 2019)

Por tanto, existe un segundo enfoque. Esta es la ruta del host. Si miras la diapositiva anterior y esta, solo podrás ver una diferencia. Nuestra carpeta se movió de Docker directamente al nodo de Kubernetes. Es un poco más sencillo aquí. Especificamos directamente la ruta en el sistema de archivos local donde nos gustaría almacenar nuestros datos.

Este método tiene ventajas. Este ya es un Persistente real y, además, un clásico. Tendremos datos grabados en el disco en alguna dirección.

También hay desventajas. Ésta es la complejidad de la gestión. Es posible que nuestro Kubernetes quiera mover el Pod a otro nodo físico. Y aquí es donde entra en juego DevOps. Debe explicar correctamente a todo el sistema que estos pods solo se pueden mover a aquellos nodos en los que haya algo montado a lo largo de estas rutas, y no más de un nodo a la vez. Es bastante difícil.

Especialmente para estos fines, creamos plantillas en nuestro operador para ocultar toda esta complejidad. Y podría simplemente decir: "Quiero tener una instancia de ClickHouse para cada nodo físico y a lo largo de tal o cual ruta".

Operador en Kubernetes para la gestión de clústeres de bases de datos. Vladislav Klimenko (Altinidad, 2019)

Pero no somos los únicos que necesitamos esta necesidad, por lo que los señores de Kubernetes también entienden que la gente quiere tener acceso a discos físicos, por lo que proporcionan una tercera capa.

Se llama local. Prácticamente no hay diferencia con la diapositiva anterior. Solo antes era necesario confirmar manualmente que no podemos transferir estos pods de un nodo a otro, porque deben estar conectados a lo largo de alguna ruta a un disco físico local, pero ahora todo este conocimiento está encapsulado en el propio Kubernetes. Y resulta mucho más fácil de configurar.

Operador en Kubernetes para la gestión de clústeres de bases de datos. Vladislav Klimenko (Altinidad, 2019)

Volvamos a nuestro problema práctico. Volvamos a la plantilla YAML. Aquí tenemos almacenamiento real. Estamos de vuelta en eso. Configuramos la plantilla clásica VolumeClaim como en k8s. Y describimos qué tipo de almacenamiento queremos.

Después de esto, k8s solicitará almacenamiento. Nos lo asignará en StatefulSet. Y al final quedará a disposición de ClickHouse.

Operador en Kubernetes para la gestión de clústeres de bases de datos. Vladislav Klimenko (Altinidad, 2019)

Teníamos este esquema. Nuestro almacenamiento persistente estaba en rojo, lo que parecía indicar que era necesario hacerlo.

Operador en Kubernetes para la gestión de clústeres de bases de datos. Vladislav Klimenko (Altinidad, 2019)

Y se pone verde. Ahora el esquema de clúster ClickHouse en k8s está completamente finalizado. Tenemos fragmentos, réplicas, ZooKeeper, tenemos un Persistente real, que se implementa de una forma u otra. El plan ya está en pleno funcionamiento.

Operador en Kubernetes para la gestión de clústeres de bases de datos. Vladislav Klimenko (Altinidad, 2019)

Seguimos viviendo. Nuestro cluster se está desarrollando. Y Alexey lo intenta y lanza una nueva versión de ClickHouse.

Surge una tarea práctica: probar la nueva versión de ClickHouse en nuestro clúster. Y, naturalmente, no querrás implementarlo todo; querrás poner una nueva versión en una réplica en algún lugar del rincón más alejado, y tal vez no una nueva versión, sino dos a la vez, porque salen con frecuencia.

¿Qué podemos decir sobre esto?

Operador en Kubernetes para la gestión de clústeres de bases de datos. Vladislav Klimenko (Altinidad, 2019)

Aquí tenemos precisamente esa oportunidad. Estas son plantillas de pods. Puede escribir que nuestro operador le permite construir un clúster heterogéneo. Aquellos. configure, comenzando con todas las réplicas en un grupo y terminando con cada réplica personal, qué versión queremos de ClickHouse, qué versión queremos de almacenamiento. Podemos configurar completamente el cluster con la configuración que necesitemos.

Operador en Kubernetes para la gestión de clústeres de bases de datos. Vladislav Klimenko (Altinidad, 2019)

Profundicemos un poco más en nuestro interior. Antes de esto, hablamos sobre cómo funciona el operador ClickHouse en relación con las características específicas de ClickHouse.

Ahora me gustaría decir algunas palabras sobre cómo funciona cualquier operador en general, así como cómo interactúa con los K8.

Operador en Kubernetes para la gestión de clústeres de bases de datos. Vladislav Klimenko (Altinidad, 2019)

Primero veamos la interacción con los K8. ¿Qué sucede cuando aplicamos kubectl? Nuestros objetos aparecen en etcd a través de la API.

Operador en Kubernetes para la gestión de clústeres de bases de datos. Vladislav Klimenko (Altinidad, 2019)

Por ejemplo, objetos básicos de Kubernetes: pod, StatefulSet, servicio, etc. en la lista.

Al mismo tiempo, todavía no ocurre nada físico. Estos objetos deben materializarse en el cluster.

Operador en Kubernetes para la gestión de clústeres de bases de datos. Vladislav Klimenko (Altinidad, 2019)

Para ello aparece un controlador. El controlador es un componente especial de k8s que puede materializar estas descripciones. Él sabe cómo y qué hacer físicamente. Sabe cómo ejecutar contenedores, qué se debe configurar allí para que el servidor funcione.

Operador en Kubernetes para la gestión de clústeres de bases de datos. Vladislav Klimenko (Altinidad, 2019)

Y materializa nuestros objetos en K8.

Pero no solo queremos operar con pods y StatefulSets, queremos crear un ClickHouseInstallation, es decir, un objeto del tipo ClickHouse, para poder operar con él como un todo. Hasta el momento no existe tal posibilidad.

Operador en Kubernetes para la gestión de clústeres de bases de datos. Vladislav Klimenko (Altinidad, 2019)

Pero el K8 tiene las siguientes ventajas. Queremos que tengamos un lugar como esta entidad compleja en la que nuestro clúster se ensamblaría a partir de pods y StatefulSet.

Operador en Kubernetes para la gestión de clústeres de bases de datos. Vladislav Klimenko (Altinidad, 2019)

¿Y qué hay que hacer para esto? En primer lugar, la definición de recursos personalizados entra en escena. ¿Lo que es? Esta es una descripción para K8, que tendrá un tipo de datos más, que queremos agregar un recurso personalizado al pod, StatefulSet, que será complejo por dentro. Esta es una descripción de la estructura de datos.

Operador en Kubernetes para la gestión de clústeres de bases de datos. Vladislav Klimenko (Altinidad, 2019)

También lo enviamos allí vía kubectl apply. Kubernetes lo aceptó felizmente.

Y ahora en nuestro almacenamiento, el objeto en etcd tiene la capacidad de registrar un recurso personalizado llamado ClickHouseInstallation.

Pero por ahora no pasará nada más. Es decir, si ahora creamos el archivo YAML que vimos que describe fragmentos y réplicas y decimos "kubectl apply", entonces Kubernetes lo aceptará, lo pondrá en etcd y dirá: "Genial, pero no sé qué hacer". con eso. No sé cómo mantener ClickHouseInstallation”.

Operador en Kubernetes para la gestión de clústeres de bases de datos. Vladislav Klimenko (Altinidad, 2019)

En consecuencia, necesitamos a alguien que ayude a Kubernetes a servir el nuevo tipo de datos. A la izquierda tenemos un controlador Kubernetes nativo que funciona con tipos de datos nativos. Y a la derecha deberíamos tener un controlador personalizado que pueda funcionar con tipos de datos personalizados.

Y de otra forma se le llama operador. Lo incluí específicamente aquí como Kubernetes, porque también se puede ejecutar fuera de K8. La mayoría de las veces, por supuesto, todos los operadores se ejecutan en Kubernetes, pero nada le impide permanecer afuera, por lo que aquí se mueve especialmente afuera.

Operador en Kubernetes para la gestión de clústeres de bases de datos. Vladislav Klimenko (Altinidad, 2019)

Y a su vez, el controlador personalizado, también conocido como operador, interactúa con Kubernetes a través de la API. Ya sabe cómo interactuar con la API. Y ya sabe cómo materializar el complejo circuito que queremos realizar a partir de un recurso personalizado. Esto es exactamente lo que hace el operador.

Operador en Kubernetes para la gestión de clústeres de bases de datos. Vladislav Klimenko (Altinidad, 2019)

¿Cómo trabaja el operador? Miremos el lado derecho para ver cómo lo hace. Averigüemos cómo el operador materializa todo esto y cómo se produce la interacción adicional con los K8.

Operador en Kubernetes para la gestión de clústeres de bases de datos. Vladislav Klimenko (Altinidad, 2019)

Un operador es un programa. Está orientada a los eventos. El operador se suscribe a eventos mediante la API de Kubernetes. La API de Kubernetes tiene puntos de entrada donde puedes suscribirte a eventos. Y si algo cambia en los K8, Kubernetes envía eventos a todos, es decir, Quien se haya suscrito a este punto API recibirá notificaciones.

El operador se suscribe a los eventos y debe realizar algún tipo de reacción. Su tarea es responder a los acontecimientos emergentes.

Operador en Kubernetes para la gestión de clústeres de bases de datos. Vladislav Klimenko (Altinidad, 2019)

Los eventos son generados por ciertas actualizaciones. Llega nuestro archivo YAML con una descripción de ClickHouseInstallation. Fue a etcd a través de kubectl apply. Allí se activó un evento y, como resultado, este evento llegó al operador de ClickHouse. El operador recibió esta descripción. Y debe hacer algo. Si llegó una actualización para el objeto ClickHouseInstallation, entonces debe actualizar el clúster. Y la tarea del operador es actualizar el clúster.

Operador en Kubernetes para la gestión de clústeres de bases de datos. Vladislav Klimenko (Altinidad, 2019)

¿Qué está haciendo? Primero, debemos elaborar un plan de acción sobre lo que haremos con esta actualización. Las actualizaciones pueden ser muy pequeñas, es decir. pequeño en la ejecución de YAML, pero puede implicar cambios muy grandes en el clúster. Por lo tanto, el operador crea un plan y luego lo cumple.

Operador en Kubernetes para la gestión de clústeres de bases de datos. Vladislav Klimenko (Altinidad, 2019)

Según este plan, comienza a cocinar esta estructura en su interior para materializar vainas, servicios, es decir. hacer cuál es su tarea principal. Así es como se construye un clúster de ClickHouse en Kubernetes.

Operador en Kubernetes para la gestión de clústeres de bases de datos. Vladislav Klimenko (Altinidad, 2019)

Ahora toquemos algo tan interesante. Esta es una división de responsabilidad entre Kubernetes y el operador, es decir. qué hace Kubernetes, qué hace el operador y cómo interactúan entre sí.

Kubernetes es responsable de las cosas del sistema, es decir. para un conjunto básico de objetos que pueden interpretarse como de alcance del sistema. Kubernetes sabe cómo iniciar pods, cómo reiniciar contenedores, cómo montar volúmenes, cómo trabajar con ConfigMap, es decir. todo lo que se puede llamar sistema.

Los operadores operan en dominios. Cada operador está hecho para su propia área temática. Lo hicimos para ClickHouse.

Y el operador interactúa precisamente en términos del área temática, como por ejemplo añadiendo una réplica, haciendo un diagrama, configurando el monitoreo. Esto resulta en una división.

Operador en Kubernetes para la gestión de clústeres de bases de datos. Vladislav Klimenko (Altinidad, 2019)

Veamos un ejemplo práctico de cómo se produce esta división de responsabilidad cuando realizamos la acción de agregar réplica.

El operador recibe una tarea: agregar una réplica. ¿Qué hace el operador? El operador calculará que es necesario crear un nuevo StatefulSet, en el que se deben describir tales o cuales plantillas, reclamo de volumen.

Operador en Kubernetes para la gestión de clústeres de bases de datos. Vladislav Klimenko (Altinidad, 2019)

Lo preparó todo y se lo pasa a K8. Dice que necesita ConfigMap, StatefulSet, Volume. Kubernetes está funcionando. Materializa las unidades básicas con las que opera.

Operador en Kubernetes para la gestión de clústeres de bases de datos. Vladislav Klimenko (Altinidad, 2019)

Y entonces vuelve a entrar en juego el operador ClickHouse. Ya tiene una cápsula física en la que ya puede hacer algo. Y el operador ClickHouse vuelve a funcionar en términos de dominio. Aquellos. Específicamente ClickHouse, para incluir una réplica en un clúster, primero debe configurar el esquema de datos que existe en este clúster. Y, en segundo lugar, esta réplica debe incluirse en el seguimiento para que pueda rastrearse claramente. El operador ya lo configura.

Operador en Kubernetes para la gestión de clústeres de bases de datos. Vladislav Klimenko (Altinidad, 2019)

Y sólo después de eso entra en juego ClickHouse, es decir. otra entidad de nivel superior. Esto ya es una base de datos. Tiene su propia instancia, otra réplica configurada que está lista para unirse al clúster.

Resulta que la cadena de ejecución y división de responsabilidades a la hora de añadir una réplica es bastante larga.

Operador en Kubernetes para la gestión de clústeres de bases de datos. Vladislav Klimenko (Altinidad, 2019)

Continuamos con nuestras tareas prácticas. Si ya tiene un clúster, puede migrar la configuración.

Operador en Kubernetes para la gestión de clústeres de bases de datos. Vladislav Klimenko (Altinidad, 2019)

Lo hicimos para que pueda pegarlo directamente en un xml existente, que ClickHouse entiende.

Operador en Kubernetes para la gestión de clústeres de bases de datos. Vladislav Klimenko (Altinidad, 2019)

Puede ajustar ClickHouse. La implementación por zonas es de lo que hablé cuando expliqué hostPath, almacenamiento local. Así es como se realiza correctamente la implementación por zonas.

Operador en Kubernetes para la gestión de clústeres de bases de datos. Vladislav Klimenko (Altinidad, 2019)

La siguiente tarea práctica es el seguimiento.

Operador en Kubernetes para la gestión de clústeres de bases de datos. Vladislav Klimenko (Altinidad, 2019)

Si nuestro clúster cambia, entonces debemos configurar el monitoreo periódicamente.

Miremos el diagrama. Ya hemos mirado las flechas verdes aquí. Ahora miremos las flechas rojas. Así es como queremos monitorear nuestro clúster. Cómo las métricas del clúster ClickHouse llegan a Prometheus y luego a Grafana.

Operador en Kubernetes para la gestión de clústeres de bases de datos. Vladislav Klimenko (Altinidad, 2019)

¿Cuál es la dificultad con el seguimiento? ¿Por qué se presenta esto como una especie de logro? La dificultad está en la dinámica. Cuando tenemos un clúster y es estático, podemos configurar el monitoreo una vez y no molestarnos más.

Pero si tenemos muchos clusters o algo cambia constantemente, entonces el proceso es dinámico. Y reconfigurar constantemente el monitoreo es una pérdida de recursos y tiempo, es decir. incluso simplemente pereza. Esto debe automatizarse. La dificultad radica en la dinámica del proceso. Y el operador lo automatiza muy bien.

Operador en Kubernetes para la gestión de clústeres de bases de datos. Vladislav Klimenko (Altinidad, 2019)

¿Cómo se desarrolló nuestro cluster? Al principio él era así.

Operador en Kubernetes para la gestión de clústeres de bases de datos. Vladislav Klimenko (Altinidad, 2019)

Entonces él era así.

Operador en Kubernetes para la gestión de clústeres de bases de datos. Vladislav Klimenko (Altinidad, 2019)

Al final, se volvió así.

Y el operador realiza el seguimiento automáticamente. Punto único de entrada.

Operador en Kubernetes para la gestión de clústeres de bases de datos. Vladislav Klimenko (Altinidad, 2019)

Y justo a la salida miramos el panel de Grafana para ver cómo hierve en su interior la vida de nuestro cluster.

Por cierto, el panel de Grafana también se distribuye a nuestro operador directamente en el código fuente. Puedes conectarte y usarlo. Nuestro DevOps me dio esta captura de pantalla.

Operador en Kubernetes para la gestión de clústeres de bases de datos. Vladislav Klimenko (Altinidad, 2019)

¿Adónde nos gustaría ir a continuación? Este:

  • Desarrollar la automatización de pruebas. La tarea principal es la prueba automatizada de nuevas versiones.
  • También queremos automatizar la integración con ZooKeeper. Y hay planes para integrarse con el operador ZooKeeper. Aquellos. Se ha escrito un operador para ZooKeeper y es lógico que los dos operadores comiencen a integrarse para construir una solución más conveniente.
  • Queremos hacer signos vitales más complejos.
  • Resalté en verde que nos acercamos a la herencia de plantillas - HECHO, es decir, con la próxima versión del operador ya tendremos herencia de plantillas. Esta es una poderosa herramienta que le permite construir configuraciones complejas a partir de piezas.
  • Y queremos automatización de tareas complejas. El principal es Re-sharding.

Operador en Kubernetes para la gestión de clústeres de bases de datos. Vladislav Klimenko (Altinidad, 2019)

Tomemos algunos resultados intermedios.

Operador en Kubernetes para la gestión de clústeres de bases de datos. Vladislav Klimenko (Altinidad, 2019)

¿Qué obtenemos como resultado? ¿Y vale la pena hacerlo o no? ¿Es incluso necesario intentar arrastrar la base de datos a Kubernetes y utilizar el operador en general y el operador Alitnity en particular?

En la salida obtenemos:

  • Importante simplificación y automatización de la configuración, implementación y mantenimiento.
  • Monitoreo inmediatamente incorporado.
  • Y plantillas codificadas listas para usar para situaciones complejas. No es necesario realizar manualmente una acción como agregar una réplica. El operador hace esto.

Operador en Kubernetes para la gestión de clústeres de bases de datos. Vladislav Klimenko (Altinidad, 2019)

Sólo queda una última pregunta. Ya tenemos una base de datos en Kubernetes, virtualización. ¿Qué pasa con el rendimiento de dicha solución, especialmente porque ClickHouse está optimizado para el rendimiento?

¡La respuesta es que todo está bien! No entraré en detalles; este es el tema de un informe aparte.

Operador en Kubernetes para la gestión de clústeres de bases de datos. Vladislav Klimenko (Altinidad, 2019)

Pero existe un proyecto como TSBS. ¿Cuál es su tarea principal? Esta es una prueba de rendimiento de la base de datos. Este es un intento de comparar lo cálido con lo cálido, lo suave con lo suave.

¿Cómo trabaja? Se genera un conjunto de datos. Luego, este conjunto de datos se ejecuta en diferentes bases de datos utilizando el mismo conjunto de pruebas. Y cada base de datos resuelve un problema como sabe. Y luego puedes comparar los resultados.

Ya admite una gran cantidad de bases de datos. He identificado tres principales. Este:

  • Escala de tiempoDB.
  • AfluenciaDB.
  • Haga clic en Casa.

Operador en Kubernetes para la gestión de clústeres de bases de datos. Vladislav Klimenko (Altinidad, 2019)

También se hizo una comparación con otra solución similar. Comparación con RedShift. La comparación se realizó en Amazon. ClickHouse también está muy por delante de todos en este asunto.

Operador en Kubernetes para la gestión de clústeres de bases de datos. Vladislav Klimenko (Altinidad, 2019)

¿Qué conclusiones se pueden sacar de lo que dije?

  • DB en Kubernetes es posible. Probablemente cualquiera sea posible, pero en general parece que es posible. ClickHouse en Kubernetes definitivamente es posible con la ayuda de nuestro operador.
  • El operador ayuda a automatizar procesos y realmente hace la vida más fácil.
  • El rendimiento es normal.
  • Y nos parece que esto puede y debe utilizarse.

Código abierto: ¡únete a nosotros!

Como ya dije, el operador es un producto completamente de código abierto, por lo que sería muy bueno si lo usara el máximo número de personas. ¡Únete a nosotros! ¡Os esperamos a todos!

¡Gracias!

preguntas

Operador en Kubernetes para la gestión de clústeres de bases de datos. Vladislav Klimenko (Altinidad, 2019)

¡Gracias por el informe! Mi nombre es Antón. Soy de SEMrush. Me pregunto qué pasa con el registro. Oímos hablar de monitoreo, pero nada de registro, si hablamos de todo el clúster. Por ejemplo, hemos creado un clúster sobre hardware. Y utilizamos el registro centralizado, reuniéndolos en un montón común utilizando medios estándar. Y luego de ahí obtenemos los datos que nos interesan.

Buena pregunta, es decir, iniciar sesión en una lista de tareas pendientes. Nuestro operador aún no automatiza esto. Todavía está en desarrollo, el proyecto es todavía bastante joven. Entendemos la necesidad de iniciar sesión. Este también es un tema muy importante. Y probablemente no sea menos importante que el seguimiento. Pero lo primero en la lista de implementación fue el monitoreo. Habrá tala. Naturalmente, intentamos automatizar todos los aspectos de la vida del clúster. Por tanto, la respuesta es que por el momento el operador, lamentablemente, no sabe cómo hacer esto, pero está en los planes, lo haremos. Si desea unirse, solicite la solicitud, por favor.

¡Hola! ¡Gracias por el informe! Tengo una pregunta estándar relacionada con los volúmenes persistentes. Cuando creamos una configuración con este operador, ¿cómo determina el operador en qué nodo tenemos conectado un disco o carpeta en particular? Primero debemos explicarle que por favor coloque nuestro ClickHouse en estos nodos que tienen un disco.

Hasta donde tengo entendido, esta pregunta es una continuación del almacenamiento local, especialmente la parte hostPath. Esto es como explicarle a todo el sistema que el pod debe iniciarse en tal o cual nodo, al que tenemos un disco conectado físicamente, que está montado a lo largo de tal o cual ruta. Esta es toda una sección que mencioné muy superficialmente porque la respuesta es bastante amplia.

Brevemente se parece a esto. Naturalmente, necesitamos aprovisionar estos volúmenes. Por el momento, no existe una provisión dinámica en el almacenamiento local, por lo que DevOps debe cortar los propios discos, estos volúmenes. Y deben explicar el aprovisionamiento de Kubernetes de que tendrá volúmenes persistentes de tal o cual clase, que se encuentran en tal o cual nodo. Luego, deberá explicarle a Kubernetes que los pods que requieren tal o cual clase de almacenamiento local deben dirigirse solo a tal o cual nodo mediante etiquetas. Para estos efectos, el operador tiene la capacidad de asignar algún tipo de etiqueta y una por instancia de host. Y resulta que Kubernetes enrutará los pods para que se ejecuten solo en nodos que cumplan con los requisitos, etiquetas, en términos simples. Los administradores asignan etiquetas y aprovisionan discos manualmente. Y luego escala.

Y es la tercera opción, local, la que ayuda a que esto sea un poco más fácil. Como ya he subrayado, se trata de un minucioso trabajo de puesta a punto que, en última instancia, ayuda a obtener el máximo rendimiento.

Tengo una segunda pregunta relacionada con esto. Kubernetes fue diseñado de tal manera que no nos importa si perdemos un nodo o no. ¿Qué debemos hacer en este caso si hemos perdido el nodo donde cuelga nuestro fragmento?

Sí, Kubernetes inicialmente se planteó que nuestra relación con nuestras cápsulas es como el ganado, pero aquí, para nosotros, cada disco se convierte en algo así como una mascota. Existe tal problema que no podemos simplemente tirarlos a la basura. Y el desarrollo de Kubernetes va en la dirección en que es imposible tratarlo completamente filosóficamente, como si fuera un recurso completamente descartado.

Ahora una pregunta práctica. ¿Qué hacer si perdiste el nodo en el que estaba el disco? Aquí el problema se resuelve a un nivel superior. En el caso de ClickHouse, tenemos réplicas que funcionan a un nivel superior, es decir. a nivel de ClickHouse.

¿Cuál es la disposición resultante? DevOps es responsable de garantizar que no se pierdan datos. Debe configurar la replicación correctamente y asegurarse de que la replicación se esté ejecutando. La réplica a nivel de ClickHouse debe tener datos duplicados. Ésta no es la tarea que resuelve el operador. Y no el problema que resuelve el propio Kubernetes. Esto es a nivel de ClickHouse.

¿Qué hacer si se te cae el nudo de hierro? Y resulta que necesitarás instalar un segundo, aprovisionar adecuadamente el disco y aplicar etiquetas. Y después de eso, cumplirá con los requisitos de que Kubernetes pueda lanzar un pod de instancia en él. Kubernetes lo lanzará. Su número de pods no es suficiente para alcanzar el número especificado. Pasará por el ciclo que mostré. Y en el nivel más alto, ClickHouse entenderá que hemos ingresado una réplica, todavía está vacía y debemos comenzar a transferirle datos. Aquellos. Este proceso aún no está bien automatizado.

¡Gracias por el informe! Cuando suceden todo tipo de cosas desagradables, el operador falla y se reinicia, y en ese momento llegan los eventos, ¿lo manejas de alguna manera?

¿Qué pasa si el operador falla y se reinicia, verdad?

Sí. Y en ese momento llegaron los acontecimientos.

La tarea de qué hacer en este caso se comparte en parte entre el operador y Kubernetes. Kubernetes tiene la capacidad de reproducir un evento ocurrido. Él repite. Y la tarea del operador es asegurarse de que cuando se reproduzca el registro de eventos, estos eventos sean idempotentes. Y para que la repetición del mismo evento no rompa nuestro sistema. Y nuestro operador hace frente a esta tarea.

¡Hola! ¡Gracias por el informe! Dmitry Zavyalov, empresa Smedova. ¿Hay planes para agregar la capacidad de configurar con haproxy al operador? Me interesaría algún otro equilibrador además del estándar, para que sea inteligente y entienda que ClickHouse realmente está ahí.

¿Estás hablando de ingreso?

Sí, reemplace Ingress con haproxy. En haproxy puedes especificar la topología del cluster donde tiene réplicas.

No lo hemos pensado todavía. Si lo necesita y puede explicar por qué es necesario, entonces será posible implementarlo, especialmente si desea participar. Estaremos encantados de considerar la opción. La respuesta corta es no, actualmente no contamos con dicha funcionalidad. Gracias por el consejo, investigaremos este asunto. Y si también explica el caso de uso y por qué es necesario en la práctica, por ejemplo, crear problemas en GitHub, entonces será genial.

Ya tengo

Bien. Estamos abiertos a cualquier sugerencia. Y haproxy se agrega a la lista de tareas pendientes. La lista de tareas pendientes está creciendo, no disminuyendo todavía. Pero esto es bueno, significa que el producto tiene demanda.

Fuente: habr.com

Añadir un comentario