

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á.

# Plano de controle do Kubernetes
<a name="scale-control-plane"></a>

**dica**  
 [Explore as](https://aws-experience.com/emea/smb/events/series/get-hands-on-with-amazon-eks?trk=4a9b4147-2490-4c63-bc9f-f8a84b122c8c&sc_channel=el) melhores práticas por meio de workshops do Amazon EKS.

O plano de controle do Kubernetes consiste no Kubernetes API Server, no Kubernetes Controller Manager, no Scheduler e em outros componentes necessários para o funcionamento do Kubernetes. Os limites de escalabilidade desses componentes são diferentes dependendo do que você está executando no cluster, mas as áreas com maior impacto na escalabilidade incluem a versão, a utilização e o escalonamento individual do Node do Kubernetes.

Você pode executar o plano de controle do cluster em um dos dois modos para atender aos diferentes requisitos de carga de trabalho:
+  **Modo padrão** — Por padrão, todos os clusters EKS usam o modo Padrão. O plano de controle aumenta e diminui automaticamente com base nas demandas de sua carga de trabalho. O modo padrão aloca dinamicamente a capacidade suficiente do plano de controle e é a opção recomendada para a maioria dos casos de uso.
+  **Modo provisionado** — Se suas cargas de trabalho não tolerarem a variabilidade de desempenho do escalonamento do plano de controle ou se exigirem uma capacidade muito alta do plano de controle, você poderá usar o modo provisionado. Com o modo provisionado, você pré-aloca a capacidade do plano de controle que está sempre pronta para lidar com requisitos exigentes. Você obtém um desempenho consistente e previsível.

Com o modo EKS Provisioned, você escolhe entre um conjunto de camadas de escalabilidade (XL, 2XL, 4XL e 8XL). Com cada camada, você obtém um desempenho alto e previsível do plano de controle do cluster. O modo provisionado é particularmente valioso para os seguintes casos de uso:
+ Performance-critical cargas de trabalho
+ Large-scale Operações de IA e aprendizado de máquina
+ Eventos previstos de alta demanda
+ Ambientes que exigem consistência entre preparação e produção

Com o modo provisionado, você pode pré-alocar a capacidade do plano de controle com antecedência e se beneficiar de um Acordo de Nível de Serviço (SLA) aprimorado de 99,99% medido em intervalos de 1 minuto. *Para obter mais informações sobre o modo provisionado do EKS, incluindo especificações de nível e preços, consulte [Plano de controle provisionado do EKS](https://docs.aws.amazon.com/eks/latest/userguide/eks-provisioned-control-plane.html) no Guia do usuário do EKS.*

## Limite a carga de trabalho e a explosão de nós
<a name="_limit_workload_and_node_bursting"></a>

**Importante**  
Para evitar atingir os limites da API no plano de controle, você deve limitar os picos de escala que aumentam o tamanho do cluster em porcentagens de dois dígitos por vez (por exemplo, 1000 nós a 1100 nós ou 4000 a 4500 pods de uma vez).

O plano de controle do EKS será escalado automaticamente à medida que seu cluster cresce, mas há limites para a rapidez com que ele será escalado. Quando você cria um cluster EKS pela primeira vez, o plano de controle não poderá ser escalado imediatamente para centenas de nós ou milhares de pods. Para ler mais sobre como o EKS fez melhorias de escalabilidade, consulte [esta postagem no blog](https://aws.amazon.com/blogs/containers/amazon-eks-control-plane-auto-scaling-enhancements-improve-speed-by-4x/).

O escalonamento de aplicativos grandes exige que a infraestrutura se adapte para ficar totalmente pronta (por exemplo, aquecendo balanceadores de carga). Para controlar a velocidade do escalonamento, certifique-se de escalar com base nas métricas certas para seu aplicativo. O escalonamento de CPU e memória pode não prever com precisão as restrições do seu aplicativo, e usar métricas personalizadas (por exemplo, solicitações por segundo) no Kubernetes Horizontal Pod Autoscaler (HPA) pode ser uma melhor opção de escalabilidade.

Para usar uma métrica personalizada, consulte os exemplos na documentação do [Kubernetes](https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale-walkthrough/#autoscaling-on-multiple-metrics-and-custom-metrics). Se você tiver necessidades de escalabilidade mais avançadas ou precisar escalar com base em fontes externas (por exemplo, fila AWS SQS), use o [KEDA](https://keda.sh) para escalonamento de carga de trabalho baseado em eventos.

## Reduza a escala de nós e pods com segurança
<a name="_scale_nodes_and_pods_down_safely"></a>

### Substitua instâncias de longa execução
<a name="_replace_long_running_instances"></a>

A substituição regular de nós mantém seu cluster íntegro, evitando desvios de configuração e problemas que só ocorrem após um tempo de atividade prolongado (por exemplo, vazamentos lentos de memória). A substituição automatizada fornecerá bons processos e práticas para atualizações de nós e correções de segurança. Se cada nó do seu cluster for substituído regularmente, haverá menos trabalho necessário para manter processos separados para manutenção contínua.

Use as configurações de [tempo de vida (TTL)](https://docs.aws.amazon.com/eks/latest/best-practices/karpenter.html#_creating_nodepools) do Karpenter para substituir as instâncias depois que elas estiverem em execução por um determinado período de tempo. Grupos de nós autogerenciados podem usar a `max-instance-lifetime` configuração para alternar nós automaticamente. Atualmente, os grupos de nós gerenciados não têm esse recurso, mas você pode rastrear a solicitação [aqui GitHub](https://github.com/aws/containers-roadmap/issues/1190).

### Remova nós subutilizados
<a name="_remove_underutilized_nodes"></a>

Você pode remover os nós quando eles não têm cargas de trabalho em execução usando o limite de redução no autoescalador de cluster do Kubernetes com o [https://github.com/kubernetes/autoscaler/blob/master/cluster-autoscaler/FAQ.md#how-does-scale-down-work](https://github.com/kubernetes/autoscaler/blob/master/cluster-autoscaler/FAQ.md#how-does-scale-down-work)ou, no Karpenter, você pode usar a configuração do provisionador. `ttlSecondsAfterEmpty`

### Use orçamentos de interrupção de pods e desligamento seguro de nós
<a name="_use_pod_disruption_budgets_and_safe_node_shutdown"></a>

A remoção de pods e nós de um cluster Kubernetes exige que os controladores façam atualizações em vários recursos (por exemplo). EndpointSlices Fazer isso com frequência ou com muita rapidez pode causar limitação do servidor de API e interrupções no aplicativo à medida que as alterações se propagam para os controladores. Os [orçamentos de interrupção do pod](https://kubernetes.io/docs/concepts/workloads/pods/disruptions/) são uma prática recomendada para diminuir a rotatividade e proteger a disponibilidade da carga de trabalho à medida que os nós são removidos ou reprogramados em um cluster.

## Use o Client-Side cache ao executar o Kubectl
<a name="_use_client_side_cache_when_running_kubectl"></a>

Usar o comando kubectl de forma ineficiente pode adicionar carga adicional ao servidor da API Kubernetes. Você deve evitar executar scripts ou automações que usem kubectl repetidamente (por exemplo, em um loop for) ou executar comandos sem um cache local.

 `kubectl`tem um cache do lado do cliente que armazena em cache as informações de descoberta do cluster para reduzir a quantidade de chamadas de API necessárias. O cache é ativado por padrão e é atualizado a cada 10 minutos.

Se você executar o kubectl a partir de um contêiner ou sem um cache do lado do cliente, poderá ter problemas de limitação de API. É recomendável manter o cache do cluster montando o `--cache-dir` para evitar fazer chamadas de API desnecessárias.

## Desativar a compactação kubectl
<a name="_disable_kubectl_compression"></a>

Desativar a compactação kubectl em seu arquivo kubeconfig pode reduzir o uso da API e da CPU do cliente. Por padrão, o servidor comprime os dados enviados ao cliente para otimizar a largura de banda da rede. Isso adiciona carga de CPU no cliente e no servidor para cada solicitação e a desativação da compactação pode reduzir a sobrecarga e a latência se você tiver largura de banda adequada. Para desativar a compactação, você pode usar o `--disable-compression=true` sinalizador ou definido `disable-compression: true` em seu arquivo kubeconfig.

```
apiVersion: v1
clusters:
- cluster:
    server: serverURL
    disable-compression: true
  name: cluster
```

## Autoescalador de clusters de fragmentos
<a name="_shard_cluster_autoscaler"></a>

O [Kubernetes Cluster Autoscaler foi testado](https://github.com/kubernetes/autoscaler/blob/master/cluster-autoscaler/proposals/scalability_tests.md) para escalar até 1000 nós. Em um cluster grande com mais de 1000 nós, é recomendável executar várias instâncias do autoescalador de cluster no modo fragmentado. Cada instância do Cluster Autoscaler é configurada para escalar um conjunto de grupos de nós. O exemplo a seguir mostra duas configurações de escalonamento automático de cluster que são configuradas para cada grupo de 4 nós de escala.

ClusterAutoscaler-1

```
autoscalingGroups:
- name: eks-core-node-grp-20220823190924690000000011-80c1660e-030d-476d-cb0d-d04d585a8fcb
  maxSize: 50
  minSize: 2
- name: eks-data_m1-20220824130553925600000011-5ec167fa-ca93-8ca4-53a5-003e1ed8d306
  maxSize: 450
  minSize: 2
- name: eks-data_m2-20220824130733258600000015-aac167fb-8bf7-429d-d032-e195af4e25f5
  maxSize: 450
  minSize: 2
- name: eks-data_m3-20220824130553914900000003-18c167fa-ca7f-23c9-0fea-f9edefbda002
  maxSize: 450
  minSize: 2
```

ClusterAutoscaler-2

```
autoscalingGroups:
- name: eks-data_m4-2022082413055392550000000f-5ec167fa-ca86-6b83-ae9d-1e07ade3e7c4
  maxSize: 450
  minSize: 2
- name: eks-data_m5-20220824130744542100000017-02c167fb-a1f7-3d9e-a583-43b4975c050c
  maxSize: 450
  minSize: 2
- name: eks-data_m6-2022082413055392430000000d-9cc167fa-ca94-132a-04ad-e43166cef41f
  maxSize: 450
  minSize: 2
- name: eks-data_m7-20220824130553921000000009-96c167fa-ca91-d767-0427-91c879ddf5af
  maxSize: 450
  minSize: 2
```

## Prioridade e imparcialidade da API
<a name="_api_priority_and_fairness"></a>

![APF](http://docs.aws.amazon.com/pt_br/eks/latest/best-practices/images/scalability/APF.jpg)


### Visão geral do
<a name="_overview"></a>

Para se proteger da sobrecarga durante períodos de aumento de solicitações, o servidor de API limita o número de solicitações de bordo que ele pode ter pendentes em um determinado momento. Quando esse limite for excedido, o servidor da API começará a rejeitar solicitações e retornará aos clientes um código de resposta HTTP 429 para “Muitas solicitações”. O servidor descartar solicitações e fazer com que os clientes tentem novamente mais tarde é preferível a não ter limites no número de solicitações do lado do servidor e sobrecarregar o plano de controle, o que pode resultar em desempenho degradado ou indisponibilidade.

O mecanismo usado pelo Kubernetes para configurar como essas solicitações de entrada são divididas entre os diferentes tipos de solicitação é chamado de [API](https://kubernetes.io/docs/concepts/cluster-administration/flow-control/) Priority and Fairness. O servidor da API configura o número total de solicitações em voo que ele pode aceitar ao somar os valores especificados pelos sinalizadores e. `--max-requests-inflight` `--max-mutating-requests-inflight` O EKS usa os valores padrão de 400 e 200 solicitações para esses sinalizadores, permitindo que um total de 600 solicitações sejam enviadas em um determinado momento. No entanto, ao escalar o plano de controle para tamanhos maiores em resposta ao aumento da utilização e da rotatividade da carga de trabalho, aumenta correspondentemente a cota de solicitações em voo até 2000 (sujeita a alterações). O APF especifica como essas cotas de solicitações de bordo são subdivididas entre os diferentes tipos de solicitação. Observe que os planos de controle EKS estão altamente disponíveis com pelo menos 2 servidores de API registrados em cada cluster. Isso significa que o número total de solicitações em voo que seu cluster pode processar é o dobro (ou mais se for ampliado horizontalmente) da cota de bordo definida por kube-apiserver. Isso equivale a vários milhares de requests/second nos maiores clusters EKS.

Dois tipos de objetos do Kubernetes, chamados PriorityLevelConfigurations e FlowSchemas, configuram como o número total de solicitações é dividido entre os diferentes tipos de solicitação. Esses objetos são mantidos automaticamente pelo servidor da API e o EKS usa a configuração padrão desses objetos para a versão secundária do Kubernetes em questão. PriorityLevelConfigurations representam uma fração do número total de solicitações permitidas. Por exemplo, a carga de trabalho máxima PriorityLevelConfiguration é alocada em 98 do total de 600 solicitações. A soma das solicitações alocadas para todos PriorityLevelConfigurations será igual a 600 (ou um pouco acima de 600, porque o servidor de API arredondará para cima se um determinado nível receber uma fração de uma solicitação). Para verificar o PriorityLevelConfigurations em seu cluster e o número de solicitações alocadas para cada um, você pode executar o comando a seguir. Estes são os padrões no EKS 1.32:

```
$ kubectl get --raw /metrics | grep apiserver_flowcontrol_nominal_limit_seats
apiserver_flowcontrol_nominal_limit_seats{priority_level="catch-all"} 13
apiserver_flowcontrol_nominal_limit_seats{priority_level="exempt"} 0
apiserver_flowcontrol_nominal_limit_seats{priority_level="global-default"} 49
apiserver_flowcontrol_nominal_limit_seats{priority_level="leader-election"} 25
apiserver_flowcontrol_nominal_limit_seats{priority_level="node-high"} 98
apiserver_flowcontrol_nominal_limit_seats{priority_level="system"} 74
apiserver_flowcontrol_nominal_limit_seats{priority_level="workload-high"} 98
apiserver_flowcontrol_nominal_limit_seats{priority_level="workload-low"} 245
```

O segundo tipo de objeto é FlowSchemas. As solicitações do API Server com um determinado conjunto de propriedades são classificadas sob o mesmo FlowSchema. Essas propriedades incluem o usuário autenticado ou os atributos da solicitação, como o grupo de API, o namespace ou o recurso. A FlowSchema também especifica para qual PriorityLevelConfiguration tipo de solicitação deve ser mapeado. Os dois objetos juntos dizem: “Quero que esse tipo de solicitação conte para essa parcela de solicitações a bordo”. Quando uma solicitação chega ao servidor da API, ela verifica cada uma delas FlowSchemas até encontrar uma que corresponda a todas as propriedades necessárias. Se várias FlowSchemas corresponderem a uma solicitação, o servidor da API escolherá aquela FlowSchema com a menor precedência correspondente, especificada como uma propriedade no objeto.

O mapeamento de FlowSchemas to PriorityLevelConfigurations pode ser visualizado usando este comando:

```
$ kubectl get flowschemas
NAME                           PRIORITYLEVEL     MATCHINGPRECEDENCE   DISTINGUISHERMETHOD   AGE     MISSINGPL
exempt                         exempt            1                    <none>                7h19m   False
eks-exempt                     exempt            2                    <none>                7h19m   False
probes                         exempt            2                    <none>                7h19m   False
system-leader-election         leader-election   100                  ByUser                7h19m   False
endpoint-controller            workload-high     150                  ByUser                7h19m   False
workload-leader-election       leader-election   200                  ByUser                7h19m   False
system-node-high               node-high         400                  ByUser                7h19m   False
system-nodes                   system            500                  ByUser                7h19m   False
kube-controller-manager        workload-high     800                  ByNamespace           7h19m   False
kube-scheduler                 workload-high     800                  ByNamespace           7h19m   False
kube-system-service-accounts   workload-high     900                  ByNamespace           7h19m   False
eks-workload-high              workload-high     1000                 ByUser                7h14m   False
service-accounts               workload-low      9000                 ByUser                7h19m   False
global-default                 global-default    9900                 ByUser                7h19m   False
catch-all                      catch-all         10000                ByUser                7h19m   False
```

PriorityLevelConfigurations pode ter um tipo de fila, rejeição ou isenção. Para os tipos Queue e Reject, um limite é imposto ao número máximo de solicitações em voo para esse nível de prioridade, no entanto, o comportamento é diferente quando esse limite é atingido. Por exemplo, o workload-high PriorityLevelConfiguration usa o tipo Queue e tem 98 solicitações disponíveis para uso pelo controller-manager, endpoint-controller, scheduler, controladores relacionados ao eks e de pods em execução no namespace kube-system. Como o tipo Queue é usado, o servidor da API tentará manter as solicitações na memória e espera que o número de solicitações em voo caia abaixo de 98 antes que essas solicitações expirem. Se uma determinada solicitação atingir o tempo limite na fila ou se muitas solicitações já estiverem na fila, o servidor de API não terá escolha a não ser descartar a solicitação e devolver ao cliente um 429. Observe que o enfileiramento pode impedir que uma solicitação receba um 429, mas tem a desvantagem de aumentar a latência de ponta a ponta na solicitação.

Agora, considere o catch-all FlowSchema que é mapeado para o catch-all com o tipo Reject PriorityLevelConfiguration . Se os clientes atingirem o limite de 13 solicitações em voo, o servidor da API não fará filas e eliminará as solicitações instantaneamente com um código de resposta 429. Por fim, as solicitações mapeadas para um PriorityLevelConfiguration com o tipo Isento nunca receberão um 429 e sempre serão enviadas imediatamente. Isso é usado para solicitações de alta prioridade, como solicitações healthz ou solicitações provenientes do grupo system:masters.

### Monitorando APF e solicitações descartadas
<a name="_monitoring_apf_and_dropped_requests"></a>

Para confirmar se alguma solicitação está sendo descartada devido ao APF, as métricas do servidor de API `apiserver_flowcontrol_rejected_requests_total` podem ser monitoradas para verificar o impacto e. FlowSchemas PriorityLevelConfigurations Por exemplo, essa métrica mostra que 100 solicitações das contas de serviço FlowSchema foram descartadas devido ao tempo limite das solicitações em filas de baixa carga de trabalho:

```
% kubectl get --raw /metrics | grep apiserver_flowcontrol_rejected_requests_total
apiserver_flowcontrol_rejected_requests_total{flow_schema="service-accounts",priority_level="workload-low",reason="time-out"} 100
```

Para verificar o quão perto um determinado PriorityLevelConfiguration está de receber 429 segundos ou experimentar um aumento na latência devido ao enfileiramento, você pode comparar a diferença entre o limite de simultaneidade e a simultaneidade em uso. Neste exemplo, temos um buffer de 100 solicitações.

```
% kubectl get --raw /metrics | grep 'apiserver_flowcontrol_nominal_limit_seats.*workload-low'
apiserver_flowcontrol_nominal_limit_seats{priority_level="workload-low"} 245

% kubectl get --raw /metrics | grep 'apiserver_flowcontrol_current_executing_seats.*workload-low'
apiserver_flowcontrol_current_executing_seats{flow_schema="service-accounts",priority_level="workload-low"} 145
```

Para verificar se um determinado PriorityLevelConfiguration está passando por filas, mas não necessariamente por solicitações canceladas, a métrica para `apiserver_flowcontrol_current_inqueue_requests` pode ser referenciada:

```
% kubectl get --raw /metrics | grep 'apiserver_flowcontrol_current_inqueue_requests.*workload-low'
apiserver_flowcontrol_current_inqueue_requests{flow_schema="service-accounts",priority_level="workload-low"} 10
```

Outras métricas úteis do Prometheus incluem:
+ apiserver\_flowcontrol\_dispatched\_requests\_total
+ apiserver\_flowcontrol\_request\_execution\_seconds
+ apiserver\_flowcontrol\_request\_wait\_duration\_seconds

Consulte a documentação inicial para obter uma lista completa das métricas do [APF.](https://kubernetes.io/docs/concepts/cluster-administration/flow-control/#observability)

### Evitando solicitações descartadas
<a name="_preventing_dropped_requests"></a>

#### Evite 429 alterando sua carga de trabalho
<a name="_prevent_429s_by_changing_your_workload"></a>

Quando o APF está descartando solicitações devido ao fato de uma determinada PriorityLevelConfiguration exceder o número máximo permitido de solicitações em voo, os clientes afetados FlowSchemas podem diminuir o número de solicitações em execução em um determinado momento. Isso pode ser feito reduzindo o número total de solicitações feitas durante o período em que 429 estão ocorrendo. Observe que solicitações de longa duração, como chamadas caras de listas, são especialmente problemáticas porque contam como uma solicitação de bordo durante todo o período em que estão sendo executadas. Reduzir o número dessas solicitações caras ou otimizar a latência dessas chamadas de lista (por exemplo, reduzindo o número de objetos buscados por solicitação ou passando a usar uma solicitação de observação) pode ajudar a reduzir a simultaneidade total exigida por determinada carga de trabalho.

#### Evite 429s alterando suas configurações de APF
<a name="_prevent_429s_by_changing_your_apf_settings"></a>

**Atenção**  
Só altere as configurações padrão do APF se você souber o que está fazendo. Configurações incorretas do APF podem resultar na perda de solicitações do API Server e em interrupções significativas na carga de trabalho.

Outra abordagem para evitar solicitações perdidas é alterar o padrão FlowSchemas ou PriorityLevelConfigurations instalar em clusters EKS. O EKS instala as configurações padrão do upstream para FlowSchemas e PriorityLevelConfigurations para a versão secundária do Kubernetes em questão. O servidor da API reconciliará automaticamente esses objetos com seus padrões se modificados, a menos que a seguinte anotação nos objetos seja definida como falsa:

```
  metadata:
    annotations:
      apf.kubernetes.io/autoupdate-spec: "false"
```

Em um alto nível, as configurações do APF podem ser modificadas para:
+ Aloque mais capacidade de bordo para as solicitações que lhe interessam.
+ Isole solicitações não essenciais ou caras que podem reduzir a capacidade de outros tipos de solicitação.

Isso pode ser feito alterando o padrão FlowSchemas PriorityLevelConfigurations e/ou criando novos objetos desses tipos. Os operadores podem aumentar os valores garantidos dos PriorityLevelConfigurations objetos relevantes ConcurrencyShares para aumentar a fração de solicitações de bordo que lhes são alocadas. Além disso, o número de solicitações que podem ser enfileiradas em um determinado momento também pode ser aumentado se o aplicativo puder lidar com a latência adicional causada pelas solicitações sendo enfileiradas antes de serem despachadas.

Como alternativa, é possível criar PriorityLevelConfigurations objetos novos FlowSchema e específicos para a carga de trabalho do cliente. Lembre-se de que alocar mais garantias ConcurrencyShares para as existentes PriorityLevelConfigurations ou novas PriorityLevelConfigurations fará com que o número de solicitações que podem ser processadas por outros buckets seja reduzido, pois o limite geral permanecerá em 600 em voo por servidor de API.

Ao fazer alterações nos padrões do APF, essas métricas devem ser monitoradas em um cluster de não produção para garantir que a alteração das configurações não cause 429s indesejados:

1. A métrica de `apiserver_flowcontrol_rejected_requests_total` deve ser monitorada para todos FlowSchemas para garantir que nenhum bucket comece a descartar solicitações.

1. Os valores de `apiserver_flowcontrol_nominal_limit_seats` e `apiserver_flowcontrol_current_executing_seats` devem ser comparados para garantir que a simultaneidade em uso não corra o risco de violar o limite desse nível de prioridade.

Um caso de uso comum para definir um novo FlowSchema e PriorityLevelConfiguration é o isolamento. Suponha que queiramos isolar chamadas de eventos de lista de longa duração dos pods para sua própria parcela de solicitações. Isso evitará que solicitações importantes de pods usando as contas de serviço existentes FlowSchema recebam 429 e fiquem sem capacidade de solicitação. Lembre-se de que o número total de solicitações em voo é finito. No entanto, este exemplo mostra que as configurações do APF podem ser modificadas para dividir melhor a capacidade de solicitação para uma determinada carga de trabalho:

Exemplo de FlowSchema objeto para isolar solicitações de eventos da lista:

```
apiVersion: flowcontrol.apiserver.k8s.io/v1
kind: FlowSchema
metadata:
  name: list-events-default-service-accounts
spec:
  distinguisherMethod:
    type: ByUser
  matchingPrecedence: 8000
  priorityLevelConfiguration:
    name: catch-all
  rules:
  - resourceRules:
    - apiGroups:
      - '*'
      namespaces:
      - default
      resources:
      - events
      verbs:
      - list
    subjects:
    - kind: ServiceAccount
      serviceAccount:
        name: default
        namespace: default
```
+ Isso FlowSchema captura todas as chamadas de eventos da lista feitas por contas de serviço no namespace padrão.
+ A precedência correspondente 8000 é menor do que o valor de 9000 usado pelas contas de serviço existentes, FlowSchema portanto, essas chamadas de eventos de lista corresponderão a list-events-default-service-accounts em vez de service-accounts.
+ Estamos usando o catch-all PriorityLevelConfiguration para isolar essas solicitações. Esse bucket permite que apenas 13 solicitações de bordo sejam usadas por essas chamadas de eventos de lista de longa duração. Os pods começarão a receber 429 assim que tentarem emitir mais de 13 dessas solicitações simultaneamente.

## Recuperação de recursos no servidor da API
<a name="_retrieving_resources_in_the_api_server"></a>

Obter informações do servidor da API é um comportamento esperado para clusters de qualquer tamanho. À medida que você escala o número de recursos no cluster, a frequência das solicitações e o volume de dados podem rapidamente se tornar um gargalo para o plano de controle e levar à latência e lentidão da API. Dependendo da gravidade da latência, isso causa um tempo de inatividade inesperado se você não tomar cuidado.

Estar ciente do que você está solicitando e com que frequência são os primeiros passos para evitar esses tipos de problemas. Aqui está uma orientação para limitar o volume de consultas com base nas melhores práticas de escalabilidade. As sugestões nesta seção são fornecidas para começar com as opções que são conhecidas por serem as melhores escaláveis.

### Use informantes compartilhados
<a name="_use_shared_informers"></a>

Ao criar controladores e automação que se integram à API do Kubernetes, você geralmente precisará obter informações dos recursos do Kubernetes. Se você pesquisar esses recursos regularmente, isso pode causar uma carga significativa no servidor da API.

Usar um [informante](https://pkg.go.dev/k8s.io/client-go/informers) da biblioteca client-go proporcionará a você a vantagem de observar as alterações nos recursos com base em eventos, em vez de pesquisar mudanças. Os informantes reduzem ainda mais a carga usando cache compartilhado para os eventos e alterações, de forma que vários controladores observando os mesmos recursos não adicionem carga adicional.

Os controladores devem evitar pesquisar recursos de todo o cluster sem rótulos e seletores de campo, especialmente em clusters grandes. Cada pesquisa não filtrada exige que muitos dados desnecessários sejam enviados do etcd por meio do servidor da API para serem filtrados pelo cliente. Ao filtrar com base em rótulos e namespaces, você pode reduzir a quantidade de trabalho que o servidor da API precisa realizar para atender à solicitação e aos dados enviados ao cliente.

### Otimize o uso da API Kubernetes
<a name="_optimize_kubernetes_api_usage"></a>

Ao chamar a API Kubernetes com controladores personalizados ou automação, é importante limitar as chamadas somente aos recursos necessários. Sem limites, você pode causar uma carga desnecessária no servidor da API e no etcd.

É recomendável usar o argumento watch sempre que possível. Sem argumentos, o comportamento padrão é listar objetos. Para usar watch em vez de list, você pode `?watch=true` anexar ao final da sua solicitação de API. Por exemplo, para colocar todos os pods no namespace padrão com um relógio, use:

```
/api/v1/namespaces/default/pods?watch=true
```

Se você estiver listando objetos, você deve limitar o escopo do que está listando e a quantidade de dados retornados. Você pode limitar os dados retornados adicionando `limit=500` argumentos às solicitações. O `fieldSelector` argumento e o `/namespace/` caminho podem ser úteis para garantir que suas listas tenham um escopo tão restrito quanto necessário. Por exemplo, para listar somente pods em execução no namespace padrão, use o caminho e os argumentos da API a seguir.

```
/api/v1/namespaces/default/pods?fieldSelector=status.phase=Running&limit=500
```

Ou liste todos os pods que estão sendo executados com:

```
/api/v1/pods?fieldSelector=status.phase=Running&limit=500
```

Outra opção para limitar as chamadas de observação ou os objetos listados é usar a [`resourceVersions`qual você pode ler na documentação do Kubernetes](https://kubernetes.io/docs/reference/using-api/api-concepts/#resource-versions). Sem uma `resourceVersion` discussão, você receberá a versão mais recente disponível, que requer uma leitura de quorum etcd, que é a leitura mais cara e mais lenta do banco de dados. A ResourceVersion depende dos recursos que você está tentando consultar e pode ser encontrada no `metadata.resourseVersion` campo. Isso também é recomendado no caso de usar chamadas de observação e não apenas de listas de chamadas.

Há uma `resourceVersion=0` disponibilidade especial que retornará os resultados do cache do servidor da API. Isso pode reduzir a carga do etcd, mas não suporta paginação.

```
/api/v1/namespaces/default/pods?resourceVersion=0
```

É recomendável usar watch com uma resourceVersion definida como o valor conhecido mais recente recebido da lista ou observação anterior. Isso é tratado automaticamente no client-go. Mas é recomendável verificar novamente se você estiver usando um cliente k8s em outros idiomas.

```
/api/v1/namespaces/default/pods?watch=true&resourceVersion=362812295
```

Se você chamar a API sem nenhum argumento, ela consumirá mais recursos para o servidor da API e etcd. Essa chamada obterá todos os pods em todos os namespaces sem paginação ou limitação do escopo e exigirá um quorum de leitura do etcd.

```
/api/v1/pods
```

### Evite DaemonSet rebanhos trovejantes
<a name="_prevent_daemonset_thundering_herds"></a>

A DaemonSet garante que todos (ou alguns) nós executem uma cópia de um pod. À medida que os nós se juntam ao cluster, o daemonset-controller cria pods para esses nós. Quando os nós saem do cluster, esses pods são coletados como lixo. Excluir um DaemonSet limpará os pods criados por ele.

Alguns usos típicos de a DaemonSet são:
+ Executando um daemon de armazenamento em cluster em cada nó
+ Executando um daemon de coleta de registros em cada nó
+ Executando um daemon de monitoramento de nós em cada nó

Em clusters com milhares de nós, criar um novo DaemonSet, atualizar um DaemonSet ou aumentar o número de nós pode resultar em uma alta carga colocada no plano de controle. Se DaemonSet os pods emitirem solicitações caras do servidor de API na inicialização do pod, eles podem causar um alto uso de recursos no plano de controle devido a um grande número de solicitações simultâneas.

Em operação normal, você pode usar a `RollingUpdate` para garantir o lançamento gradual de novos DaemonSet pods. Com uma estratégia de `RollingUpdate` atualização, depois de atualizar um DaemonSet modelo, o controlador elimina os DaemonSet pods antigos e cria novos DaemonSet pods automaticamente de forma controlada. No máximo, um pod do DaemonSet será executado em cada nó durante todo o processo de atualização. Você pode realizar uma distribuição gradual definindo `maxUnavailable` como 1, `maxSurge` 0 e `minReadySeconds` 60. Se você não especificar uma estratégia de atualização, o Kubernetes usará como padrão a criação de um `RollingUpdate` com `maxUnavailable` como 1, `maxSurge` como 0 e `minReadySeconds` como 0.

```
minReadySeconds: 60
strategy:
  type: RollingUpdate
  rollingUpdate:
    maxSurge: 0
    maxUnavailable: 1
```

A `RollingUpdate` garante a implantação gradual de novos DaemonSet pods se eles já tiverem sido criados e tiverem o DaemonSet número esperado de `Ready` pods em todos os nós. Problemas com o rebanho trovejante podem ocorrer sob certas condições que não são cobertas pelas estratégias. `RollingUpdate`

#### Evite rebanhos trovejantes na criação DaemonSet
<a name="_prevent_thundering_herds_on_daemonset_creation"></a>

Por padrão, independentemente da `RollingUpdate` configuração, o daemonset-controller no kube-controller-manager criará pods para todos os nós correspondentes simultaneamente quando você criar um novo. DaemonSet Para forçar o lançamento gradual dos pods depois de criar um DaemonSet, você pode usar um ou. `NodeSelector` `NodeAffinity` Isso criará um DaemonSet que corresponda a zero nós e, em seguida, você poderá atualizar gradualmente os nós para torná-los elegíveis para executar um pod a partir do a uma DaemonSet taxa controlada. Você pode seguir essa abordagem:
+ Adicione um rótulo a todos os nós do`run-daemonset=false`.

```
kubectl label nodes --all run-daemonset=false
```
+ Crie o seu DaemonSet com uma `NodeAffinity` configuração que corresponda a qualquer nó sem um `run-daemonset=false` rótulo. Inicialmente, isso fará com que você não DaemonSet tenha cápsulas correspondentes.

```
affinity:
  nodeAffinity:
    requiredDuringSchedulingIgnoredDuringExecution:
      nodeSelectorTerms:
      - matchExpressions:
        - key: run-daemonset
          operator: NotIn
          values:
          - "false"
```
+ Remova a `run-daemonset=false` etiqueta dos seus nós em uma taxa controlada. Você pode usar esse script bash como exemplo:

```
#!/bin/bash

nodes=$(kubectl get --raw "/api/v1/nodes" | jq -r '.items | .[].metadata.name')

for node in ${nodes[@]}; do
   echo "Removing run-daemonset label from node $node"
   kubectl label nodes $node run-daemonset-
   sleep 5
done
```
+ Opcionalmente, remova a `NodeAffinity` configuração do seu DaemonSet objeto. Observe que isso também acionará a `RollingUpdate` e substituirá gradualmente todos os DaemonSet pods existentes porque o DaemonSet modelo foi alterado.

#### Evite rebanhos trovejantes em escalabilidade horizontal de nós
<a name="_prevent_thundering_herds_on_node_scale_outs"></a>

Da mesma forma que a DaemonSet criação, a criação rápida de novos nós pode resultar em um grande número de DaemonSet pods iniciando simultaneamente. Você deve criar novos nós em uma taxa controlada para que o controlador crie DaemonSet pods na mesma taxa. Se isso não for possível, você pode tornar os novos nós inicialmente inelegíveis para os existentes DaemonSet usando`NodeAffinity`. Em seguida, você pode adicionar um rótulo aos novos nós gradualmente para que o daemonset-controller crie pods em uma taxa controlada. Você pode seguir essa abordagem:
+ Adicione um rótulo a todos os nós existentes para `run-daemonset=true` 

```
kubectl label nodes --all run-daemonset=true
```
+ Atualize seu DaemonSet com uma `NodeAffinity` configuração para combinar com qualquer nó com um `run-daemonset=true` rótulo. Observe que isso também acionará a `RollingUpdate` e substituirá gradualmente todos os DaemonSet pods existentes porque o DaemonSet modelo foi alterado. Você deve esperar que o `RollingUpdate` seja concluído antes de avançar para a próxima etapa.

```
affinity:
  nodeAffinity:
    requiredDuringSchedulingIgnoredDuringExecution:
      nodeSelectorTerms:
      - matchExpressions:
        - key: run-daemonset
          operator: In
          values:
          - "true"
```
+ Crie novos nós em seu cluster. Observe que esses nós não terão o `run-daemonset=true` rótulo, portanto, não DaemonSet corresponderão a esses nós.
+ Adicione o `run-daemonset=true` rótulo aos seus novos nós (que atualmente não têm o `run-daemonset` rótulo) em uma taxa controlada. Você pode usar esse script bash como exemplo:

```
#!/bin/bash

nodes=$(kubectl get --raw "/api/v1/nodes?labelSelector=%21run-daemonset" | jq -r '.items | .[].metadata.name')

for node in ${nodes[@]}; do
   echo "Adding run-daemonset=true label to node $node"
   kubectl label nodes $node run-daemonset=true
   sleep 5
done
```
+ Opcionalmente, remova a `NodeAffinity` configuração do seu DaemonSet objeto e remova o `run-daemonset` rótulo de todos os nós.

#### Evite rebanhos trovejantes nas atualizações DaemonSet
<a name="_prevent_thundering_herds_on_daemonset_updates"></a>

Uma `RollingUpdate` política respeitará apenas a `maxUnavailable` configuração de DaemonSet pods que sejam`Ready`. Se a DaemonSet tiver apenas `NotReady` pods ou uma grande porcentagem de `NotReady` pods e você atualizar seu modelo, o daemonset-controller criará novos pods simultaneamente para qualquer pod. `NotReady` Isso pode resultar em problemas de rebanho trovejante se houver um número significativo de `NotReady` pods, por exemplo, se os pods falharem continuamente ou não conseguirem extrair imagens.

Para forçar o lançamento gradual de pods ao atualizar um DaemonSet e houver `NotReady` pods, você pode alterar temporariamente a estratégia de atualização no de para. DaemonSet `RollingUpdate` `OnDelete` Com`OnDelete`, depois de atualizar um DaemonSet modelo, o controlador cria novos pods depois que você exclui manualmente os antigos para que você possa controlar a implantação de novos pods. Você pode seguir essa abordagem:
+ Verifique se você tem alguma `NotReady` cápsula no seu DaemonSet.
+ Se não, você pode atualizar o DaemonSet modelo com segurança e a `RollingUpdate` estratégia garantirá uma implementação gradual.
+ Se sim, você deve primeiro atualizá-lo DaemonSet para usar a `OnDelete` estratégia.

```
updateStrategy:
  type: OnDelete
```
+ Em seguida, atualize seu DaemonSet modelo com as alterações necessárias.
+ Após essa atualização, você pode excluir os DaemonSet pods antigos emitindo solicitações de exclusão de pods em uma taxa controlada. Você pode usar esse script bash como exemplo em que o DaemonSet nome é fluentd-elasticsearch no namespace kube-system:

```
#!/bin/bash

daemonset_pods=$(kubectl get --raw "/api/v1/namespaces/kube-system/pods?labelSelector=name%3Dfluentd-elasticsearch" | jq -r '.items | .[].metadata.name')

for pod in ${daemonset_pods[@]}; do
   echo "Deleting pod $pod"
   kubectl delete pod $pod -n kube-system
   sleep 5
done
```
+ Finalmente, você pode atualizar suas DaemonSet costas para a `RollingUpdate` estratégia anterior.