O que é escalonabilidade?
Em um cluster do Kubernetes, escalonabilidade refere-se à capacidade do cluster em crescer mantendo-se dentro de seus objetivos de nível de serviço (SLOs, na sigla em inglês). O Kubernetes também tem seu próprio conjunto de SLOs.
O Kubernetes é um sistema complexo, e a capacidade de escalonamento dele é determinada por vários fatores. Alguns desses fatores incluem o tipo e número de nós em um pool de nós, os tipos e números de pools de nós, o número de pods disponíveis, como os recursos são alocados aos pods e o número de serviços ou back-ends por trás de um serviço.
Práticas recomendadas de disponibilidade
Como escolher um plano de controle regional ou zonal
Devido às diferenças de arquitetura, os clusters regionais são mais adequados para alta disponibilidade. Os clusters regionais têm vários planos de controle em diversas zonas de computação de uma região, enquanto que os clusters zonais têm um plano de controle em uma única zona de computação.
Se o upgrade de um cluster zonal for realizado, a VM do plano de controle passará por um período de inatividade durante o qual a API Kubernetes não estará disponível até que o upgrade seja concluído.
Em clusters regionais, o plano de controle permanece disponível durante manutenções do cluster, como rotação de IPs, upgrade de VMs do plano de controle ou redimensionamento de clusters ou pools de nós. Ao fazer upgrade de um cluster regional, pelo menos uma das várias VMs do plano de controle fica sempre em execução durante a implementação do upgrade. Dessa forma, a API Kubernetes ainda estará disponível. Da mesma forma, uma interrupção de zona única não causará inatividade no plano de controle regional.
No entanto, os clusters regionais de maior disponibilidade vêm com algumas contrapartidas:
As alterações na configuração do cluster demoram mais porque precisam ser propagadas em todos os planos de controle de um cluster regional, em vez do plano de controle único de clusters zonais.
Talvez não seja possível criar ou fazer upgrade de clusters regionais com a mesma frequência dos clusters zonais. Se não for possível criar VMs em uma das zonas, seja por falta de capacidade ou por outro problema temporário, não será possível criar ou fazer o upgrade de clusters.
Devido a essas contrapartidas, os clusters locais e regionais têm diferentes casos de uso:
- Use clusters zonais para criar ou atualizar clusters rapidamente quando a disponibilidade não for um problema.
- Use clusters regionais quando disponibilidade for mais importante do que flexibilidade.
Selecione cuidadosamente o tipo de cluster a ser criado, porque não será possível alterá-lo depois de sua criação. Se necessário, crie um novo cluster e, em seguida, migre o tráfego para ele. Migrar o tráfego de produção entre clusters é possível, mas difícil em escala.
Como escolher pools de nós de zona única ou de várias zonas
Para conseguir alta disponibilidade, o plano de controle do Kubernetes e seus nós precisam estar espalhados por diferentes zonas. O GKE oferece dois tipos de pools de nós: de zona única e de várias zonas.
Para implantar um aplicativo altamente disponível, use pools de nó multizonais, que distribuem nós uniformemente em todas as zonas, para distribuir a carga de trabalho em várias zonas de computação em uma região.
Se todos os nós estiverem na mesma zona, não será possível agendar pods se essa zona ficar inacessível. O uso de pools de nós de várias zonas tem certas contrapartidas:
GPUs estão disponíveis apenas em zonas específicas. Talvez não seja possível obtê-los em todas as zonas da região.
A latência de ida e volta entre as zonas de uma única região pode ser maior que a entre os recursos em uma única zona. A diferença deve ser immaterial para a maioria das cargas de trabalho.
O preço do tráfego de saída entre zonas na mesma região está disponível na página de preços do Compute Engine.
Práticas recomendadas para escalonamento
Infraestrutura base
As cargas de trabalho do Kubernetes exigem rede, computação e armazenamento. É necessário fornecer CPU e memória suficientes para executar pods. No entanto, existem mais parâmetros de infraestrutura subjacente que podem influenciar o desempenho e a escalonabilidade de um cluster do GKE.
Rede de cluster
Usar um cluster nativo de VPC é o padrão de rede e a escolha recomendada para configurar novos clusters do GKE. Clusters nativos de VPC permitem cargas de trabalho maiores, maior número de nós e algumas outras vantagens.
Neste modo, a rede VPC tem um intervalo secundário para todos os endereços IP do pod. Cada nó recebe uma fatia do intervalo secundário para os próprios endereços IP do pod. Isso permite que a rede VPC compreenda nativamente como encaminhar o tráfego para pods sem depender de rotas personalizadas. Uma única rede VPC pode ter até 15.000 VMs.
Outra abordagem, que está obsoleta e não aceita mais de 1.500 nós, é usar um cluster baseado em rotas. Um cluster baseado em rotas não é adequado para grandes cargas de trabalho. Consome a cota de rotas da VPC e não oferece outros benefícios da rede nativa da VPC. Ele funciona adicionando uma nova rota personalizada à tabela de roteamento na rede VPC para cada novo nó.
Tamanho do cluster
Clusters com mais de 5.000 nós precisam usar o Private Service Connect. O Private Service Connect conecta nós e o plano de controle de maneira particular, além de oferecer mais segurança e melhor desempenho de rede.
Balanceamento de carga de cluster
O Cloud Load Balancing e o Ingress do GKE configuram e implantam balanceadores de carga para expor cargas de trabalho do Kubernetes fora do cluster e também para a Internet pública. Os controladores do Ingress e de serviço do GKE implantam objetos, como regras de encaminhamento, mapas de URL, serviços de back-end, grupos de endpoints de rede e muito mais, em nome das cargas de trabalho do GKE. Cada um desses recursos tem cotas e limites inerentes, e esses limites também se aplicam ao GKE. Quando um recurso específico do Cloud Load Balancing atinge sua cota, ele impede que um determinado Ingress ou serviço seja implantado corretamente, e os erros serão exibidos nos eventos do recurso.
Consulte na tabela a seguir os limites de escalonamento ao usar o Ingress e os serviços do GKE:
Balanceador de carga | Limite de nós por cluster |
---|---|
Balanceador de carga de rede de passagem interna |
|
Balanceador de carga de rede de passagem externa | 1000 nós por zona |
Balanceador de carga de aplicativo externo |
|
Balanceador de carga de aplicativo interno | Sem limite de nós |
Se precisar escalonar ainda mais, entre em contato com a equipe de vendas do Google Cloud para aumentar esse limite.
DNS
A descoberta de serviços no GKE é fornecida por meio do kube-dns, que é um recurso centralizado para fornecer resolução de DNS aos pods em execução no cluster. Isso pode se tornar um gargalo em clusters muito grandes ou para cargas de trabalho com carga de solicitação alta. O GKE faz escalonamento de maneira automática de kube-dns com base no tamanho do cluster para aumentar a capacidade. Quando essa capacidade ainda não é suficiente, o GKE oferece resolução local distribuída de consultas DNS em cada nó com DNSCache NodeLocal. Isso fornece um cache DNS local em cada nó do GKE que responde às consultas localmente, distribuindo a carga e fornecendo tempos de resposta mais rápidos.
Como gerenciar endereços IP em clusters nativos de VPC
Um cluster nativo de VPC usa três intervalos de endereços IP:
- Intervalo principal da sub-rede do nó: o padrão é /20 (endereços IP 4.092).
- Intervalo secundário da sub-rede do pod: o padrão é /14 (262.144 endereços IP). No entanto, é possível configurar a sub-rede do pod.
- Intervalo secundário da sub-rede de serviço: o padrão é /20 (4.096 endereços). No entanto, não será possível alterar esse intervalo depois de criar essa sub-rede de serviço.
Para mais informações, consulte Intervalos de endereço IP para clusters nativos de VPC.
Limitações e recomendações de endereços IP:
- Limite de nós: esse limite é determinado pelos endereços IP principal e do pod por nó. É preciso que haja endereços suficientes nos intervalos de endereços IP do nó e do pod para provisionar um novo nó. Por padrão, é possível criar apenas 1.024 nós devido a limitações de endereços IP do pod.
- Limite de pods por nó: por padrão, o limite de pods por nó é de 110. No entanto, é possível configurar CIDRs de pods menores para uso eficiente com menos pods por nó.
- Escalonamento além do RFC 1918: se você precisar de mais endereços IP do que o disponível no espaço privado definido pelo RFC 1918, recomendamos usar endereços privados não RFC 1918 ou PUPIs para ter mais flexibilidade.
- Intervalo de endereços IP secundário para o serviço e o pod: por padrão, é possível configurar 4.096 serviços. No entanto, é possível configurar mais serviços escolhendo o intervalo de sub-rede de serviço. Não é possível modificar intervalos secundários após a criação. Ao criar um cluster, escolha intervalos grandes o suficiente para acomodar o crescimento previsto. No entanto, é possível adicionar mais endereços IP para pods depois usando o CIDR de vários pods descontínuos.
Para ver mais informações, consulte os seguintes tópicos:
- Não há espaço de endereço IP livre suficiente para pods
- Intervalos de limitação de nós
- Planejar endereços IP ao migrar para o GKE
Como configurar nós para melhorar o desempenho
Os nós do GKE são máquinas virtuais Google Cloud normais. Alguns de seus parâmetros como, por exemplo, o número de núcleos ou o tamanho do disco, podem influenciar o desempenho dos clusters do GKE.
Como reduzir os tempos de inicialização do pod
É possível usar o streaming de imagem para fazer streaming de dados de imagens de contêiner qualificadas conforme suas cargas de trabalho as solicitam, o que leva a tempos de inicialização mais rápidos.
Tráfego de saída
No Google Cloud, o tipo de máquina e o número de núcleos alocados à instância determinam a capacidade de rede dela. A largura de banda de saída máxima varia de 1 a 32 Gbps, enquanto a de máquinas e2-medium-2 padrão é 2 Gbps. Para saber mais sobre esses limites, consulte Tipos de máquinas com núcleo compartilhado.
IOPS e capacidade de disco
No Google Cloud, o tamanho dos discos permanentes determina a IOPS e a capacidade do disco. Normalmente, o GKE usa discos permanentes como discos de inicialização e suporte aos volumes permanentes do Kubernetes. Aumentar o tamanho do disco aumenta a IOPS e a capacidade, até certos limites.
Cada operação de gravação do disco permanente contribui para o limite de saída de rede cumulativo da instância da máquina virtual (VM, na sigla em inglês). Assim, o desempenho de IOPS de discos, especialmente SSDs, também depende do número de vCPUs na instância, além do tamanho do disco. As VMs de núcleo inferior têm limites de IOPS de gravação mais baixos devido às limitações de saída de rede na capacidade de gravação.
Se a instância de máquina virtual não tiver CPUs suficientes, o aplicativo não será capaz de chegar perto do limite de IOPS. Como regra geral, é necessária uma CPU disponível para cada 2.000 a 2.500 IOPS de tráfego esperado.
As cargas de trabalho que exigem alta capacidade ou grande número de discos precisam considerar os limites de quantos PDs podem ser anexados a uma única VM. Para VMs regulares, esse limite é de 128 discos com um tamanho total de 64 TB, enquanto as VMs de núcleo compartilhado têm um limite de 16 PDs com um tamanho total de 3 TB.O Google Cloud impõe esse limite, não o Kubernetes.
Monitorar métricas do plano de controle
Use as métricas do plano de controle disponíveis para configurar os painéis de monitoramento. Use as métricas do plano de controle para observar a integridade do cluster, os resultados das alterações de configuração do cluster (por exemplo, implantar cargas de trabalho adicionais ou componentes de terceiros) ou resolver problemas.
Uma das métricas mais importantes a serem monitoradas é a latência da API Kubernetes. Aumentos na latência indicam que o sistema está sobrecarregado. Lembre-se de que é esperado que as chamadas LIST que transferem grandes quantidades de dados tenham uma latência muito maior do que as solicitações menores.
O aumento da latência da API Kubernetes também pode ser causado por respostas lentas de webhooks de admissão de terceiros. É possível usar métricas para medir a latência dos webhooks e detectar problemas comuns.
O limite superior sugerido para uma chamada de recurso único, como GET, POST ou PATCH, é de um segundo. O limite superior sugerido para chamadas LIST com escopo de namespace e de cluster é de 30 segundos. As expectativas de limite superior são definidas por SLOs definidos pela comunidade de código aberto do Kubernetes. Para mais informações, consulte Detalhes dos SLIs/SLOs de latência da chamada de API.
Práticas recomendadas para desenvolvedores do Kubernetes
Usar padrão de lista e de relógio em vez de listagem periódica
Como desenvolvedor do Kubernetes, talvez seja necessário criar um componente com os seguintes requisitos:
- Seu componente precisa recuperar a lista de alguns objetos do Kubernetes periodicamente.
- Seu componente precisa ser executado em várias instâncias (no caso de DaemonSet, mesmo em cada nó).
Esse componente pode gerar picos de carga no kube-apiserver, mesmo que o estado de objetos recuperados periodicamente não mude.
A abordagem mais simples é usar chamadas LIST periódicas. No entanto, essa é uma abordagem ineficiente e cara para o autor da chamada e o servidor porque todos os objetos precisam ser carregados na memória, serializados e transferidos a cada vez. O uso excessivo de solicitações LIST pode sobrecarregar o plano de controle ou gerar uma limitação pesada dessas solicitações.
É possível melhorar o componente definindo o parâmetro resourceVersion=0 nas chamadas LIST. Isso permite que o kube-apiserver use o cache de objetos na memória e reduz a frequência com que o servidor da API Kubernetes interage com a API etcd, o que também reduz qualquer processamento relacionado.
É altamente recomendável evitar chamadas LIST repetíveis e substituí-las pelo padrão de lista e de observação. Liste os objetos uma vez e use a API Watch para receber mudanças incrementais do estado. Essa abordagem reduz o tempo de processamento e minimiza o tráfego em comparação com chamadas LIST periódicas. Quando os objetos não mudam, nenhuma carga adicional é gerada.
Se você usar a linguagem Go, verifique o SharedInformer e o SharedInformerFactory para acessar pacotes Go que implementam esse padrão.
Limitar tráfego desnecessário gerado por relógios e listas
O Kubernetes usa relógios para enviar notificações sobre atualizações de objetos. Mesmo com relógios que exigem muito menos recursos do que chamadas LIST periódicas, o processamento de relógios em clusters grandes pode levar uma parte significativa dos recursos do cluster e afetar o desempenho do cluster. O maior impacto negativo é gerado com a criação de relógios que observam objetos em constante mudança de vários lugares. Por exemplo, observando os dados sobre todos os pods de um componente em execução em todos os nós. Se você instalar códigos ou extensões de terceiros no cluster, eles poderão criar esses relógios em segundo plano.
Recomendamos as seguintes práticas recomendadas:
- Reduza o processamento e o tráfego desnecessários gerados por relógios e chamadas LIST.
- Evite criar relógios que observem objetos alterados com frequência de vários lugares (por exemplo, DaemonSets).
- (altamente recomendável) criar um controlador central que observe e processe os dados necessários em um único nó.
- Observe apenas um subconjunto dos objetos, como o kubelet em cada nó. Observe apenas os pods programados no mesmo nó.
- Evite implantar componentes ou extensões de terceiros que possam afetar o desempenho do cluster fazendo um volume alto de relógios ou chamadas LIST.
Use atualizações graduais com DaemonSets para evitar aumentos repentinos de tráfego
Quando um DaemonSet é criado em um cluster, ele programa um novo pod em todos os nós
imediatamente. Se todos esses novos pods se conectarem ao mesmo endpoint de rede, essas solicitações vão ocorrer simultaneamente, o que vai colocar uma carga alta no host de destino. Para evitar isso, configure seus DaemonSets com atualizações rotativas com pods maxSurge
limitados.
Limitar o tamanho do manifesto do objeto do Kubernetes
Se você precisar de operações rápidas que exijam alta capacidade de processamento do pod, como redimensionamento ou atualização de grandes cargas de trabalho, mantenha os tamanhos dos manifestos do pod para um mínimo, idealmente menor que 10 KiB.
O Kubernetes armazena manifestos de recursos em um banco de dados que é um armazenamento de chave-valor. O manifesto inteiro é enviado sempre que o recurso é recuperado, inclusive quando você usa a lista e o padrão de observação.
O tamanho do manifesto tem as seguintes limitações:
- Tamanho máximo de cada manifesto de objeto: aproximadamente 1,5 MiB.
- Cota total para todos os objetos da API Kubernetes no cluster:o tamanho da cota pré-configurada é de 6 GiB. Isso inclui um registro de mudanças com todas as atualizações de todos os objetos nos últimos 150 segundos do histórico do cluster.
- Desempenho do plano de controle durante períodos de tráfego intenso: tamanhos de manifesto maiores aumentam a carga no servidor da API.
Para objetos únicos e raramente processados, o tamanho do manifesto geralmente não é uma preocupação, desde que seja inferior a 1,5 MiB. No entanto, tamanhos de manifesto maiores que 10 KiB para vários objetos processados com frequência, como pods em cargas de trabalho muito grandes, podem aumentar a latência da chamada de API e diminuir o desempenho geral. Listas e observações podem ser significativamente afetados por tamanhos grandes de manifestos. Você também pode ter problemas com a cota do banco de dados de estado do cluster, porque a quantidade de revisões nos últimos 150 segundos pode se acumular rapidamente durante períodos de alto tráfego do servidor da API.
Para reduzir o tamanho do manifesto de um pod, os ConfigMaps do Kubernetes podem ser aproveitados para armazenar parte da configuração, especialmente a parte compartilhada por vários pods no cluster. Por exemplo, as variáveis de ambiente geralmente são compartilhadas por todos os pods em uma carga de trabalho.
Também é possível enfrentar problemas semelhantes com objetos ConfigMap se eles forem tão numerosos, grandes e processados com a mesma frequência que os pods. Extrair parte da configuração é mais útil quando diminui o tráfego geral.
Desativar a ativação automática da conta de serviço padrão
Se a lógica em execução nos pods não precisar acessar a API Kubernetes, desative a montagem padrão e automática da conta de serviço para evitar a criação de secrets e relógios relacionados.
Quando você cria um pod sem especificar uma conta de serviço, o Kubernetes realiza automaticamente as seguintes ações:
- Atribui a conta de serviço padrão ao pod.
- Monta as credenciais da conta de serviço como um Secret para o pod.
- Para cada Secret ativado, o kubelet cria um relógio para observar as alterações nesse Secret em cada nó.
Em clusters grandes, essas ações representam milhares de relógios desnecessários, que podem colocar uma carga significativa no kube-apiserver.
Usar buffers de protocolo em vez de JSON para solicitações de API
Use buffers de protocolo para implementar componentes altamente escalonáveis, conforme descrito nos Conceitos da API Kubernetes.
A API REST do Kubernetes é compatível com buffers JSON e de protocolo como um formato de serialização para objetos. O JSON é usado por padrão, mas os buffers de protocolo são mais eficientes para o desempenho em escala porque exigem menos processamento intensivo da CPU e envio de menos dados pela rede. A sobrecarga relacionada ao processamento de JSON pode causar tempos limite ao listar dados de tamanho grande.