
Estamos felizes em anunciar que a empresa "Flant" está expandindo sua contribuição para ferramentas de Open Source para Kubernetes, lançando (Container Storage Interface) para Yandex.Cloud.
Mas antes de entrarmos nos detalhes da implementação, vamos responder à pergunta, por que isso é necessário, quando o Yandex já possui o serviço .
Introdução
Por que isso?
Dentro da nossa empresa, desde o início da operação do Kubernetes em produção (ou seja, há vários anos), desenvolvemos uma ferramenta própria (deckhouse), que, por sinal, também planejamos tornar disponível em breve como um projeto Open Source. Com ela, configuramos e ajustamos uniformemente todos os nossos clusters, e atualmente já são mais de 100, em diferentes configurações de hardware e em todos os serviços de nuvem disponíveis.
Os clusters que utilizam o deckhouse possuem todos os componentes necessários para funcionar: balanceadores, monitoramento com gráficos e métricas amigáveis, alertas, autenticação de usuários através de provedores externos para acesso a todos os dashboards, e assim por diante. Um cluster "potente" como esse não faz sentido ser colocado em uma solução gerenciada, pois muitas vezes isso é impossível, ou levará à necessidade de desativar metade dos componentes.
NB: Esta é a nossa experiência, e ela é bastante específica. De forma alguma afirmamos que todos devem lidar com a configuração de clusters Kubernetes em vez de utilizar soluções prontas. Vale ressaltar que não temos experiência real no uso do Kubernetes da parte do Yandex e não faremos uma avaliação deste serviço neste artigo.
O que é isso e para quem?
Assim, já falamos sobre a abordagem moderna para armazenamento em Kubernetes: e a essa abordagem.
Atualmente, muitos grandes provedores de serviços em nuvem desenvolveram drivers para utilizar seus "discos de nuvem" como Persistent Volume no Kubernetes. Se o provedor não tiver tal driver, mas todas as funções necessárias forem oferecidas através de API, nada impede a implementação de um driver por conta própria. Assim, foi como conseguimos com o Yandex.Cloud.
Tomamos como base para o desenvolvimento e algumas ideias do já que a interação com as APIs dessas nuvens (Google e Yandex) possui várias semelhanças. Em particular, as APIs de ambos e retorna um objeto Operação para monitorar o status de operações longas (por exemplo, a criação de um novo disco). Para interagir com a API do Yandex.Cloud, utiliza-se .
O resultado do trabalho realizado e pode ser útil para aqueles que, por algum motivo, usam sua própria instalação do Kubernetes em máquinas virtuais do Yandex.Cloud (mas não um cluster gerenciado pronto) e gostariam de usar (encomendar) discos através do CSI.
Implementação
Principais funcionalidades
Atualmente, o driver suporta as seguintes funções:
- Encomenda de discos em todas as zonas do cluster de acordo com a topologia dos nós disponíveis no cluster;
- Remoção de discos encomendados anteriormente;
- Redimensionamento offline para discos (Yandex.Cloud aumentando discos que estão montados na máquina virtual). Sobre como foi necessário melhorar o driver para realizar o redimensionamento da forma mais indolor possível, veja abaixo.
Futuramente, está previsto implementar o suporte à criação e remoção de snapshots de discos.
A principal dificuldade e sua superação
A ausência na API do Yandex.Cloud da possibilidade de aumentar discos em tempo real é uma limitação que complica a operação de redimensionamento para PV (Volume Persistente): neste caso, é necessário que o pod da aplicação que utiliza o disco esteja parado, o que pode causar a inatividade da aplicação.
De acordo com , se o controlador CSI informa que só consegue fazer resize de discos «offline» (VolumeExpansion.OFFLINE), então o processo de aumento do disco deve ocorrer da seguinte forma:
Se o plugin tem apenas
VolumeExpansion.OFFLINEcapacidade de expansão e o volume está atualmente publicado ou disponível em um nó, entãoControllerExpandVolumeDEVE ser chamado SOMENTE após uma das seguintes condições:
- O plugin tem capacidade de controlador
PUBLISH_UNPUBLISH_VOLUMEeControllerUnpublishVolumefoi invocado com sucesso.OU
- O plugin NÃO possui capacidade de controlador, o plugin tem
PUBLISH_UNPUBLISH_VOLUMEcapacidade de nóSTAGE_UNSTAGE_VOLUMEeNodeUnstageVolumefoi concluído com sucesso.OU
- O plugin NÃO possui capacidade de controlador, o plugin tem
PUBLISH_UNPUBLISH_VOLUMEcapacidade, nem nóSTAGE_UNSTAGE_VOLUMEeNodeUnpublishVolumefoi concluído com sucesso.
Isso essencialmente significa que é necessário desconectar o disco da máquina virtual antes de aumentá-lo.
No entanto, infelizmente, implementação as especificações do CSI através dos sidecars não atendem a esses requisitos:
- No container sidecar
csi-attacher, que deve ser responsável por garantir o espaço adequado entre as montagens, esse funcionalidade não foi implementada no redimensionamento offline. A discussão sobre isso foi iniciada . - O que é, afinal, um contêiner sidecar nesse contexto? O próprio plugin CSI não interage com a API do Kubernetes, apenas reage a chamadas gRPC que são enviadas a ele pelos contêineres sidecar. Os últimos são da comunidade Kubernetes.
No nosso caso (plugin CSI), a operação de aumento de disco parece da seguinte maneira:
- Recebemos uma chamada gRPC
ControllerExpandVolume; - Tentamos aumentar o disco na API, mas recebemos um erro de operação não permitida, pois o disco está montado;
- Salvamos o identificador do disco em um mapa que contém discos para os quais é necessária a operação de aumento. Daqui em diante, para abreviar, chamaremos esse mapa de
volumeResizeRequired; - Removemos manualmente o pod que está utilizando o disco. O Kubernetes o reiniciará. Para que o disco não seja montado (
ControllerPublishVolume) antes da conclusão da operação de aumento durante a tentativa de montagem, verificamos se este disco ainda está emvolumeResizeRequirede retornamos um erro; - O driver CSI tenta repetir a operação de resize. Se a operação for bem-sucedida, removemos o disco de
volumeResizeRequired; - Como o identificador do disco não está presente em
volumeResizeRequired,ControllerPublishVolumea operação é bem-sucedida, o disco é montado e o pod é iniciado.
Tudo parece bastante simples, mas como sempre há armadilhas. O aumento dos discos é feito por , que em caso de erro ao realizar a operação com aumento exponencial do tempo de tempo limite até 1000 segundos:
func DefaultControllerRateLimiter() RateLimiter {
return NewMaxOfRateLimiter(
NewItemExponentialFailureRateLimiter(5*time.Millisecond, 1000*time.Second),
// 10 qps, 100 bucket size. Isso é apenas para velocidade de repetição e é apenas o fator geral (não por item)
&BucketRateLimiter{Limiter: rate.NewLimiter(rate.Limit(10), 100)},
)
}Isso pode ocasionalmente fazer com que a operação de aumento de disco se prolongue por mais de 15 minutos, resultando assim na indisponibilidade do pod correspondente.
A única opção que nos permitiu reduzir o tempo potencial de inatividade de forma relativamente fácil foi usar nossa própria versão do external-resizer com um limite máximo de tempo limite :
workqueue.NewItemExponentialFailureRateLimiter(5*time.Millisecond, 5*time.Second)Não achamos necessário iniciar uma discussão urgente e corrigir o external-resizer, pois o resize offline de discos é um atavismo que em breve desaparecerá de todos os provedores de nuvem.
Como começar a usar?
O driver é suportado nas versões do Kubernetes 1.15 e superiores. Para que o driver funcione, os seguintes requisitos devem ser atendidos:
- A bandeira
--allow-privilegeddefinido comoverdadeiropara o API server e kubelet; - Ativado
--feature-gates=VolumeSnapshotDataSource=true,KubeletPluginsWatcher=true,CSINodeInfo=true,CSIDriverRegistry=truepara o API server e kubelet; - A propagação de montagem () deve ser habilitada no cluster. Ao usar o Docker, o daemon deve ser configurado para permitir montagens compartilhadas.
Todos os passos necessários para a instalação . A instalação envolve a criação de objetos no Kubernetes a partir de manifestos.
Para o funcionamento do driver, você precisará do seguinte:
- especificar no manifesto o identificador do diretório (
folder-id) do Yandex.Cloud (); - . Para interagir com a API do Yandex.Cloud no driver CSI, é utilizado uma conta de serviço. No manifesto Secret, é necessário fornecer da conta de serviço. Na documentação , como criar uma conta de serviço e obter as chaves.
Em geral — , e ficaremos felizes com seu feedback e , caso encontre alguma dificuldade!
Suporte adicional
Por fim, gostaríamos de destacar que este driver CSI foi desenvolvido não por um grande desejo de nos divertir escrevendo aplicativos em Go, mas por uma necessidade urgente dentro da empresa. Consideramos que manter nossa própria implementação não é viável, portanto, se o Yandex demonstrar interesse e decidir continuar o suporte ao driver, ficaremos felizes em transferir o repositório para eles.
Além disso, provavelmente o Yandex tem sua própria implementação do driver CSI no cluster Kubernetes gerenciado, que pode ser lançado como Open Source. Essa opção de desenvolvimento também nos parece favorável — a comunidade poderá usar um driver testado do provedor de serviços, em vez de uma empresa externa.
P.S.
Confira também em nosso blog:
- «»;
- «»;
- «»;
- «».
Fonte: habr.com
