Operador de kubernetes de Tarantool



Kubernetes ya se ha convertido en un estándar de facto para ejecutar aplicaciones sin estado, principalmente porque puede reducir el tiempo de comercialización de nuevas características. Lanzar aplicaciones con estado, como bases de datos o microservicios con estado, sigue siendo una tarea compleja, pero las empresas deben cumplir con la competencia y mantener una alta tasa de entrega. Entonces crean una demanda de tales soluciones.

Queremos presentar nuestra solución para el lanzamiento de agrupaciones de cartuchos de Tarantool : Operador Tarantool Kubernetes , más bajo el corte.

  1. En lugar de mil palabras
  2. Lo que el operador realmente hace
  3. Un poco sobre los detalles
  4. Cómo funciona el operador
  5. Lo que crea el operador
  6. Resumen

Tarantool es un DBMS de código abierto y un servidor de aplicaciones todo en uno. Como base de datos, tiene muchas características únicas: alta eficiencia en la utilización del hardware, esquema de datos flexible, soporte para almacenamiento en disco y en memoria, y la posibilidad de extensión usando el lenguaje Lua. Como servidor de aplicaciones, le permite mover el código de la aplicación lo más cerca posible de los datos con un tiempo de respuesta mínimo y un rendimiento máximo. Además, Tarantool tiene un extenso ecosistema que proporciona módulos listos para usar para resolver problemas de aplicación: fragmentación , cola , módulos para un fácil desarrollo ( cartucho , luatest ), soluciones para la operación ( métrica , ansible ), solo por nombrar algunos.

Por todos sus méritos, las capacidades de una sola instancia de Tarantool son siempre limitadas. Tendría que crear decenas y cientos de instancias para almacenar terabytes de datos y procesar millones de solicitudes, lo que ya implica un sistema distribuido con todos sus problemas típicos. Para resolverlos, tenemos el cartucho Tarantool , que es un marco diseñado para ocultar todo tipo de dificultades al escribir aplicaciones distribuidas. Permite a los desarrolladores concentrarse en el valor comercial de la aplicación. Cartridge proporciona un conjunto robusto de componentes para la orquestación automática de clústeres, distribución automática de datos, WebUI para operación y herramientas para desarrolladores.

Tarantool no solo se trata de tecnologías, sino también de un equipo de ingenieros que trabajan en el desarrollo de sistemas empresariales llave en mano, soluciones listas para usar y soporte para componentes de código abierto.

A nivel mundial, todas nuestras tareas se pueden dividir en dos áreas: el desarrollo de nuevos sistemas y la mejora de las soluciones existentes. Por ejemplo, hay una extensa base de datos de un proveedor conocido. Para escalarlo para la lectura, se coloca un caché consistente eventualmente basado en Tarantool. O viceversa: para escalar la escritura, Tarantool se instala en la configuración frío / calor: mientras los datos se "enfrían", se vuelcan al almacenamiento en frío y al mismo tiempo a la cola de análisis. O se escribe una versión ligera de un sistema existente (copia de seguridad funcional) para hacer una copia de seguridad de los datos "activos" mediante la replicación de datos del sistema principal. Obtenga más información de los informes de la conferencia T + 2019 .

Todos estos sistemas tienen una cosa en común: son algo difíciles de operar. Bueno, hay muchas cosas interesantes: crear rápidamente un clúster de más de 100 instancias respaldando en 3 centros de datos; para actualizar la aplicación que almacena datos sin tiempo de inactividad o inconvenientes de mantenimiento; crear una copia de seguridad y restaurar para prepararse para un posible accidente o errores humanos; para garantizar la conmutación por error de componentes ocultos; para organizar la gestión de la configuración ...

El cartucho de Tarantool que literalmente se acaba de lanzar en código abierto simplifica significativamente el desarrollo del sistema distribuido: admite agrupación de componentes, descubrimiento de servicios, gestión de configuración, detección de fallas de instancia y conmutación por error automática, gestión de topología de replicación y componentes de fragmentación.
Sería genial si pudiéramos operar todo esto tan rápido como desarrollarlo. Kubernetes lo hace posible, pero un operador especializado haría la vida aún más cómoda.

Hoy presentamos la versión alfa de Tarantool Kubernetes Operator.

En lugar de mil palabras


Hemos preparado un pequeño ejemplo basado en el cartucho de Tarantool, y vamos a trabajar con él. Es una aplicación simple llamada almacenamiento de valor clave distribuido con interfaz HTTP. Después de la puesta en marcha, tenemos lo siguiente:



Donde

  • Los enrutadores son parte del clúster responsable de aceptar y procesar las solicitudes HTTP entrantes;
  • Los almacenamientos son parte del clúster responsable de almacenar y procesar datos; Se instalan tres fragmentos de la caja, cada uno con un maestro y una réplica.

Para equilibrar el tráfico HTTP entrante en los enrutadores, se utiliza un Kubernetes Ingress. Los datos se distribuyen en el almacenamiento al nivel de Tarantool utilizando el componente vshard .

Necesitamos Kubernetes 1.14+, pero minikube servirá. También es encantador tener kubectl . Para iniciar el operador, cree una cuenta de servicio, un rol y un enlace de rol:

$ kubectl create -f https://raw.githubusercontent.com/tarantool/tarantool-operator/0.0.1/deploy/service_account.yaml $ kubectl create -f https://raw.githubusercontent.com/tarantool/tarantool-operator/0.0.1/deploy/role.yaml $ kubectl create -f https://raw.githubusercontent.com/tarantool/tarantool-operator/0.0.1/deploy/role_binding.yaml 

Tarantool Operator extiende la API de Kubernetes con sus definiciones de recursos, así que creémoslas:

 $ kubectl create -f https://raw.githubusercontent.com/tarantool/tarantool-operator/0.0.1/deploy/crds/tarantool_v1alpha1_cluster_crd.yaml $ kubectl create -f https://raw.githubusercontent.com/tarantool/tarantool-operator/0.0.1/deploy/crds/tarantool_v1alpha1_role_crd.yaml $ kubectl create -f https://raw.githubusercontent.com/tarantool/tarantool-operator/0.0.1/deploy/crds/tarantool_v1alpha1_replicasettemplate_crd.yaml 

Todo está listo para iniciar el operador, así que aquí va:

 $ kubectl create -f https://raw.githubusercontent.com/tarantool/tarantool-operator/0.0.1/deploy/operator.yaml 

Estamos esperando que el operador comience y luego podemos continuar con el inicio de la aplicación:

 $ kubectl create -f https://raw.githubusercontent.com/tarantool/tarantool-operator/0.0.1/examples/kv/deployment.yaml 

Se declara un Ingress en la interfaz de usuario web en el archivo YAML con el ejemplo; Está disponible en cluster_ip/admin/cluster . Cuando al menos un Ingress Pod está listo y ejecutándose, puede ir allí para ver cómo se agregan nuevas instancias al clúster y cómo cambia su topología.
Estamos esperando que se use el clúster:

 $ kubectl describe clusters.tarantool.io examples-kv-cluster 

Estamos esperando el siguiente estado del clúster:

 … Status: State: Ready … 

¡Eso es todo, y la aplicación está lista para usar!

¿Necesitas más espacio de almacenamiento? Luego, agreguemos algunos fragmentos:

 $ kubectl scale roles.tarantool.io storage --replicas=3 

Si los fragmentos no pueden manejar la carga, aumentemos el número de instancias en el fragmento editando la plantilla de conjunto de réplicas:

 $ kubectl edit replicasettemplates.tarantool.io storage-template 

.spec.replicas valor de .spec.replicas en dos para aumentar el número de instancias en cada conjunto de réplicas en dos.

Si ya no se necesita un clúster, simplemente elimínelo junto con todos los recursos:

 $ kubectl delete clusters.tarantool.io examples-kv-cluster 

¿Algo salió mal? Cree un boleto y trabajaremos rápidamente en él.

Lo que el operador realmente hace


La puesta en marcha y el funcionamiento del clúster de cartucho de Tarantool es una historia de la realización de acciones específicas en un orden específico en un momento específico.

El clúster en sí mismo se administra principalmente a través de la API de administración: GraphQL sobre HTTP. Sin duda, puede bajar un nivel y dar comandos directamente a través de la consola, pero esto no sucede con mucha frecuencia.
Por ejemplo, así es como se inicia el clúster:

  1. Implementamos el número requerido de instancias de Tarantool, por ejemplo, usando systemd.
  2. Luego conectamos las instancias en membresía:

     mutation { probe_instance: probe_server(uri: "storage:3301") } 
  3. Luego asignamos los roles a las instancias y especificamos los identificadores del conjunto de instancias y réplicas. La API GraphQL se utiliza para este propósito:

     mutation { join_server( uri:"storage:3301", instance_uuid: "cccccccc-cccc-4000-b000-000000000001", replicaset_uuid: "cccccccc-0000-4000-b000-000000000000", roles: ["storage"], timeout: 5 ) } 
  4. Inicialmente, arrancamos el componente responsable de fragmentar utilizando la API:

     mutation { bootstrap_vshard cluster { failover(enabled:true) } } 

Fácil, verdad?

Todo es más interesante cuando se trata de expansión de clúster. La función de enrutadores del ejemplo se escala fácilmente: cree más instancias, únalas a un clúster existente, ¡y listo! El papel de Storages es algo más complicado. El almacenamiento está fragmentado, por lo que al agregar / eliminar instancias, es necesario reequilibrar los datos moviéndolos a / desde las instancias nuevas / eliminadas, respectivamente. De lo contrario, se producirían instancias subcargadas o pérdida de datos. ¿Qué pasa si no hay solo uno, sino una docena de clústeres con diferentes topologías?

En general, esto es todo lo que maneja el operador de Tarantool. El usuario describe el estado necesario del clúster de cartucho de Tarantool, y el operador lo traduce en un conjunto de acciones aplicadas a los recursos de K8 y en ciertas llamadas a la API del administrador del clúster de Tarantool en un orden específico en un momento específico. También trata de ocultar todos los detalles del usuario.

Un poco sobre los detalles


Mientras trabaja con la API de administrador del clúster de Tarantool Cartridge, tanto el orden de las llamadas como su destino son esenciales. ¿Por qué es eso?

Tarantool Cartridge contiene su almacenamiento de topología, componente de descubrimiento de servicio y componente de configuración. Cada instancia del clúster almacena una copia de la topología y la configuración en un archivo YAML.

 servers: d8a9ce19-a880-5757-9ae0-6a0959525842: uri: storage-2-0.examples-kv-cluster:3301 replicaset_uuid: 8cf044f2-cae0-519b-8d08-00a2f1173fcb 497762e2-02a1-583e-8f51-5610375ebae9: uri: storage-0-0.examples-kv-cluster:3301 replicaset_uuid: 05e42b64-fa81-59e6-beb2-95d84c22a435 … vshard: bucket_count: 30000 ... 

Las actualizaciones se aplican consistentemente utilizando el mecanismo de confirmación de dos fases . Una actualización exitosa requiere un quórum del 100%: cada instancia debe responder. De lo contrario, retrocede. ¿Qué significa esto en términos de operación? En términos de confiabilidad, todas las solicitudes a la API de administrador que modifican el estado del clúster deben enviarse a una sola instancia, o al líder, porque de lo contrario nos arriesgamos a obtener diferentes configuraciones en diferentes instancias. Tarantool Cartridge no sabe cómo hacer una elección de líder (todavía no), pero el operador de Tarantool puede, y para usted, esto es un hecho divertido, porque el operador hace todo.

Cada instancia también debe tener una identidad fija, es decir, un conjunto de instance_uuid y replicaset_uuid , así como advertise_uri . Si de repente se reinicia un almacenamiento y uno de estos parámetros cambia, entonces corre el riesgo de romper el quórum, y el operador es responsable de esto.

Cómo funciona el operador


El propósito del operador es llevar el sistema al estado definido por el usuario y mantener el sistema en este estado hasta que se den nuevas instrucciones. Para que el operador pueda trabajar, necesita:

  1. La descripción del estado del sistema.
  2. El código que llevaría al sistema a este estado.
  3. Un mecanismo para integrar este código en k8s (por ejemplo, para recibir notificaciones de cambio de estado).

El grupo de cartuchos de Tarantool se describe en términos de k8s utilizando una definición de recursos personalizados (CRD) . El operador necesitaría tres recursos personalizados unidos bajo el grupo tarantool.io/v1alpha:

  • El clúster es un recurso de nivel superior que corresponde a un solo clúster de cartucho de Tarantool.
  • El rol es un rol de usuario en términos de cartucho de Tarantool.
  • Replicaset Template es una plantilla para crear StatefulSets (te diré un poco más tarde por qué son con estado; no se debe confundir con K8s ReplicaSet).

Todos estos recursos reflejan directamente el modelo de descripción del clúster de cartucho de Tarantool. Tener un diccionario común facilita la comunicación con los desarrolladores y la comprensión de lo que les gustaría ver en producción.

El código que lleva el sistema al estado dado es el controlador en términos de K8. En el caso del operador Tarantool, hay varios controladores:

  • Cluster Controller es responsable de interactuar con el clúster de Tarantool Cartridge; conecta instancias al clúster y desconecta instancias del clúster.
  • Role Controller es el controlador de roles de usuario responsable de crear StatefulSets a partir de la plantilla y mantener el número predefinido de ellos.

¿Cómo es un controlador? Es un conjunto de código que gradualmente pone el mundo a su alrededor en orden. Un controlador de clúster se vería esquemáticamente como:



Un punto de entrada es una prueba para ver si existe un recurso Cluster correspondiente para un evento. ¿Existe? "No" significa dejar de fumar. "Sí" significa pasar al siguiente bloque y tomar posesión de los roles de usuario. Cuando se toma la propiedad de un rol, se cierra y se repite por segunda vez. Sigue y sigue hasta que toma la propiedad de todos los roles. Cuando se toma la propiedad, es hora de pasar al siguiente bloque de operaciones. Y el proceso continúa hasta el último bloque. Después de eso, podemos suponer que el sistema controlado está en el estado definido.

En general, todo es bastante simple. Sin embargo, es importante determinar los criterios de éxito para pasar cada etapa. Por ejemplo, la operación de unión de clúster no se considera exitosa cuando devuelve éxito hipotético = verdadero, pero cuando devuelve un error como "ya se unió".

Y la última parte de este mecanismo es la integración del controlador con K8. Desde una vista de pájaro, los K8 completos consisten en un conjunto de controladores que generan eventos y responden a ellos. Estos eventos están organizados en colas a las que podemos suscribirnos. Se vería esquemáticamente como:



El usuario llama a kubectl create -f tarantool_cluster.yaml , y se crea el recurso Cluster correspondiente. El Cluster Controller recibe una notificación de la creación de recursos del Cluster. Y lo primero que intenta hacer es encontrar todos los recursos de rol que deberían formar parte de este clúster. Si lo hace, entonces asigna el Clúster como el Propietario del Rol y actualiza el recurso del Rol. El Controlador de roles recibe una notificación de actualización de roles, entiende que el recurso tiene su Propietario y comienza a crear StatefulSets. Así es como funciona: el primer evento activa el segundo, el segundo evento activa el tercero, y así sucesivamente hasta que uno de ellos se detiene. También puede establecer un disparador de tiempo, por ejemplo, cada 5 segundos.

Así es como se organiza el operador: creamos un recurso personalizado y escribimos el código que responde a los eventos relacionados con los recursos.

Lo que crea el operador


Las acciones del operador finalmente resultan en la creación de K8s Pods y contenedores. En el clúster de cartucho de Tarantool implementado en K8, todos los pods están conectados a StatefulSets.

¿Por qué StatefulSet? Como mencioné anteriormente, cada instancia de Tarantool Cluster mantiene una copia de la topología y configuración del clúster. Y de vez en cuando un servidor de aplicaciones tiene un espacio dedicado, por ejemplo, para colas o datos de referencia, y este ya es un estado completo. StatefulSet también garantiza que se preservan las identidades de Pod, lo cual es importante cuando se agrupan instancias: las instancias deben tener identidades fijas, de lo contrario corremos el riesgo de perder el quórum al reiniciar.

Cuando todos los recursos del clúster están listos y en el estado deseado, reflejan la siguiente jerarquía:



Las flechas indican la relación dependiente del propietario entre los recursos. Es necesario, por ejemplo, que el recolector de basura se limpie después de la eliminación del clúster.

Además de StatefulSets, el operador de Tarantool crea un servicio sin cabeza para la elección del líder, y las instancias se comunican entre sí a través de este servicio.

El operador de Tarantool se basa en el marco del operador , y el código del operador está escrito en Golang, por lo que no hay nada especial aquí.

Resumen


Eso es casi todo lo que hay que hacer. Estamos a la espera de sus comentarios y entradas. No podemos prescindir de ellos, es la versión alfa después de todo. ¿Qué sigue? El siguiente paso es pulir mucho:

  • Unidad, pruebas E2E;
  • Pruebas de Chaos Monkey;
  • pruebas de estrés;
  • copia de seguridad / restauración;
  • proveedor de topología externo.

Cada uno de estos temas es amplio por sí solo y merece un artículo separado, ¡así que espere las actualizaciones!

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


All Articles