Planejar a escalonabilidade


Nesta página, descrevemos as práticas recomendadas gerais para arquitetar clusters do GKE escalonáveis. É possível aplicar essas recomendações a todos os clusters e as cargas de trabalho para alcançar o desempenho ideal. Essas recomendações são especialmente importantes para clusters que você planeja escalonar amplamente. As práticas recomendadas são destinadas a administradores responsáveis pelo provisionamento da infraestrutura e aos desenvolvedores que preparam componentes e cargas de trabalho do Kubernetes.

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, duas das três VMs do plano de controle ficarão 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ó.

Clusters particulares

Em clusters normais do GKE, todos os nós têm endereços IP públicos. Nos clusters particulares, os nós têm apenas endereços IP internos para isolá-los da conectividade de entrada e de saída com a Internet. O GKE usa o peering de rede VPC para conectar VMs que executam o servidor da API Kubernetes com o restante do cluster. Isso permite maior capacidade entre planos de controle e nós do GKE, já que o tráfego é roteado usando endereços IP particulares.

O uso de clusters particulares tem o benefício de segurança adicional de que os nós não estão expostos à Internet.

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 a 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, certifique-se de escolher intervalos grandes o suficiente para acomodar o crescimento previsto. No entanto, é possível adicionar mais endereços IP para pods posteriormente usando o CIDR de vários pods descontínuos. Para mais informações, consulte Não há espaço IP livre suficiente para pods.

Para mais informações, consulte intervalos de limitação de nós e 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 do 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.

Cargas de trabalho que exigem alta capacidade ou grande quantidade de discos precisam considerar os limites de quantos DPs podem ser anexados a uma única VM. Para VMs regulares, esse limite é de 128 discos com um tamanho total de 64 TB, enquanto VMs de núcleo compartilhado têm um limite de 16 DPs, com um tamanho total de 3 TB. Esse limite é aplicado pelo Google Cloud, e não pelo 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. Quando a latência aumenta, isso indica 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 pela lentidão na resposta de webhooks de admissão de terceiros. É possível usar métricas para medir a latência dos webhooks e detectar problemas comuns.

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 reduza o número de interações internas entre o kube-apiserver, o banco de dados etcd e o 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.

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 abaixo de 10 KiB.

O Kubernetes armazena manifestos de recursos no etcd. 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 objeto no etcd: aproximadamente 1,5 MiB.
  • Cota total para todos os objetos etcd no cluster: o tamanho da cota pré-configurada é de 6 GiB. Isso inclui um registro de alterações 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 acima de 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 etcd, porque a quantidade de revisões nos últimos 150 segundos pode se acumular rapidamente durante os 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.

A seguir