Workloads - Amazon EKS

As traduções são geradas por tradução automática. Em caso de conflito entre o conteúdo da tradução e da versão original em inglês, a versão em inglês prevalecerá.

Workloads

As cargas de trabalho têm um impacto no tamanho que seu cluster pode escalar. As cargas de trabalho que usam APIs muito o Kubernetes limitarão a quantidade total de cargas de trabalho que você pode ter em um único cluster, mas há alguns padrões que você pode alterar para ajudar a reduzir a carga.

As cargas de trabalho em um cluster Kubernetes têm acesso a recursos que se integram à API do Kubernetes (por exemplo, segredos e ServiceAccounts), mas esses recursos nem sempre são necessários e devem ser desativados se não estiverem sendo usados. Limitar o acesso à carga de trabalho e a dependência do plano de controle do Kubernetes aumentará o número de cargas de trabalho que você pode executar no cluster e melhorará a segurança de seus clusters removendo o acesso desnecessário às cargas de trabalho e implementando práticas de privilégios mínimos. Leia as melhores práticas de segurança para obter mais informações.

Uso IPv6 para rede de pods

Você não pode fazer a transição de uma VPC de IPv4 para, IPv6 portanto, habilitar IPv6 antes de provisionar um cluster é importante. Se você habilitar IPv6 em uma VPC, isso não significa que você precisa usá-la. Se seus pods e serviços usarem, IPv6 você ainda poderá rotear o tráfego de e para endereços. IPv4 Consulte as melhores práticas de rede EKS para obter mais informações.

O uso IPv6 em seu cluster evita alguns dos limites mais comuns de escalabilidade de clusters e cargas de trabalho. IPv6 evita o esgotamento do endereço IP quando pods e nós não podem ser criados porque nenhum endereço IP está disponível. Ele também tem melhorias no desempenho por nó porque os pods recebem endereços IP mais rapidamente ao reduzir o número de anexos ENI por nó. Você pode obter um desempenho de nó semelhante usando o modo de IPv4 prefixo na VPC CNI, mas ainda precisa se certificar de que tem endereços IP suficientes disponíveis na VPC.

Limitar o número de serviços por namespace

O número máximo de serviços em um namespace é 5.000 e o número máximo de serviços em um cluster é 10.000. Para ajudar a organizar cargas de trabalho e serviços, aumentar o desempenho e evitar o impacto em cascata dos recursos com escopo de namespace, recomendamos limitar o número de serviços por namespace a 500.

O número de regras de tabelas IP criadas por nó com o kube-proxy cresce com o número total de serviços no cluster. A geração de milhares de regras de tabelas IP e o roteamento de pacotes por meio dessas regras têm um impacto no desempenho dos nós e aumentam a latência da rede.

Crie namespaces Kubernetes que englobem um único ambiente de aplicativo, desde que o número de serviços por namespace seja inferior a 500. Isso manterá a descoberta de serviços pequena o suficiente para evitar limites de descoberta de serviços e também pode ajudá-lo a evitar colisões de nomenclatura de serviços. Ambientes de aplicativos (por exemplo, dev, test, prod) devem usar clusters EKS separados em vez de namespaces.

Entenda as cotas do Elastic Load Balancer

Ao criar seus serviços, considere o tipo de balanceamento de carga que você usará (por exemplo, Network Load Balancer (NLB) ou Application Load Balancer (ALB)). Cada tipo de balanceador de carga fornece funcionalidades diferentes e tem cotas diferentes. Algumas das cotas padrão podem ser ajustadas, mas há algumas cotas máximas que não podem ser alteradas. Para ver as cotas e o uso da sua conta, acesse o painel Service Quotas no console da AWS.

Por exemplo, os alvos padrão do ALB são 1000. Se você tiver um serviço com mais de 1.000 endpoints, precisará aumentar a cota, dividir o serviço em vários ALBs ou usar o Kubernetes Ingress. Os alvos padrão do NLB são 3000, mas estão limitados a 500 alvos por AZ. Se seu cluster executar mais de 500 pods para um serviço NLB, você precisará usar vários AZs ou solicitar um aumento do limite de cota.

Uma alternativa ao uso de um balanceador de carga acoplado a um serviço é usar um controlador de entrada. O controlador do AWS Load Balancer pode criar recursos ALBs de entrada, mas você pode considerar executar um controlador dedicado em seu cluster. Um controlador de entrada no cluster permite que você exponha vários serviços do Kubernetes a partir de um único balanceador de carga executando um proxy reverso dentro do seu cluster. Os controladores têm recursos diferentes, como suporte para a API do Gateway, que pode ter benefícios dependendo de quantas e do tamanho de suas cargas de trabalho.

Use o Route 53, o Global Accelerator ou CloudFront

Para disponibilizar um serviço usando vários balanceadores de carga como um único endpoint, você precisa usar o Amazon CloudFront, o AWS Global Accelerator ou o Amazon Route 53 para expor todos os balanceadores de carga como um único endpoint voltado para o cliente. Cada opção tem benefícios diferentes e pode ser usada separadamente ou em conjunto, dependendo de suas necessidades.

O Route 53 pode expor vários balanceadores de carga com um nome comum e pode enviar tráfego para cada um deles com base no peso atribuído. Você pode ler mais sobre os pesos do DNS na documentação e ler como implementá-los com o controlador DNS externo do Kubernetes na documentação do AWS Load Balancer Controller.

O Global Accelerator pode rotear cargas de trabalho para a região mais próxima com base no endereço IP solicitado. Isso pode ser útil para cargas de trabalho implantadas em várias regiões, mas não melhora o roteamento para um único cluster em uma única região. Usar o Route 53 em combinação com o Global Accelerator tem benefícios adicionais, como verificação de integridade e failover automático se um AZ não estiver disponível. Você pode ver um exemplo do uso do Global Accelerator com o Route 53 nesta postagem do blog.

CloudFront pode ser usado com o Route 53 e o Global Accelerator ou sozinho para rotear o tráfego para vários destinos. CloudFront armazena em cache os ativos que estão sendo servidos pelas fontes de origem, o que pode reduzir os requisitos de largura de banda, dependendo do que você está servindo.

Use EndpointSlices em vez de endpoints

Ao descobrir pods que correspondem a uma etiqueta de serviço, você deve usar EndpointSlicesem vez de endpoints. Os endpoints eram uma maneira simples de expor serviços em pequenas escalas, mas serviços grandes que escalam automaticamente ou têm atualizações causam muito tráfego no plano de controle do Kubernetes. EndpointSlices têm agrupamento automático que permite coisas como dicas com reconhecimento de topologia.

Nem todos os controladores usam EndpointSlices por padrão. Você deve verificar as configurações do controle e ativá-lo, se necessário. Para o AWS Load Balancer Controller, você deve habilitar o uso da bandeira --enable-endpoint-slices opcional. EndpointSlices

Use segredos imutáveis e externos, se possível

O kubelet mantém um cache das chaves e valores atuais dos segredos que são usados em volumes para pods nesse nó. O kubelet monitora os segredos para detectar alterações. À medida que o cluster se expande, o número crescente de relógios pode afetar negativamente o desempenho do servidor da API.

Existem duas estratégias para reduzir o número de relógios em Secrets:

  • Para aplicativos que não precisam de acesso aos recursos do Kubernetes, você pode desativar a montagem automática de segredos da conta de serviço definindo Token: false automountServiceAccount

  • Se os segredos do seu aplicativo forem estáticos e não forem modificados no futuro, marque-os como imutáveis. O kubelet não mantém um monitor de API para segredos imutáveis.

Para desativar a montagem automática de uma conta de serviço em pods, você pode usar a seguinte configuração em sua carga de trabalho. Você pode substituir essas configurações se cargas de trabalho específicas precisarem de uma conta de serviço.

apiVersion: v1
kind: ServiceAccount
metadata:
  name: app
automountServiceAccountToken: true

Monitore o número de segredos no cluster antes que ele exceda o limite de 10.000. Você pode ver uma contagem total de segredos em um cluster com o comando a seguir. Você deve monitorar esse limite por meio de suas ferramentas de monitoramento de cluster.

kubectl get secrets -A | wc -l

Você deve configurar o monitoramento para alertar o administrador do cluster antes que esse limite seja atingido. Considere usar opções externas de gerenciamento de segredos, como o AWS Key Management Service (AWS KMS) ou o Hashicorp Vault com o driver CSI da Secrets Store.

Limitar o histórico de implantação

Os pods podem ser lentos ao criar, atualizar ou excluir porque objetos antigos ainda são rastreados no cluster. Você pode reduzir o número revisionHistoryLimit de implantações para limpar mais antigas, ReplicaSets o que reduzirá a quantidade total de objetos rastreados pelo Kubernetes Controller Manager. O limite de histórico padrão para implantações em 10.

Se o cluster criar muitos objetos de trabalho por meio CronJobs de outros mecanismos, use a ttlSecondsAfterFinishedconfiguração para limpar automaticamente os pods antigos no cluster. Isso removerá os trabalhos executados com sucesso do histórico de trabalhos após um período de tempo especificado.

Quando um pod é executado em um Node, o kubelet adiciona um conjunto de variáveis de ambiente para cada serviço ativo. Os processos Linux têm um tamanho máximo para seu ambiente, que pode ser alcançado se você tiver muitos serviços em seu namespace. O número de serviços por namespace não deve exceder 5.000. Depois disso, o número de variáveis do ambiente de serviço ultrapassa os limites do shell, fazendo com que os pods falhem na inicialização.

Há outros motivos pelos quais os pods não devem usar variáveis de ambiente de serviço para descoberta de serviços. Conflitos de nomes de variáveis de ambiente, nomes de serviços vazados e tamanho total do ambiente são alguns exemplos. Você deve usar o CoreDNS para descobrir endpoints de serviço.

Limite os webhooks de admissão dinâmica por recurso

Os webhooks de admissão dinâmica incluem webhooks de admissão e webhooks mutantes. Eles são endpoints de API que não fazem parte do plano de controle do Kubernetes e são chamados em sequência quando um recurso é enviado para a API do Kubernetes. Cada webhook tem um tempo limite padrão de 10 segundos e pode aumentar a quantidade de tempo que uma solicitação de API leva se você tiver vários webhooks ou se algum deles atingir o tempo limite.

Certifique-se de que seus webhooks estejam altamente disponíveis, especialmente durante um incidente de AZ, e que a FailurePolicy esteja configurada corretamente para rejeitar o recurso ou ignorar a falha. Não chame webhooks quando não for necessário, permitindo que os comandos --dry-run kubectl ignorem o webhook.

apiVersion: admission.k8s.io/v1
kind: AdmissionReview
request:
  dryRun: False

Webhooks mutantes podem modificar recursos em sucessão frequente. Se você tiver 5 webhooks mutantes e implantar 50 recursos, o etcd armazenará todas as versões de cada recurso até que a compactação seja executada — a cada 5 minutos — para remover as versões antigas dos recursos modificados. Nesse cenário, quando o etcd remover recursos substituídos, haverá 200 versões de recursos removidas do etcd e, dependendo do tamanho dos recursos, poderão usar um espaço considerável no host etcd até que a desfragmentação seja executada a cada 15 minutos.

Essa desfragmentação pode causar pausas no etcd, o que pode ter outros efeitos na API e nos controladores do Kubernetes. Você deve evitar a modificação frequente de grandes recursos ou a modificação de centenas de recursos em rápida sucessão.

Compare cargas de trabalho em vários clusters

Se você tiver dois clusters que deveriam ter desempenho semelhante, mas não têm, tente comparar as métricas para identificar o motivo.

Por exemplo, comparar a latência do cluster é um problema comum. Isso geralmente é causado pela diferença no volume de solicitações de API. Você pode executar a CloudWatch LogInsight consulta a seguir para entender a diferença.

filter @logStream like "kube-apiserver-audit"
| stats count(*) as cnt by objectRef.apiGroup, objectRef.apiVersion, objectRef.resource, userAgent, verb, responseStatus.code
| sort cnt desc
| limit 1000

Você pode adicionar filtros adicionais para restringi-lo. por exemplo, focando em todas as solicitações de lista defoo.

filter @logStream like "kube-apiserver-audit"
| filter verb = "list"
| filter user.username like "foo"
| stats count(*) as cnt by objectRef.apiGroup, objectRef.apiVersion, objectRef.resource, responseStatus.code
| sort cnt desc
| limit 1000