Operador Tarantool kubernetes



O Kubernetes já se tornou um padrão de fato para a execução de aplicativos sem estado, principalmente porque pode reduzir o tempo de colocação no mercado para novos recursos. O lançamento de aplicativos com estado, como bancos de dados ou microsserviços com estado, ainda é uma tarefa complexa, mas as empresas precisam enfrentar a concorrência e manter uma alta taxa de entrega. Então, eles criam uma demanda por essas soluções.

Queremos apresentar nossa solução para o lançamento de clusters de cartucho Tarantool com estado: Tarantool Kubernetes Operator , mais detalhados .

  1. Em vez de mil palavras
  2. O que o operador realmente faz
  3. Um pouco sobre os detalhes
  4. Como o operador trabalha
  5. O que o operador cria
  6. Sumário

Tarantool é um DBMS de código aberto e um servidor de aplicativos tudo em um. Como banco de dados, possui muitas características únicas: alta eficiência na utilização de hardware, esquema de dados flexível, suporte para armazenamento em memória e disco e a possibilidade de extensão usando a linguagem Lua. Como servidor de aplicativos, permite mover o código do aplicativo o mais próximo possível dos dados, com tempo de resposta mínimo e taxa de transferência máxima. Além disso, o Tarantool possui um extenso ecossistema que fornece módulos prontos para uso para solucionar problemas de aplicativos: sharding , fila , módulos para fácil desenvolvimento ( cartucho , luatest ), soluções para operação ( métricas , ansible ), apenas para citar alguns.

Por todos os seus méritos, os recursos de uma única instância do Tarantool são sempre limitados. Você precisaria criar dezenas e centenas de instâncias para armazenar terabytes de dados e processar milhões de solicitações, o que já implica em um sistema distribuído com todos os seus problemas típicos. Para resolvê-los, temos o Tarantool Cartridge , que é uma estrutura projetada para ocultar todo tipo de dificuldade ao escrever aplicativos distribuídos. Ele permite que os desenvolvedores se concentrem no valor comercial do aplicativo. O cartucho fornece um conjunto robusto de componentes para orquestração automática de cluster, distribuição automática de dados, WebUI para operação e ferramentas de desenvolvedor.

O Tarantool não é apenas sobre tecnologias, mas também sobre uma equipe de engenheiros trabalhando no desenvolvimento de sistemas corporativos prontos para uso, soluções prontas para uso e suporte para componentes de código aberto.

Globalmente, todas as nossas tarefas podem ser divididas em duas áreas: o desenvolvimento de novos sistemas e a melhoria das soluções existentes. Por exemplo, há um extenso banco de dados de um fornecedor conhecido. Para escalá-lo para leitura, um cache consistente com base em Tarantool é colocado atrás dele. Ou vice-versa: para dimensionar a gravação, o Tarantool é instalado na configuração quente / frio: enquanto os dados estão "esfriando", eles são despejados no armazenamento a frio e, ao mesmo tempo, na fila de análise. Ou uma versão light de um sistema existente é gravada (backup funcional) para fazer backup dos dados "quentes" usando a replicação de dados do sistema principal. Saiba mais nos relatórios da conferência T + 2019 .

Todos esses sistemas têm uma coisa em comum: eles são um pouco difíceis de operar. Bem, há muitas coisas interessantes: criar rapidamente um cluster de mais de 100 instâncias de backup em três data centers; atualizar o aplicativo que armazena dados sem tempo de inatividade ou rebaixamentos de manutenção; criar um backup e restauração para se preparar para um possível acidente ou erro humano; garantir failover de componente oculto; para organizar o gerenciamento de configuração ...

O cartucho Tarantool, que acaba de ser lançado em código aberto, simplifica significativamente o desenvolvimento do sistema distribuído: suporta clustering de componentes, descoberta de serviços, gerenciamento de configuração, detecção de falhas de instância e failover automático, gerenciamento de topologia de replicação e componentes de sharding.
Seria ótimo se pudéssemos operar tudo isso o mais rápido possível. O Kubernetes torna isso possível, mas um operador especializado tornaria a vida ainda mais confortável.

Hoje, apresentamos a versão alfa do Tarantool Kubernetes Operator.

Em vez de mil palavras


Preparamos um pequeno exemplo baseado no Tarantool Cartridge e vamos trabalhar com ele. É um aplicativo simples chamado armazenamento de valor-chave distribuído com interface HTTP. Após a inicialização, temos o seguinte:



Onde

  • Os roteadores fazem parte do cluster responsável por aceitar e processar solicitações HTTP recebidas;
  • Os armazenamentos fazem parte do cluster responsável pelo armazenamento e processamento de dados; três shards são instalados fora da caixa, cada um com um mestre e uma réplica.

Para equilibrar o tráfego HTTP de entrada nos roteadores, um ingresso do Kubernetes é usado. Os dados são distribuídos no armazenamento no nível do Tarantool, usando o componente vshard .

Precisamos do Kubernetes 1.14+, mas o minikube serve . Também é adorável ter o kubectl . Para iniciar o operador, crie uma ServiceAccount, uma Função e uma RoleBinding:

$ 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 

O Tarantool Operator estende a API do Kubernetes com suas definições de recursos, então vamos criá-las:

 $ 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 

Tudo está pronto para iniciar o operador, então aqui está:

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

Estamos aguardando o início do operador e, em seguida, podemos continuar com o aplicativo:

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

Um ingresso é declarado na interface do usuário da web no arquivo YAML com o exemplo; está disponível em cluster_ip/admin/cluster . Quando pelo menos um Ingress Pod estiver pronto e em execução, você poderá ver como novas instâncias são adicionadas ao cluster e como sua topologia é alterada.
Estamos aguardando o cluster ser usado:

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

Estamos aguardando o seguinte status do cluster:

 … Status: State: Ready … 

Isso é tudo, e o aplicativo está pronto para uso!

Você precisa de mais espaço de armazenamento? Então, vamos adicionar alguns shards:

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

Se os shards não puderem lidar com a carga, aumentemos o número de instâncias no shard editando o modelo do conjunto de réplicas:

 $ kubectl edit replicasettemplates.tarantool.io storage-template 

Vamos definir o valor .spec.replicas como dois para aumentar o número de instâncias em cada réplica configurada para dois.

Se um cluster não for mais necessário, basta excluí-lo com todos os recursos:

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

Algo deu errado? Crie um ticket e trabalharemos rapidamente nele.

O que o operador realmente faz


A inicialização e operação do cluster Tarantool Cartridge é uma história de execução de ações específicas em uma ordem específica e em um momento específico.

O cluster em si é gerenciado principalmente por meio da API de administração: GraphQL sobre HTTP. Sem dúvida, você pode descer um nível mais baixo e dar comandos diretamente através do console, mas isso não acontece com muita frequência.
Por exemplo, é assim que o cluster é iniciado:

  1. Implantamos o número necessário de instâncias do Tarantool, por exemplo, usando systemd.
  2. Em seguida, conectamos as instâncias à associação:

     mutation { probe_instance: probe_server(uri: "storage:3301") } 
  3. Em seguida, atribuímos as funções às instâncias e especificamos os identificadores do conjunto de réplicas e instâncias. A API GraphQL é usada para esta finalidade:

     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. Por fim, inicializamos o componente responsável pelo sharding usando a API:

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

Fácil né?

Tudo é mais interessante quando se trata de expansão de cluster. A função Roteadores do exemplo é dimensionada facilmente: crie mais instâncias, junte-as a um cluster existente e pronto! O papel de Armazenamento é um pouco mais complicado. O armazenamento é fragmentado; portanto, ao adicionar / remover instâncias, é necessário reequilibrar os dados movendo-os para / das instâncias novas / excluídas, respectivamente. Não fazer isso resultaria em instâncias com carga insuficiente ou perda de dados. E se não houver apenas um, mas uma dúzia de clusters com diferentes topologias?

Em geral, isso é tudo que o Operador Tarantool gerencia. O usuário descreve o estado necessário do cluster do Tarantool Cartridge e o operador o converte em um conjunto de ações aplicadas aos recursos do K8s e em determinadas chamadas à API do administrador do cluster do Tarantool em uma ordem específica em um horário específico. Ele também tenta ocultar todos os detalhes do usuário.

Um pouco sobre os detalhes


Ao trabalhar com a API do administrador de cluster do Tarantool Cartridge, a ordem das chamadas e seu destino são essenciais. Por que isso?

O cartucho Tarantool contém seu armazenamento de topologia, componente de descoberta de serviço e componente de configuração. Cada instância do cluster armazena uma cópia da topologia e configuração em um arquivo 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 ... 

As atualizações são aplicadas consistentemente usando o mecanismo de confirmação de duas fases . Uma atualização bem-sucedida requer um quorum de 100%: toda instância deve responder. Caso contrário, ele reverte. O que isso significa em termos de operação? Em termos de confiabilidade, todas as solicitações à API do administrador que modificam o estado do cluster devem ser enviadas para uma única instância ou líder, pois, caso contrário, corremos o risco de obter configurações diferentes em instâncias diferentes. O Cartucho Tarantool não sabe como fazer uma eleição de líder (ainda não), mas o Operador Tarantool pode, e para você, isso é apenas um fato divertido, porque o operador faz tudo.

Cada instância também deve ter uma identidade fixa, ou seja, um conjunto de instance_uuid e replicaset_uuid , além de advertise_uri . Se repentinamente um armazenamento for reiniciado e um desses parâmetros for alterado, você corre o risco de quebrar o quorum e o operador é responsável por isso.

Como o operador trabalha


O objetivo do operador é trazer o sistema para o estado definido pelo usuário e manter o sistema nesse estado até que novas direções sejam fornecidas. Para que o operador possa trabalhar, ele precisa:

  1. A descrição do status do sistema.
  2. O código que traria o sistema para esse estado.
  3. Um mecanismo para integrar esse código no k8s (por exemplo, para receber notificações de alteração de estado).

O cluster do Tarantool Cartridge é descrito em termos de k8s usando uma definição de recurso personalizado (CRD) . O operador precisaria de três recursos personalizados unidos no grupo tarantool.io/v1alpha:

  • O cluster é um recurso de nível superior que corresponde a um único cluster do Tarantool Cartridge.
  • A função é uma função do usuário em termos de cartucho Tarantool.
  • Replicaset Template é um modelo para a criação de StatefulSets (falarei um pouco mais tarde por que eles são stateful; não devem ser confundidos com o K8s ReplicaSet).

Todos esses recursos refletem diretamente o modelo de descrição de cluster do Tarantool Cartridge. Ter um dicionário comum facilita a comunicação com os desenvolvedores e o entendimento do que eles gostariam de ver na produção.

O código que leva o sistema ao estado especificado é o Controller em termos de K8s. No caso do Tarantool Operator, existem vários controladores:

  • O Cluster Controller é responsável por interagir com o cluster Tarantool Cartridge; ele conecta instâncias ao cluster e desconecta instâncias do cluster.
  • O Controlador de Função é o controlador de função de usuário responsável por criar StatefulSets a partir do modelo e manter o número predefinido deles.

Como é um controlador? É um conjunto de códigos que gradualmente coloca o mundo ao seu redor em ordem. Um Cluster Controller seria esquematicamente parecido com:



Um ponto de entrada é um teste para verificar se existe um recurso de cluster correspondente para um evento. Existe? "Não" significa desistir. "Sim" significa passar para o próximo bloco e assumir a propriedade das funções de usuário. Quando a propriedade de uma função é assumida, ela sai e passa pela segunda vez. Ele continua e continua até assumir a propriedade de todas as funções. Quando a propriedade é tomada, é hora de passar para o próximo bloco de operações. E o processo continua até o último bloco. Depois disso, podemos assumir que o sistema controlado está no estado definido.

Em geral, tudo é bastante simples. No entanto, é importante determinar os critérios de sucesso para a aprovação de cada estágio. Por exemplo, a operação de junção de cluster não é considerada bem-sucedida quando retorna sucesso hipotético = true, mas quando retorna um erro como "já ingressado".

E a última parte desse mecanismo é a integração do controlador com os K8s. Do ponto de vista de um pássaro, todo o K8s consiste em um conjunto de controladores que geram eventos e respondem a eles. Esses eventos são organizados em filas nas quais podemos assinar. Seria esquematicamente parecido com:



O usuário chama kubectl create -f tarantool_cluster.yaml e o recurso de cluster correspondente é criado. O Cluster Controller é notificado sobre a criação de recursos do Cluster. E a primeira coisa que ele está tentando fazer é encontrar todos os recursos da Função que devem fazer parte desse cluster. Se isso acontecer, ele atribui o cluster como o proprietário da função e atualiza o recurso da função. O Controlador de Função recebe uma notificação de atualização de Função, entende que o recurso tem seu Proprietário e começa a criar StatefulSets. É assim que funciona: o primeiro evento aciona o segundo, o segundo evento aciona o terceiro e assim por diante até que um deles pare. Você também pode definir um gatilho de tempo, por exemplo, a cada 5 segundos.

É assim que o operador está organizado: criamos um recurso personalizado e escrevemos o código que responde aos eventos relacionados aos recursos.

O que o operador cria


As ações do operador resultam na criação de Pods e contêineres K8s. No cluster do Tarantool Cartridge implantado nos K8s, todos os Pods estão conectados ao StatefulSets.

Por que StatefulSet? Como mencionei anteriormente, toda instância do Tarantool Cluster mantém uma cópia da topologia e configuração do cluster. De vez em quando, um servidor de aplicativos tem algum espaço dedicado, por exemplo, para filas ou dados de referência, e esse já é um estado completo. StatefulSet também garante que as identidades do Pod sejam preservadas, o que é importante ao agrupar instâncias: as instâncias devem ter identidades fixas; caso contrário, corremos o risco de perder o quorum ao reiniciar.

Quando todos os recursos do cluster estão prontos e no estado desejado, eles refletem a seguinte hierarquia:



As setas indicam o relacionamento Dependente do proprietário entre os recursos. É necessário, por exemplo, que o Garbage Collector seja limpo após a remoção do Cluster.

Além do StatefulSets, o Tarantool Operator cria um serviço sem cabeça para a eleição do líder e as instâncias se comunicam entre si por esse serviço.

O Tarantool Operator é baseado na Estrutura do Operador e o código do operador está escrito em Golang, portanto não há nada de especial aqui.

Sumário


Isso é praticamente tudo o que existe. Estamos aguardando seus comentários e tickets. Não podemos ficar sem eles - afinal, é a versão alfa. O que vem depois? O próximo passo é muito polido:

  • Unidade, testes E2E;
  • Testes do macaco do caos;
  • testes de estresse;
  • backup / restauração;
  • provedor de topologia externa.

Cada um desses tópicos é amplo por si só e merece um artigo separado. Portanto, aguarde atualizações!

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


All Articles