Operador Tarantool kubernetes



O Kubernetes está se tornando o padrão de fato para a execução de aplicativos sem estado. Principalmente porque pode reduzir significativamente o tempo de colocação no mercado para a entrega de novos recursos. O lançamento de aplicativos com estado - bancos de dados, microsserviços com estado - ainda é uma tarefa difícil, mas a necessidade de resistir à concorrência e manter uma alta taxa de entrega leva as empresas a experimentar nesta área e cria uma demanda por essas soluções.

Apresentamos a você nossa solução para o lançamento de clusters com estado de cartucho Tarantool : Operador Tarantool Kubernetes , para obter detalhes que eu solicito em cat.

Sumário:

  1. Em vez de mil palavras
  2. O que o operador faz de todo
  3. Um pouco sobre as nuances
  4. Como o operador trabalha
  5. O que o operador expande
  6. Sumário


Tarantool é um banco de dados de código aberto e servidor de aplicativos em um pacote. Como banco de dados, ele possui várias características únicas: alta eficiência na utilização do ferro, esquema de dados flexível, suporte para armazenamento em memória e em disco e a possibilidade de expansão através do uso da linguagem Lua. Como servidor de aplicativos, permite mover o código do aplicativo o mais próximo possível dos dados, enquanto obtém tempo de resposta mínimo e taxa de transferência máxima. Além disso, o Tarantool possui um extenso ecossistema , fornecendo módulos prontos para solucionar problemas de aplicativos: sharding , fila , módulos para facilitar o desenvolvimento ( cartucho , luatest ), soluções para operação ( métricas , ansible ) - esses são apenas alguns exemplos.

Por todos os seus méritos, os recursos de uma única instância do Tarantool não são ilimitados: para armazenar terabytes de dados e processar milhões de solicitações, é necessário aumentar dezenas e centenas de instâncias, e este é um sistema distribuído, com todos os seus problemas inerentes. Para resolvê-los, temos o Tarantool Cartridge , uma estrutura cuja principal tarefa é ocultar todos os tipos de dificuldades na criação de aplicativos distribuídos e permitir que os desenvolvedores se concentrem no valor comercial do aplicativo. O cartucho fornece um conjunto poderoso 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 tecnologia, mas também uma equipe de engenheiros envolvidos no desenvolvimento de sistemas corporativos chave na mão, soluções de caixa e suporte para componentes de código-fonte aberto.

Globalmente, nossas tarefas podem ser divididas em duas áreas: o desenvolvimento de novos sistemas e o aumento das soluções existentes. Por exemplo, há uma grande base de um fornecedor famoso. Para escalá-lo para leitura, eles colocaram um cache finalmente consistente no Tarantool por trás dele. Ou vice-versa: para escalar o registro, eles colocam o Tarantool na configuração quente / frio, onde, quando "esfriam", os dados são despejados no armazenamento a frio e em paralelo à fila de análise. Ou, para fazer o backup de um sistema existente, é gravada uma versão leve desse sistema (reserva funcional), que reserva o principal "quente" com a replicação de dados do sistema principal. Mais informações podem ser encontradas nos relatórios do T + 2019 .

Todos esses sistemas têm uma coisa em comum: são bastante difíceis de operar. Implemente rapidamente um cluster de mais de 100 instâncias com redundância para 3 data centers, atualize o aplicativo que armazena dados sem tempo de inatividade e rebaixamentos de manutenção, faça uma restauração de backup em caso de catástrofe ou erros causados ​​pelo homem, garanta o failover discreto de componentes, organize o gerenciamento de configuração ... Em geral, uma tonelada interessante

E seria ótimo se tudo isso ainda fosse operado da maneira mais simples possível. O Kubernetes possibilita alcançar o resultado desejado, mas o uso de um operador especializado torna a vida ainda mais fácil.

Em vez de mil palavras


Preparamos um pequeno exemplo baseado no cartucho Tarantool e vamos trabalhar com ele. Um aplicativo simples como "armazenamento de valor-chave distribuído com interface HTTP". Após o lançamento, temos esta imagem:



Onde:

  • Roteadores - a parte do cluster responsável por aceitar e processar solicitações HTTP recebidas;
  • Armazenamentos é a parte do cluster responsável pelo armazenamento e processamento de dados; três fragmentos surgem da caixa, em cada mestre e réplica.

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

Precisamos do kubernetes 1.14+, o minikube funcionará . Além disso, a disponibilidade do kubectl não prejudicará. Para iniciar o operador, você precisa criar um ServiceAccount, Role e RoleBinding para ele:

$ 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, nós as criaremos:

 $ 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, vamos:

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

Estamos aguardando o início do operador e podemos iniciar o aplicativo:

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

No arquivo yaml com o exemplo, o Ingress é declarado na interface da web; está disponível em cluster_ip/admin/cluster . Quando pelo menos um Pod do Ingress está ativo, você pode ir lá e observar 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 

Esperamos que no Status do cluster haja o seguinte:

 … Status: State: Ready … 

Tudo, o aplicativo está pronto para uso!

Precisa de mais espaço de armazenamento? Adicione fragmentos:

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

Os fragmentos não conseguem lidar com a carga? Aumente o número de instâncias no shard editando o modelo de replicaset:

 $ kubectl edit replicasettemplates.tarantool.io storage-template 

Defina .spec.replicas , por exemplo 2, para aumentar o número de instâncias em cada replicaset para duas.

Um cluster não é mais necessário? Nós o excluímos junto com todos os recursos:

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

Algo deu errado? Pontuação do bilhete , vamos desmontar rapidamente. :)

O que o operador faz de todo


O lançamento e a operação do cluster Tarantool Cartridge é a história de executar determinadas ações, em uma ordem específica, em um determinado momento.

O cluster em si é gerenciado principalmente por meio da API de administração: GraphQL sobre HTTP. Você pode, é claro, descer um nível mais baixo e acionar comandos diretamente no console, mas isso raramente acontece. Por exemplo, é assim que o cluster é iniciado:

  1. Aumentamos o número necessário de instâncias do Tarantool, por exemplo, no systemd.
  2. Mesclar instâncias na associação:

     mutation { probe_instance: probe_server(uri: "storage:3301") } 

  3. Atribua funções a instâncias, prescreva identificadores de instância e replicaset. A API GraphQL também é usada para isso:

     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. Realizamos bootstrap do componente responsável pelo sharding. Também através da API:

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


Fácil né?

Tudo se torna mais interessante quando se trata de expandir um cluster. O papel dos roteadores do exemplo é dimensionado de forma simples: aumente mais instâncias, conecte-as a um cluster existente - pronto! O papel dos armazenamentos é um pouco mais complicado. O armazenamento é fragmentado; portanto, ao adicionar / remover instâncias, é necessário reequilibrar os dados para mudar para novas instâncias / para mudar de instâncias excluídas. Se isso não for feito, em um caso, teremos instâncias com carga insuficiente, no segundo - perderemos dados. E se não for apenas um, mas uma dúzia desses clusters com diferentes topologias estão em operação?

Em geral, o Tarantool Operator está ocupado com tudo isso. O usuário descreve o estado desejado do cluster do Tarantool Cartridge e o operador converte isso em um conjunto de ações nos recursos do k8s e em determinadas chamadas para as APIs do painel de administração do cluster Tarantool - em uma ordem específica, em um determinado momento e geralmente tenta ocultar todas as nuances do usuário.

Um pouco sobre as nuances


Ao trabalhar com a API do cluster administrativo do Tarantool Cartridge, é importante a ordem das chamadas e de onde elas são recebidas. Porque

O Tarantool Cartridge carrega seu repositório de topologia, seu componente de descoberta de serviço e seu 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 ... 

A atualização ocorre em conjunto usando o mecanismo de confirmação de duas fases . Uma atualização bem-sucedida requer um quorum de 100%: cada instância deve responder, caso contrário, a reversão. O que isso significa em termos de operação? Todas as solicitações à API do administrador que modificam o estado do cluster são mais confiáveis ​​para serem enviadas a uma instância, ao líder, 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 sabe como), e o Operador Tarantool pode - e você só pode saber sobre isso como um fato interessante, porque o operador estragará tudo.

Além disso, cada instância deve ter uma identidade fixa, ou seja, um conjunto de instance_uuid e replicaset_uuid , além de advertise_uri . Se o armazenamento reiniciar repentinamente e um desses parâmetros for alterado, você corre o risco de quebrar o quorum - o operador também faz isso.

Como o operador trabalha


A tarefa do operador é trazer o sistema para o estado definido pelo usuário e manter o sistema nesse estado até que novas direções sejam recebidas. Para que o operador possa executar seu trabalho, ele precisa:

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

O cluster do Tarantool Cartridge é descrito em termos de k8s por meio de uma definição de recurso personalizado (CRD) ; o operador precisa de 3 desses recursos personalizados, unidos no grupo tarantool.io/v1alpha:

  • O cluster é um recurso de nível superior que corresponde a um cluster do Tarantool Cartridge.
  • Função - em termos de cartucho Tarantool, essa é uma função do usuário .
  • ReplicasetTemplate - um modelo pelo qual os StatefulSets serão criados (por que stateful - vou lhe contar um pouco mais tarde; não confunda com o k8s ReplicaSet).

Todos esses recursos refletem diretamente o modelo de descrição de cluster do Tarantool Cartridge. Com um dicionário comum, é mais fácil para um operador se comunicar com os desenvolvedores e entender o que eles querem ver no produto.

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

  • ClusterController - é responsável por interagir com o cluster do Tarantool Cartridge, conecta instâncias ao cluster, desconecta instâncias do cluster.
  • RoleController - controlador de função de usuário, é responsável pela implantação de StatefulSets a partir do modelo e pela manutenção de seu número em um determinado número.

Como é um controlador? Um conjunto de códigos que gradualmente coloca o mundo ao seu redor em ordem. ClusterController pode ser representado esquematicamente assim:



Um ponto de entrada é uma verificação para ver se existe um recurso de cluster em relação ao qual o evento ocorreu. Não existe? Nós estamos indo embora. Existe? Passamos para o próximo bloco: conquistar a propriedade sobre as funções de usuário. Capturado um - esquerdo, no segundo círculo capturamos o segundo. E assim por diante, até capturarmos tudo. Todas as funções são capturadas? Então vá para o próximo bloco de operações. E assim, até chegarmos ao último; então podemos assumir que o sistema controlado está em um determinado estado.

Em geral, tudo é simples. É importante determinar os critérios de sucesso para passar em cada estágio. Por exemplo, consideramos bem-sucedida a operação de ingressar em um cluster não quando ele retornou sucesso condicional = true, mas quando retornou um erro como "já ingressado".

E a última parte desse mecanismo é a integração do controlador com o k8s. Vista aérea, todo o k8s consiste em um conjunto de controladores que geram eventos e respondem a eles. Os eventos passam por filas nas quais podemos nos inscrever. Esquematicamente, isso pode ser representado da seguinte maneira:



O usuário chama kubectl create -f tarantool_cluster.yaml , o recurso de cluster correspondente é criado. ClusterController é notificado sobre a criação de um recurso de cluster. E a primeira coisa que ele está tentando fazer é encontrar todos os recursos da função que devem fazer parte desse cluster. Se encontrar, designa Cluster como Proprietário da Função e atualiza o recurso Função. O RoleController recebe uma notificação de atualização de função, vê que o recurso tem um proprietário e começa a criar StatefulSets. E assim por diante em um círculo: o primeiro gatilho do segundo, o segundo gatilho do terceiro - e assim por diante até que alguém pare. E você também pode acionar a tempo, por exemplo, a cada 5 segundos, o que às vezes é útil.

Esse é o operador inteiro: crie um recurso personalizado e escreva um código que responda a eventos nos recursos.

O que o operador expande


As ações do operador levam os k8s a criar Pods e contêineres. No cluster do Tarantool Cartridge implantado nos k8s, todos os Pods são mesclados no StatefulSets.

Por que StatefulSet? Como escrevi anteriormente, cada instância do Tarantool Cluster mantém uma cópia da topologia e configuração do cluster e, geralmente, no servidor de aplicativos, não, não, e eles usam algum tipo de espaço, por exemplo, dados alternativos ou de referência, e esse já é um estado completo . E StatefulSet também garante a preservação dos Pods de identidade, o que é importante ao agrupar instâncias em um cluster: a identidade das instâncias deve ser corrigida; caso contrário, corremos o risco de perder o quorum ao reiniciar.

Quando todos os recursos do cluster são criados e trazidos para o estado desejado, eles formam a seguinte hierarquia:



As setas indicam o relacionamento Dependente do proprietário entre os recursos. É necessário que o Garbage Collector faça uma limpeza depois de nós no caso, por exemplo, da remoção do Cluster.

Além do StatefulSets, o Operador Tarantool cria o Serviço Sem Cabeça, necessário para a eleição do líder e, por meio dele, as instâncias se comunicam.

Sob o capô do operador Tarantool está a estrutura do operador, o próprio código do operador está em golang, nada de extraordinário aqui.

Sumário


Isso é tudo, em geral! Estamos aguardando seus comentários e tickets - onde, sem eles, a versão alfa é a mesma. O que vem a seguir? E, em seguida, há muito trabalho para lembrar tudo isso:

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

Cada um desses tópicos é extenso por si só e merece um material separado, aguarde atualizações!

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


All Articles