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
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.
Use EKS 1.24 ou superior
O EKS 1.24 introduziu várias mudanças e alterou o tempo de execução do contêiner para containerd--container-runtime
Limite a carga de trabalho e a explosão de nós
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 escala, consulte esta postagem no blog
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
Reduza a escala de nós e pods com segurança
Substitua instâncias de longa execução
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)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
Remova nós subutilizados
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 --scale-down-utilization-threshold
ttlSecondsAfterEmpty
Use orçamentos de interrupção de pods e desligamento seguro de nós
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
Use o cache do lado do cliente ao executar o Kubectl
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
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 fragmentados
O Kubernetes Cluster Autoscaler foi testado
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

Visão geral
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--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.24:
$ kubectl get --raw /metrics | grep apiserver_flowcontrol_request_concurrency_limit apiserver_flowcontrol_request_concurrency_limit{priority_level="catch-all"} 13 apiserver_flowcontrol_request_concurrency_limit{priority_level="global-default"} 49 apiserver_flowcontrol_request_concurrency_limit{priority_level="leader-election"} 25 apiserver_flowcontrol_request_concurrency_limit{priority_level="node-high"} 98 apiserver_flowcontrol_request_concurrency_limit{priority_level="system"} 74 apiserver_flowcontrol_request_concurrency_limit{priority_level="workload-high"} 98 apiserver_flowcontrol_request_concurrency_limit{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. Juntos, os dois objetos 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 end-to-end a latência 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
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_request_concurrency_limit.*workload-low' apiserver_flowcontrol_request_concurrency_limit{priority_level="workload-low"} 245 % kubectl get --raw /metrics | grep 'apiserver_flowcontrol_request_concurrency_in_use.*workload-low' apiserver_flowcontrol_request_concurrency_in_use{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.
Evitando solicitações descartadas
Evite 429 alterando sua carga de trabalho
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
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 de volta aos 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 dos PriorityLevelConfigurations objetos relevantes assuredConcurrencyShares para aumentar a fração de solicitações de voo 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 assuredConcurrencyShares para solicitações 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:
-
A métrica de
apiserver_flowcontrol_rejected_requests_total
deve ser monitorada para todos, FlowSchemas a fim de garantir que nenhum bucket comece a descartar solicitações. -
Os valores de
apiserver_flowcontrol_request_concurrency_limit
eapiserver_flowcontrol_request_concurrency_in_use
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/v1beta1 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 da lista list-events-default-service corresponderão a -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
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
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
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
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 KubernetesresourceVersion
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á um especial resourceVersion=0
disponível 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 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 mata 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
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 umrun-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á aRollingUpdate
e substituirá gradualmente todos os DaemonSet pods existentes porque o DaemonSet modelo foi alterado.
Evite rebanhos trovejantes em escalabilidade horizontal de nós
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 usandoNodeAffinity
. 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 qualquer nó com umrun-daemonset=true
rótulo. Observe que isso também acionará aRollingUpdate
e substituirá gradualmente todos os DaemonSet pods existentes porque o DaemonSet modelo foi alterado. Você deve esperar que oRollingUpdate
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 orun-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 orun-daemonset
rótulo de todos os nós.
Evite rebanhos trovejantes nas atualizações DaemonSet
Uma RollingUpdate
política respeitará apenas a maxUnavailable
configuração de DaemonSet pods que sejamReady
. 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
ComOnDelete
, 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.