
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:
- Em vez de mil palavras
- O que o operador faz de todo
- Um pouco sobre as nuances
- Como o operador trabalha
- O que o operador expande
- 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:
- Aumentamos o número necessário de instâncias do Tarantool, por exemplo, no systemd.
- Mesclar instâncias na associação:
mutation { probe_instance: probe_server(uri: "storage:3301") }
- 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 ) }
- 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:
- Descrição do status do sistema.
- O código que leva o sistema a esse estado.
- 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!