Planeie a escalabilidade

Esta página descreve as práticas recomendadas gerais para criar arquiteturas de clusters do GKE escaláveis. Pode aplicar estas recomendações em todos os clusters e cargas de trabalho para alcançar o desempenho ideal. Estas recomendações são especialmente importantes para clusters que planeia escalar em grande medida. As práticas recomendadas destinam-se aos administradores responsáveis pelo aprovisionamento da infraestrutura e aos programadores que preparam os componentes e as cargas de trabalho do Kubernetes.

O que é a escalabilidade?

Num cluster do Kubernetes, a escalabilidade refere-se à capacidade do cluster de crescer, mantendo-se dentro dos seus objetivos ao nível do serviço (SLOs). O Kubernetes também tem o seu próprio conjunto de SLOs

O Kubernetes é um sistema complexo e a sua capacidade de escalabilidade é determinada por vários fatores. Alguns destes fatores incluem o tipo e o número de nós num conjunto de nós, os tipos e os números de conjuntos de nós, o número de pods disponíveis, como os recursos são atribuídos aos pods e o número de serviços ou back-ends por detrás de um serviço.

Práticas recomendadas para a disponibilidade

Escolher um plano de controlo regional ou zonal

Devido às diferenças de arquitetura, os clusters regionais são mais adequados para a alta disponibilidade. Os clusters regionais têm vários planos de controlo em várias zonas de computação numa região, enquanto os clusters zonais têm um plano de controlo numa única zona de computação.

Se um cluster zonal for atualizado, a VM do plano de controlo sofre uma indisponibilidade durante a qual a API Kubernetes não está disponível até a atualização estar concluída.

Nos clusters regionais, o plano de controlo permanece disponível durante a manutenção do cluster, como a rotação de IPs, a atualização de VMs do plano de controlo ou a alteração do tamanho dos clusters ou dos node pools. Quando atualiza um cluster regional, pelo menos uma das várias VMs do plano de controlo está sempre em execução durante a atualização contínua, pelo que a API Kubernetes continua disponível. Da mesma forma, uma indisponibilidade de uma única zona não causa qualquer tempo de inatividade no painel de controlo regional.

No entanto, os clusters regionais de maior disponibilidade têm determinadas desvantagens:

  • As alterações à configuração do cluster demoram mais tempo porque têm de se propagar por todos os planos de controlo num cluster regional, em vez do plano de controlo único nos clusters zonais.

  • Pode não conseguir criar ou atualizar clusters regionais com a mesma frequência que os clusters zonais. Se não for possível criar VMs numa das zonas, seja por falta de capacidade ou outro problema transitório, não é possível criar nem atualizar clusters.

Devido a estas concessões, os clusters zonais e regionais têm diferentes exemplos de utilização:

  • Use clusters zonais para criar ou atualizar clusters rapidamente quando a disponibilidade não for uma preocupação.
  • Use clusters regionais quando a disponibilidade for mais importante do que a flexibilidade.

Selecione cuidadosamente o tipo de cluster quando criar um cluster, uma vez que não o pode alterar depois de o cluster ser criado. Em alternativa, tem de criar um novo cluster e, em seguida, migrar o tráfego para o mesmo. A migração do tráfego de produção entre clusters é possível, mas difícil em grande escala.

Escolher pools de nós de várias zonas ou de zona única

Para alcançar uma elevada disponibilidade, o painel de controlo do Kubernetes e os respetivos nós têm de ser distribuídos por diferentes zonas. O GKE oferece dois tipos de pools de nós: de zona única e multizonal.

Para implementar uma aplicação de elevada disponibilidade, distribua a sua carga de trabalho por várias zonas de computação numa região através de pools de nós multizonais que distribuem os nós uniformemente pelas zonas.

Se todos os seus nós estiverem na mesma zona, não pode agendar pods se essa zona ficar inacessível. A utilização de node pools multizonais tem determinadas desvantagens:

  • As GPUs só estão disponíveis em zonas específicas. Pode não ser possível obtê-los em todas as zonas da região.

  • A latência de ida e volta entre zonas numa única região pode ser superior à latência entre recursos numa única zona. A diferença deve ser irrelevante 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 a escala

Infraestrutura de base

As cargas de trabalho do Kubernetes requerem redes, computação e armazenamento. Tem de fornecer CPU e memória suficientes para executar pods. No entanto, existem mais parâmetros da infraestrutura subjacente que podem influenciar o desempenho e a escalabilidade de um cluster do GKE.

Trabalho em rede de clusters

A utilização de um cluster nativo de VPC é a predefinição de rede e a opção recomendada para configurar novos clusters do GKE. Os clusters nativos de VPC permitem cargas de trabalho maiores, um número mais elevado de nós e algumas outras vantagens.

Neste modo, a rede VPC tem um intervalo secundário para todos os endereços IP dos pods. Em seguida, é atribuído a cada nó um segmento do intervalo secundário para os respetivos endereços IP do agrupamento. Isto permite que a rede VPC compreenda nativamente como encaminhar o tráfego para os pods sem depender de rotas personalizadas. Uma única rede de VPC pode ter até 15 000 VMs.

Outra abordagem, que está descontinuada e suporta não mais de 1500 nós, é usar um cluster baseado em trajetos. Um cluster baseado em rotas não é adequado para cargas de trabalho grandes. Consome a quota de rotas da VPC e não tem outras vantagens das redes nativas da VPC. Funciona adicionando uma nova rota personalizada à tabela de encaminhamento na rede VPC para cada novo nó.

Tamanho do cluster

Os clusters com mais de 5000 nós têm de usar o Private Service Connect. O Private Service Connect liga nós e o plano de controlo de forma privada e oferece melhor segurança e desempenho da rede.

Balanceamento de carga do cluster

O GKE Ingress e o Cloud Load Balancing configuram e implementam equilibradores de carga para expor cargas de trabalho do Kubernetes fora do cluster e também à Internet pública. Os controladores GKE Ingress e Service implementam objetos, como regras de encaminhamento, mapas de URLs, serviços de back-end, grupos de pontos finais da rede e muito mais, em nome das cargas de trabalho do GKE. Cada um destes recursos tem quotas e limites inerentes, e estes limites também se aplicam no GKE. Quando um recurso específico do Cloud Load Balancing atinge a respetiva quota, impede a implementação correta de um determinado Ingress ou serviço, e são apresentados erros nos eventos do recurso.

A tabela seguinte descreve os limites de escalabilidade quando usa o GKE Ingress e os serviços:

Balanceador de carga Limite de nós por cluster
Balanceador de carga de rede de encaminhamento interno
Balanceador de carga de rede de encaminhamento externo 1000 nós por zona
Balanceador de carga de aplicações externo
Balanceador de carga de aplicações interno Sem limite de nós

Se precisar de aumentar ainda mais a escala, contacte a sua Google Cloud equipa de vendas para aumentar este limite.

DNS

A deteção de serviços no GKE é fornecida através do kube-dns, que é um recurso centralizado para fornecer resolução de DNS aos pods em execução no cluster. Isto pode tornar-se um gargalo em clusters muito grandes ou para cargas de trabalho com uma carga de pedidos elevada. O GKE cria automaticamente uma escala automática do kube-dns com base no tamanho do cluster para aumentar a respetiva capacidade. Quando esta capacidade ainda não é suficiente, o GKE oferece uma resolução distribuída e local de consultas DNS em cada nó com o NodeLocal DNSCache. Isto fornece uma cache DNS local em cada nó do GKE que responde a consultas localmente, distribuindo a carga e oferecendo tempos de resposta mais rápidos.

Gerir endereços IP em clusters nativos de VPC

Um cluster nativo de VPC usa três intervalos de endereços IP:

  • Intervalo principal para a sub-rede do nó: a predefinição é /20 (4092 endereços IP).
  • Intervalo secundário para a sub-rede do agrupamento: predefinição de /14 (262 144 endereços IP). No entanto, pode configurar a sub-rede do pod.
  • Intervalo secundário para a sub-rede de serviço: predefinição de /20 (4096 endereços). No entanto, não pode alterar este intervalo depois de criar esta sub-rede de serviço.

Para mais informações, consulte o artigo Intervalos de endereços IP para clusters nativos da VPC.

Limitações e recomendações de endereços IP:

  • Limite de nós: o limite de nós é determinado pelos endereços IP primários e dos pods por nó. Tem de haver endereços suficientes nos intervalos de endereços IP do nó e do agrupamento para aprovisionar um novo nó. Por predefinição, só pode criar 1024 nós devido às limitações do endereço IP do pod.
  • Limite de agrupamentos por nó: por predefinição, o limite de agrupamentos por nó é de 110 agrupamentos. No entanto, pode configurar CIDRs de pods mais pequenos para uma utilização eficiente com menos pods por nó.
  • Escalar para além da RFC 1918: se precisar de mais endereços IP do que os disponíveis no espaço privado definido pela RFC 1918, recomendamos que use endereços privados não RFC 1918 ou PUPIs para ter flexibilidade adicional.
  • Intervalo de endereços IP secundários para o serviço e o pod: por predefinição, pode configurar 4096 serviços. No entanto, pode configurar mais serviços escolhendo o intervalo da sub-rede de serviços. Não pode modificar intervalos secundários após a criação. Quando criar um cluster, certifique-se de que escolhe intervalos suficientemente grandes para acomodar o crescimento previsto. No entanto, pode adicionar mais endereços IP para pods posteriormente através do CIDR de vários pods não contíguos.

Para mais informações, consulte o seguinte:

Configurar nós para um melhor desempenho

Os nós do GKE são Google Cloud máquinas virtuais normais. Alguns dos respetivos parâmetros, por exemplo, o número de núcleos ou o tamanho do disco, podem influenciar o desempenho dos clusters do GKE.

Reduzir os tempos de inicialização do pod

Pode usar o streaming de imagens para fazer streaming de dados de imagens de contentores elegíveis à medida que as suas cargas de trabalho os pedem, 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 atribuídos à instância determinam a respetiva capacidade de rede. A largura de banda de saída máxima varia entre 1 e 32 Gbps, enquanto a largura de banda de saída máxima para máquinas e2-medium-2 predefinidas é de 2 Gbps. Para ver detalhes sobre os limites de largura de banda, consulte o artigo Tipos de máquinas com núcleo partilhado.

IOPS e débito do disco

No Google Cloud, o tamanho dos discos persistentes determina os IOPS e a capacidade de processamento do disco. Normalmente, o GKE usa discos persistentes como discos de arranque e para fazer uma cópia de segurança dos volumes persistentes do Kubernetes. O aumento do tamanho do disco aumenta as IOPS e a taxa de transferência, até determinados limites.

Cada operação de gravação em disco persistente contribui para o limite de saída de rede cumulativo da instância da máquina virtual. Assim, o desempenho de IOPS dos discos, especialmente os SSDs, também depende do número de vCPUs na instância, além do tamanho do disco. As VMs com menos núcleos têm limites de IOPS de escrita mais baixos devido às limitações de saída da rede na taxa de transferência de escrita.

Se a instância da máquina virtual tiver CPUs insuficientes, a sua aplicação não vai conseguir aproximar-se do limite de IOPS. Como regra geral, deve ter uma CPU disponível para cada 2000 a 2500 IOPS de tráfego esperado.

As cargas de trabalho que requerem uma capacidade elevada ou um grande número de discos têm de ter em conta os limites de quantos PDs podem ser anexados a uma única VM. Para VMs normais, esse limite é de 128 discos com um tamanho total de 64 TB, enquanto as VMs de núcleo partilhado têm um limite de 16 PDs com um tamanho total de 3 TB.O Google Cloud aplica este limite e não o Kubernetes.

Monitorize as métricas do plano de controlo

Use as métricas do plano de controlo disponíveis para configurar os painéis de controlo de monitorização. Pode usar as métricas do plano de controlo para: observar o estado do cluster, observar os resultados das alterações à configuração do cluster (por exemplo, implementar cargas de trabalho adicionais ou componentes de terceiros) ou quando resolve problemas.

Uma das métricas mais importantes a monitorizar é a latência da API Kubernetes. Os aumentos na latência indicam que o sistema está sobrecarregado. Tenha em atenção que as chamadas LIST que transferem grandes quantidades de dados devem ter uma latência muito superior à dos pedidos mais pequenos.

O aumento da latência da API Kubernetes também pode ser causado por respostas lentas de webhooks de admissão de terceiros. Pode usar métricas para medir a latência dos webhooks e detetar estes 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 ao nível do espaço de nomes e ao nível do cluster é de 30 segundos. As expetativas máximas são definidas pelos SLOs definidos pela comunidade Kubernetes de código aberto. Para mais informações, consulte os detalhes dos SLIs/SLOs de latência de chamadas de API.

Práticas recomendadas para programadores do Kubernetes

Use o padrão de lista e observação em vez da listagem periódica

Enquanto programador do Kubernetes, pode ter de criar um componente com os seguintes requisitos:

  • O seu componente tem de obter a lista de alguns objetos do Kubernetes periodicamente.
  • O seu componente tem de ser executado em várias instâncias (no caso do DaemonSet, mesmo em cada nó).

Este componente pode gerar picos de carga no kube-apiserver, mesmo que o estado dos objetos obtidos periodicamente não esteja a mudar.

A abordagem mais simples é usar chamadas LIST periódicas. No entanto, esta é uma abordagem ineficiente e dispendiosa para o autor da chamada e o servidor, uma vez que todos os objetos têm de ser carregados na memória, serializados e transferidos de cada vez. A utilização excessiva de pedidos LIST pode sobrecarregar o plano de controlo ou gerar uma limitação excessiva desses pedidos.

Pode melhorar o seu componente definindo o parâmetro resourceVersion=0 em chamadas LIST. Isto permite que o kube-apiserver use a 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.

Recomendamos vivamente que evite chamadas LIST repetíveis e as substitua pelo padrão de list e watch. Liste os objetos uma vez e, em seguida, use a API Watch para receber alterações incrementais do estado. Esta abordagem reduz o tempo de processamento e minimiza o tráfego em comparação com as chamadas LIST periódicas. Quando os objetos não mudam, não é gerado nenhum carregamento adicional.

Se usar a linguagem Go, verifique o SharedInformer e o SharedInformerFactory para pacotes Go que implementam este padrão.

Limite o tráfego desnecessário gerado por visualizações e listas

O Kubernetes usa internamente observações para enviar notificações sobre atualizações de objetos. Mesmo com relógios que requerem muito menos recursos do que as chamadas LIST periódicas, o processamento de relógios em grandes clusters pode ocupar uma parte significativa dos recursos do cluster e afetar o desempenho do cluster. O maior impacto negativo é gerado pela criação de observações que observam objetos que mudam frequentemente a partir de vários locais. Por exemplo, observando dados sobre todos os pods de um componente em execução em todos os nós. Se instalar código ou extensões de terceiros no seu cluster, estes podem criar essas observações de forma oculta.

Recomendamos as seguintes práticas recomendadas:

  • Reduza o processamento desnecessário e o tráfego gerado por observações e chamadas LIST.
  • Evite criar observações que observem objetos que mudam frequentemente de vários locais (por exemplo, DaemonSets).
  • (Altamente recomendado) Crie um controlador central que monitorize e processe os dados necessários num único nó.
  • Observar apenas um subconjunto dos objetos, por exemplo, o kubelet em cada nó observa apenas pods agendados no mesmo nó.
  • Evite implementar componentes ou extensões de terceiros que possam afetar o desempenho do cluster fazendo um volume elevado de visualizações ou chamadas LIST.

Use atualizações contínuas com DaemonSets para evitar aumentos súbitos no tráfego

Quando um DaemonSet é criado num cluster, agenda imediatamente um novo pod em cada nó. Se todos esses novos Pods se ligarem ao mesmo ponto final de rede, esses pedidos ocorrem em simultâneo, o que coloca uma carga elevada no anfitrião de destino. Para evitar esta situação, configure os seus DaemonSets com atualizações contínuas com um número limitado de maxSurge pods.

Limite o tamanho do manifesto de objetos do Kubernetes

Se precisar de operações rápidas que exijam um elevado débito de agrupamentos, como redimensionar ou atualizar grandes cargas de trabalho, certifique-se de que mantém os tamanhos dos manifestos de agrupamentos ao mínimo, idealmente inferiores a 10 KiB.

O Kubernetes armazena manifestos de recursos numa base de dados que é um armazenamento de chave-valor. Todo o manifesto é enviado sempre que o recurso é obtido, inclusive quando usa o padrão de lista e observação.

O tamanho do manifesto tem as seguintes limitações:

  • Tamanho máximo para cada manifesto de objeto: aproximadamente 1,5 MiB.
  • Quota total para todos os objetos da API Kubernetes no cluster: o tamanho da quota pré-configurado é de 6 GiB. Isto inclui um registo de alterações com todas as atualizações de todos os objetos nos 150 segundos mais recentes do histórico do cluster.
  • Desempenho do plano de controlo durante períodos de tráfego elevado: os tamanhos dos manifestos maiores aumentam a carga no servidor da API.

Para objetos únicos e raramente processados, o tamanho do manifesto não é normalmente um problema, desde que seja inferior a 1,5 MiB. No entanto, os tamanhos de manifesto superiores a 10 KiB para objetos processados com frequência, como pods em cargas de trabalho muito grandes, podem causar um aumento na latência das chamadas API e uma diminuição no desempenho geral. As listas e os relógios, em particular, podem ser significativamente afetados por tamanhos de manifesto grandes. Também pode ter problemas com a quota da base de dados de estado do cluster, porque a quantidade de revisões nos últimos 150 segundos pode acumular-se rapidamente durante períodos de tráfego elevado do servidor da API.

Para reduzir o tamanho do manifesto de um pod, é possível tirar partido dos ConfigMaps do Kubernetes para armazenar parte da configuração, particularmente a parte que é partilhada por vários pods no cluster. Por exemplo, as variáveis de ambiente são frequentemente partilhadas por todos os pods numa carga de trabalho.

Tenha em atenção que também é possível ter problemas semelhantes com objetos ConfigMap se forem tão numerosos, grandes e processados com a mesma frequência que os pods. A extração de parte da configuração é mais útil quando diminui o tráfego geral.

Desative a montagem automática da conta de serviço predefinida

Se a lógica executada nos seus pods não precisar de aceder à API Kubernetes, deve desativar a montagem automática predefinida da conta de serviço para evitar a criação de segredos e monitorizações relacionados.

Quando cria um pod sem especificar uma conta de serviço, o Kubernetes realiza automaticamente as seguintes ações:

  • Atribui a conta de serviço predefinida ao pod.
  • Monta as credenciais da conta de serviço como um segredo para o pod.
  • Para cada segredo montado, o kubelet cria uma observação para observar as alterações a esse segredo em todos os nós.

Em clusters grandes, estas ações representam milhares de observações desnecessárias que podem colocar uma carga significativa no kube-apiserver.

Use buffers de protocolo em vez de JSON para pedidos de API

Use buffers de protocolo quando implementar componentes altamente escaláveis, conforme descrito em Conceitos da API Kubernetes.

A API REST do Kubernetes suporta JSON e buffers de protocolo como formato de serialização para objetos. O JSON é usado por predefinição, mas os buffers de protocolo são mais eficientes para o desempenho em grande escala, porque requerem um processamento menos intensivo da CPU e enviam menos dados através da rede. A sobrecarga relacionada com o processamento de JSON pode causar tempos limite ao listar dados de grande dimensão.

O que se segue?