No Kubernetes, escalonamento refere-se à certeza de que os Pods correspondam aos nós para que o kubelet possa executá-los. Preempção é o processo de finalizar Pods com menor prioridade, para que os Pods com maior prioridade possam ser escalonados nos nós. Remoção é o processo de finalização proativa de um ou mais Pods em nós com poucos recursos.
No Kubernetes, escalonamento refere-se à certeza de que Pods correspondam aos nós para que o Kubelet possa executá-los. Preempção é o processo de finalizar Pods com menor prioridade para que os Pods com maior prioridade possam ser escalonados nos nós. Remoção é o processo de finalização de um ou mais Pods em nós.
Disrupção do Pod é o processo pelo qual Pods ou nós são interrompidos de forma voluntária ou involuntária.
Disrupções voluntárias são iniciadas intencionalmente pelos donos das aplicações ou administradores dos clusters. Disrupções involuntárias não são intencionais e podem ser encadeadas por problemas inevitáveis como Nós com poucos recursos, ou por exclusões acidentais.
No Kubernetes, escalonamento refere-se a garantir que os Pods sejam correspondidos aos Nós para que o Kubelet possa executá-los.
Um escalonador observa Pods recém-criados que não possuem um Nó atribuído. Para cada Pod que o escalonador descobre, ele se torna responsável por encontrar o melhor Nó para execução do Pod. O escalonador chega a essa decisão de alocação levando em consideração os princípios de escalonamento descritos abaixo.
Se você quiser entender por que os Pods são alocados em um Nó específico ou se planeja implementar um escalonador personalizado, esta página ajudará você a aprender sobre escalonamento.
kube-scheduler é o escalonador padrão do Kubernetes e é executado como parte da camada de gerenciamento. O kube-scheduler é projetado para que, se você quiser e precisar, possa escrever seu próprio componente de escalonamento e usá-lo.
O kube-scheduler seleciona um Nó ideal para executar Pods recém-criados ou não escalonados (unscheduled). Como os contêineres em Pods — e os próprios Pods — podem ter diferentes requisitos, o escalonador filtra os Nós que não atendem às necessidades específicas de escalonamento do Pod. Alternativamente, a API permite que você especifique um Nó para um Pod ao criá-lo, mas isso é incomum e só é feito em casos especiais.
Em um cluster, Nós que atendem aos requisitos de escalonamento para um Pod são chamados de Nós viáveis. Se nenhum dos Nós for adequado, o Pod permanece não escalonado até que o escalonador consiga alocá-lo.
O escalonador encontra Nós viáveis para um Pod e, em seguida, executa um conjunto de funções para classificar esses Nós viáveis e escolhe o Nó com a maior pontuação entre os possíveis para executar o Pod. O escalonador então notifica o servidor de API sobre essa decisão em um processo chamado binding.
Fatores que precisam ser levados em consideração para decisões de escalonamento incluem requisitos individuais e coletivos de recursos, restrições de hardware / software / política, especificações de afinidade e anti-afinidade, localização de dados, interferência entre cargas de trabalho e assim por diante.
O kube-scheduler seleciona um Nó para o Pod em uma operação que consiste em duas etapas:
A etapa de filtragem localiza o conjunto de Nós onde é possível alocar o Pod. Por exemplo, o filtro PodFitsResources verifica se um Nó candidato possui recursos disponíveis suficientes para atender às solicitações de recursos específicas de um Pod. Após esta etapa, a lista de Nós contém quaisquer Nós adequados; frequentemente, haverá mais de um. Se a lista estiver vazia, esse Pod (ainda) não é escalonável.
Na etapa de pontuação, o escalonador classifica os Nós restantes para escolher o mais adequado. O escalonador atribui uma pontuação a cada Nó que passou na filtragem, baseando essa pontuação nas regras de pontuação ativas.
Por fim, o kube-scheduler atribui o Pod ao Nó com a classificação mais alta. Se houver mais de um Nó com pontuações iguais, o kube-scheduler seleciona um deles aleatoriamente.
Existem duas maneiras suportadas de configurar o comportamento de filtragem e pontuação do escalonador:
QueueSort, Filter, Score,
Bind, Reserve, Permit, e outros. Você também pode configurar o kube-scheduler para executar
diferentes perfis.Você pode restringir um Pod para que ele seja limitado a executar em nó(s) específicos, ou para preferir executar em nós específicos. Existem várias maneiras de fazer isso e as abordagens recomendadas utilizam seletores de rótulos para facilitar a seleção. Frequentemente, você não precisa definir nenhuma dessas restrições; o escalonador fará automaticamente uma alocação adequada (por exemplo, distribuindo seus Pods entre os nós para não alocá-los em um nó com recursos livres insuficientes). No entanto, existem algumas circunstâncias em que você pode querer controlar em qual nó o Pod será implantado, por exemplo, para garantir que um Pod seja alocado em um nó com um SSD conectado, ou para colocalizar Pods de dois serviços diferentes que se comunicam frequentemente na mesma zona de disponibilidade.
Você pode usar qualquer um dos seguintes métodos para escolher onde o Kubernetes aloca Pods específicos:
Assim como muitos outros objetos do Kubernetes, os nós possuem rótulos. Você pode anexar rótulos manualmente. O Kubernetes também preenche um conjunto padrão de rótulos em todos os nós de um cluster.
kubernetes.io/hostname pode ser o mesmo que o nome do nó em alguns ambientes
e um valor diferente em outros ambientes.Adicionar rótulos aos nós permite direcionar Pods para alocação em nós ou grupos de nós específicos. Você pode usar essa funcionalidade para garantir que Pods específicos executem apenas em nós com determinadas propriedades de isolamento, segurança ou conformidade regulatória.
Se você usar rótulos para isolamento de nós, escolha chaves de rótulos que o kubelet não possa modificar. Isso impede que um nó comprometido defina esses rótulos em si mesmo para fazer com que o escalonador aloque cargas de trabalho no nó comprometido.
O plugin de admissão NodeRestriction
impede que o kubelet defina ou modifique rótulos com o
prefixo node-restriction.kubernetes.io/.
Para utilizar esse prefixo de rótulo para isolamento de nós:
NodeRestriction.node-restriction.kubernetes.io/ aos seus nós e use esses rótulos em seus seletores de nós.
Por exemplo, example.com.node-restriction.kubernetes.io/fips=true ou example.com.node-restriction.kubernetes.io/pci-dss=true.nodeSelector é a forma recomendada mais simples de restrição de seleção de nós.
Você pode adicionar o campo nodeSelector à especificação do seu Pod e especificar os
rótulos de nós que você deseja que o nó de destino possua.
O Kubernetes aloca o Pod apenas em nós que possuem cada um dos rótulos que você
especificar.
Consulte Atribuir Pods a Nós para mais informações.
nodeSelector é a maneira mais simples de restringir Pods a nós com rótulos
específicos. Afinidade e antiafinidade expandem os tipos de restrições que você pode
definir. Alguns dos benefícios da afinidade e antiafinidade incluem:
nodeSelector apenas
seleciona nós com todos os rótulos especificados. Afinidade/antiafinidade oferece
mais controle sobre a lógica de seleção.A funcionalidade de afinidade consiste em dois tipos de afinidade:
nodeSelector, mas é mais expressiva e
permite especificar regras flexíveis.Afinidade de nó é conceitualmente similar a nodeSelector, permitindo restringir em quais nós seu
Pod pode ser alocado com base em rótulos de nós. Existem dois tipos de afinidade
de nó:
requiredDuringSchedulingIgnoredDuringExecution: O escalonador não pode
alocar o Pod a menos que a regra seja atendida. Isso funciona como nodeSelector,
mas com uma sintaxe mais expressiva.preferredDuringSchedulingIgnoredDuringExecution: O escalonador tenta
encontrar um nó que atenda à regra. Se um nó correspondente não estiver disponível, o
escalonador ainda aloca o Pod.IgnoredDuringExecution significa que se os rótulos do nó
mudarem após o Kubernetes alocar o Pod, o Pod continuará em execução.Você pode especificar afinidades de nó usando o campo .spec.affinity.nodeAffinity na
especificação do seu Pod.
Por exemplo, considere a seguinte especificação de Pod:
apiVersion: v1
kind: Pod
metadata:
name: with-node-affinity
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: topology.kubernetes.io/zone
operator: In
values:
- antarctica-east1
- antarctica-west1
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 1
preference:
matchExpressions:
- key: another-node-label-key
operator: In
values:
- another-node-label-value
containers:
- name: with-node-affinity
image: registry.k8s.io/pause:3.8Neste exemplo, as seguintes regras se aplicam:
topology.kubernetes.io/zone e
o valor desse rótulo deve ser antarctica-east1 ou antarctica-west1.another-node-label-key e
o valor another-node-label-value.Você pode usar o campo operator para especificar um operador lógico para o Kubernetes usar ao
interpretar as regras. Você pode usar In, NotIn, Exists, DoesNotExist,
Gt e Lt.
Leia Operadores para saber mais sobre como eles funcionam.
NotIn e DoesNotExist permitem definir o comportamento de antiafinidade de nó.
Alternativamente, você pode usar taints de nó
para repelir Pods de nós específicos.
Se você especificar tanto nodeSelector quanto nodeAffinity, ambos devem ser satisfeitos
para que o Pod seja alocado em um nó.
Se você especificar múltiplos termos em nodeSelectorTerms associados a tipos de nodeAffinity,
então o Pod pode ser alocado em um nó se um dos termos especificados
puder ser satisfeito (os termos são combinados com OR).
Se você especificar múltiplas expressões em um único campo matchExpressions associado a um
termo em nodeSelectorTerms, então o Pod pode ser alocado em um nó apenas
se todas as expressões forem satisfeitas (as expressões são combinadas com AND).
Consulte Atribuir Pods a Nós usando Afinidade de Nó para mais informações.
Você pode especificar um weight (peso) entre 1 e 100 para cada instância do
tipo de afinidade preferredDuringSchedulingIgnoredDuringExecution. Quando o
escalonador encontra nós que atendem a todos os outros requisitos de alocação do Pod, o
escalonador itera por cada regra preferencial que o nó satisfaz e adiciona o
valor do weight dessa expressão a uma soma.
A soma final é adicionada à pontuação de outras funções de prioridade do nó. Nós com a maior pontuação total são priorizados quando o escalonador toma uma decisão de alocação para o Pod.
Por exemplo, considere a seguinte especificação de Pod:
apiVersion: v1
kind: Pod
metadata:
name: with-affinity-preferred-weight
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/os
operator: In
values:
- linux
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 1
preference:
matchExpressions:
- key: label-1
operator: In
values:
- key-1
- weight: 50
preference:
matchExpressions:
- key: label-2
operator: In
values:
- key-2
containers:
- name: with-node-affinity
image: registry.k8s.io/pause:3.8
Se houver dois nós possíveis que correspondem à regra
preferredDuringSchedulingIgnoredDuringExecution, um com o
rótulo label-1:key-1 e outro com o rótulo label-2:key-2, o escalonador
considera o weight de cada nó e adiciona o peso às outras pontuações daquele
nó, e aloca o Pod no nó com a maior pontuação final.
kubernetes.io/os=linux.Kubernetes v1.20 [beta]
Ao configurar múltiplos perfis de alocação, você pode associar
um perfil a uma afinidade de nó, o que é útil se um perfil se aplica apenas a um conjunto específico de nós.
Para fazer isso, adicione um addedAffinity ao campo args do plugin NodeAffinity
na configuração do escalonador. Por exemplo:
apiVersion: kubescheduler.config.k8s.io/v1
kind: KubeSchedulerConfiguration
profiles:
- schedulerName: default-scheduler
- schedulerName: foo-scheduler
pluginConfig:
- name: NodeAffinity
args:
addedAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: scheduler-profile
operator: In
values:
- foo
O addedAffinity é aplicado a todos os Pods que definem .spec.schedulerName como foo-scheduler, além da
NodeAffinity especificada no PodSpec.
Ou seja, para corresponder ao Pod, os nós precisam satisfazer o addedAffinity e
o .spec.NodeAffinity do Pod.
Como o addedAffinity não é visível para os usuários finais, seu comportamento pode ser
inesperado para eles. Use rótulos de nós que tenham uma correlação clara com o
nome do perfil do escalonador.
nodeAffinity no controlador DaemonSet.Afinidade e antiafinidade entre Pods permitem restringir em quais nós seus Pods podem ser alocados com base nos rótulos de Pods já em execução naquele nó, em vez dos rótulos do nó.
Afinidade e antiafinidade entre Pods assumem a forma "este Pod deve (ou, no caso de antiafinidade, não deve) executar em um X se esse X já estiver executando um ou mais Pods que atendem à regra Y", onde X é um domínio topológico como nó, rack, zona ou região do provedor de nuvem, ou similar, e Y é a regra que o Kubernetes tenta satisfazer.
Você expressa essas regras (Y) como seletores de rótulos com uma lista opcional associada de namespaces. Pods são objetos com namespace no Kubernetes, então rótulos de Pods também implicitamente possuem namespaces. Quaisquer seletores de rótulos para rótulos de Pods devem especificar os namespaces nos quais o Kubernetes deve procurar esses rótulos.
Você expressa o domínio topológico (X) usando uma topologyKey, que é a chave do
rótulo do nó que o sistema usa para indicar o domínio. Para exemplos, consulte
Rótulos, Anotações e Taints conhecidos.
topologyKey.
Se alguns ou todos os nós não tiverem o rótulo topologyKey especificado, isso pode levar
a comportamentos não intencionais.Similar à afinidade de nó, existem dois tipos de afinidade e antiafinidade de Pod, como segue:
requiredDuringSchedulingIgnoredDuringExecutionpreferredDuringSchedulingIgnoredDuringExecutionPor exemplo, você poderia usar
afinidade requiredDuringSchedulingIgnoredDuringExecution para dizer ao escalonador para
colocalizar Pods de dois serviços na mesma zona do provedor de nuvem porque eles
se comunicam muito entre si. Da mesma forma, você poderia usar
antiafinidade preferredDuringSchedulingIgnoredDuringExecution para distribuir Pods
de um serviço em múltiplas zonas do provedor de nuvem.
Para usar afinidade entre Pods, use o campo affinity.podAffinity na especificação do Pod.
Para antiafinidade entre Pods, use o campo affinity.podAntiAffinity na especificação
do Pod.
Ao alocar um novo Pod, o escalonador do Kubernetes avalia as regras de afinidade/antiafinidade do Pod no contexto do estado atual do cluster:
Restrições rígidas (Filtragem de nós):
podAffinity.requiredDuringSchedulingIgnoredDuringExecution e podAntiAffinity.requiredDuringSchedulingIgnoredDuringExecution:
Restrições flexíveis (Pontuação):
podAffinity.preferredDuringSchedulingIgnoredDuringExecution e podAntiAffinity.preferredDuringSchedulingIgnoredDuringExecution:
Campos ignorados:
podAffinity.preferredDuringSchedulingIgnoredDuringExecution de Pods existentes:
podAntiAffinity.preferredDuringSchedulingIgnoredDuringExecution de Pods existentes:
Se o Pod atual sendo alocado é o primeiro de uma série que tem afinidade consigo mesmos, ele pode ser alocado se passar em todas as outras verificações de afinidade. Isso é determinado verificando que nenhum outro Pod no cluster corresponde ao namespace e seletor deste Pod, que o Pod corresponde aos seus próprios termos, e que o nó escolhido corresponde a todas as topologias solicitadas. Isso garante que não haverá um deadlock mesmo se todos os Pods tiverem afinidade entre Pods especificada.
Considere a seguinte especificação de Pod:
apiVersion: v1
kind: Pod
metadata:
name: with-pod-affinity
spec:
affinity:
podAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: security
operator: In
values:
- S1
topologyKey: topology.kubernetes.io/zone
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchExpressions:
- key: security
operator: In
values:
- S2
topologyKey: topology.kubernetes.io/zone
containers:
- name: with-pod-affinity
image: registry.k8s.io/pause:3.8
Este exemplo define uma regra de afinidade de Pod e uma regra de antiafinidade de Pod. A
regra de afinidade de Pod usa o "rígido"
requiredDuringSchedulingIgnoredDuringExecution, enquanto a regra de antiafinidade
usa o "flexível" preferredDuringSchedulingIgnoredDuringExecution.
A regra de afinidade especifica que o escalonador pode alocar o Pod de exemplo
em um nó apenas se esse nó pertencer a uma zona
específica onde outros Pods foram rotulados com security=S1.
Por exemplo, se tivermos um cluster com uma zona designada, vamos chamá-la de "Zona V",
consistindo de nós rotulados com topology.kubernetes.io/zone=V, o escalonador pode
atribuir o Pod a qualquer nó dentro da Zona V, desde que haja pelo menos um Pod dentro
da Zona V já rotulado com security=S1. Por outro lado, se não houver Pods com rótulos
security=S1 na Zona V, o escalonador não atribuirá o Pod de exemplo a nenhum nó nessa zona.
A regra de antiafinidade especifica que o escalonador deve tentar evitar alocar o Pod
em um nó se esse nó pertencer a uma zona
específica onde outros Pods foram rotulados com security=S2.
Por exemplo, se tivermos um cluster com uma zona designada, vamos chamá-la de "Zona R",
consistindo de nós rotulados com topology.kubernetes.io/zone=R, o escalonador deve evitar
atribuir o Pod a qualquer nó dentro da Zona R, desde que haja pelo menos um Pod dentro
da Zona R já rotulado com security=S2. Por outro lado, a regra de antiafinidade não impacta
a alocação na Zona R se não houver Pods com rótulos security=S2.
Para se familiarizar mais com os exemplos de afinidade e antiafinidade de Pod, consulte a proposta de projeto.
Você pode usar os valores In, NotIn, Exists e DoesNotExist no
campo operator para afinidade e antiafinidade de Pod.
Leia Operadores para saber mais sobre como eles funcionam.
Em princípio, a topologyKey pode ser qualquer chave de rótulo permitida, com as seguintes
exceções por razões de desempenho e segurança:
topologyKey vazio não é permitido tanto em
requiredDuringSchedulingIgnoredDuringExecution
quanto em preferredDuringSchedulingIgnoredDuringExecution.requiredDuringSchedulingIgnoredDuringExecution,
o controlador de admissão LimitPodHardAntiAffinityTopology limita
topologyKey a kubernetes.io/hostname. Você pode modificar ou desabilitar o
controlador de admissão se quiser permitir topologias personalizadas.Além de labelSelector e topologyKey, você pode opcionalmente especificar uma lista
de namespaces com os quais o labelSelector deve corresponder usando o
campo namespaces no mesmo nível que labelSelector e topologyKey.
Se omitido ou vazio, namespaces assume como padrão o namespace do Pod onde a
definição de afinidade/antiafinidade aparece.
Kubernetes v1.24 [stable]
Você também pode selecionar namespaces correspondentes usando namespaceSelector, que é uma consulta de rótulos sobre o conjunto de namespaces.
O termo de afinidade é aplicado aos namespaces selecionados tanto pelo namespaceSelector quanto pelo campo namespaces.
Note que um namespaceSelector vazio ({}) corresponde a todos os namespaces, enquanto uma lista namespaces nula ou vazia e
um namespaceSelector nulo correspondem ao namespace do Pod onde a regra é definida.
Kubernetes v1.33 [stable](habilitado por padrão)O campo matchLabelKeys é um campo de nível beta e está habilitado por padrão no
Kubernetes 1.35.
Quando você quiser desabilitá-lo, você deve desabilitá-lo explicitamente através do
feature gate MatchLabelKeysInPodAffinity.
O Kubernetes inclui um campo opcional matchLabelKeys para afinidade
ou antiafinidade de Pod. O campo especifica chaves para os rótulos que devem corresponder aos rótulos do Pod de entrada,
ao satisfazer a (anti)afinidade de Pod.
As chaves são usadas para buscar valores dos rótulos do Pod; esses rótulos de chave-valor são combinados
(usando AND) com as restrições de correspondência definidas usando o campo labelSelector. A filtragem
combinada seleciona o conjunto de Pods existentes que será considerado no cálculo de (anti)afinidade de Pod.
matchLabelKeys com rótulos que possam ser atualizados diretamente nos pods.
Mesmo se você editar o rótulo do pod que está especificado em matchLabelKeys diretamente (isto é, não através de um Deployment),
o kube-apiserver não reflete a atualização do rótulo no labelSelector mesclado.Um caso de uso comum é usar matchLabelKeys com pod-template-hash (definido em Pods
gerenciados como parte de um Deployment, onde o valor é único para cada revisão).
Usar pod-template-hash em matchLabelKeys permite selecionar os Pods que pertencem
à mesma revisão que o Pod de entrada, para que uma atualização gradual não quebre a afinidade.
apiVersion: apps/v1
kind: Deployment
metadata:
name: application-server
...
spec:
template:
spec:
affinity:
podAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app
operator: In
values:
- database
topologyKey: topology.kubernetes.io/zone
# Apenas Pods de um determinado rollout são considerados ao calcular a afinidade de pod.
# Se você atualizar o Deployment, os Pods substitutos seguem suas próprias regras de afinidade
# (se houver alguma definida no novo template de Pod)
matchLabelKeys:
- pod-template-hash
Kubernetes v1.33 [stable](habilitado por padrão)O campo mismatchLabelKeys é um campo de nível beta e está habilitado por padrão no
Kubernetes 1.35.
Quando você quiser desabilitá-lo, você deve desabilitá-lo explicitamente através do
feature gate MatchLabelKeysInPodAffinity.
O Kubernetes inclui um campo opcional mismatchLabelKeys para afinidade
ou antiafinidade de Pod. O campo especifica chaves para os rótulos que não devem corresponder aos rótulos do Pod de entrada,
ao satisfazer a (anti)afinidade de Pod.
mismatchLabelKeys com rótulos que possam ser atualizados diretamente nos pods.
Mesmo se você editar o rótulo do pod que está especificado em mismatchLabelKeys diretamente (isto é, não através de um Deployment),
o kube-apiserver não reflete a atualização do rótulo no labelSelector mesclado.Um exemplo de caso de uso é garantir que os Pods vão para o domínio topológico (nó, zona, etc.) onde apenas Pods do mesmo locatário ou equipe são alocados. Em outras palavras, você quer evitar executar Pods de dois locatários diferentes no mesmo domínio topológico ao mesmo tempo.
apiVersion: v1
kind: Pod
metadata:
labels:
# Assume que todos os Pods relevantes têm um rótulo "tenant" definido
tenant: tenant-a
...
spec:
affinity:
podAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
# garante que os Pods associados a este locatário sejam alocados no pool de nós correto
- matchLabelKeys:
- tenant
labelSelector: {}
topologyKey: node-pool
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
# garante que os Pods associados a este locatário não possam ser alocados em nós usados por outro locatário
- mismatchLabelKeys:
- tenant # qualquer que seja o valor do rótulo "tenant" para este Pod, impede
# a alocação em nós de qualquer pool onde qualquer Pod de um
# locatário diferente esteja em execução.
labelSelector:
# Precisamos ter o labelSelector que seleciona apenas Pods com o rótulo tenant,
# caso contrário, este Pod teria antiafinidade contra Pods de DaemonSets também, por exemplo,
# que não deveriam ter o rótulo tenant.
matchExpressions:
- key: tenant
operator: Exists
topologyKey: node-pool
Afinidade e antiafinidade entre Pods podem ser ainda mais úteis quando são usadas com coleções de nível superior, como ReplicaSets, StatefulSets, Deployments, etc. Essas regras permitem configurar que um conjunto de cargas de trabalho deve ser colocalizado na mesma topologia definida; por exemplo, preferindo alocar dois Pods relacionados no mesmo nó.
Por exemplo: imagine um cluster de três nós. Você usa o cluster para executar uma aplicação web e também um cache em memória (como Redis). Para este exemplo, assuma também que a latência entre a aplicação web e o cache em memória deve ser a mais baixa possível. Você poderia usar afinidade e antiafinidade entre Pods para colocalizar os servidores web com o cache tanto quanto possível.
No seguinte exemplo de Deployment para o cache Redis, as réplicas recebem o rótulo app=store. A
regra podAntiAffinity diz ao escalonador para evitar alocar múltiplas réplicas
com o rótulo app=store em um único nó. Isso cria cada cache em um
nó separado.
apiVersion: apps/v1
kind: Deployment
metadata:
name: redis-cache
spec:
selector:
matchLabels:
app: store
replicas: 3
template:
metadata:
labels:
app: store
spec:
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app
operator: In
values:
- store
topologyKey: "kubernetes.io/hostname"
containers:
- name: redis-server
image: redis:3.2-alpine
O seguinte exemplo de Deployment para os servidores web cria réplicas com o rótulo app=web-store.
A regra de afinidade de Pod diz ao escalonador para alocar cada réplica em um nó que tenha um Pod
com o rótulo app=store. A regra de antiafinidade de Pod diz ao escalonador para nunca alocar
múltiplos servidores app=web-store em um único nó.
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-server
spec:
selector:
matchLabels:
app: web-store
replicas: 3
template:
metadata:
labels:
app: web-store
spec:
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app
operator: In
values:
- web-store
topologyKey: "kubernetes.io/hostname"
podAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app
operator: In
values:
- store
topologyKey: "kubernetes.io/hostname"
containers:
- name: web-app
image: nginx:1.16-alpine
Criar os dois Deployments anteriores resulta no seguinte layout de cluster, onde cada servidor web é colocalizado com um cache, em três nós separados.
| node-1 | node-2 | node-3 |
|---|---|---|
| webserver-1 | webserver-2 | webserver-3 |
| cache-1 | cache-2 | cache-3 |
O efeito geral é que cada instância de cache provavelmente será acessada por um único cliente que está executando no mesmo nó. Esta abordagem visa minimizar tanto a assimetria (carga desbalanceada) quanto a latência.
Você pode ter outras razões para usar antiafinidade de Pod. Consulte o tutorial do ZooKeeper para um exemplo de um StatefulSet configurado com antiafinidade para alta disponibilidade, usando a mesma técnica deste exemplo.
nodeName é uma forma mais direta de seleção de nó do que afinidade ou
nodeSelector. nodeName é um campo na especificação do Pod. Se o campo nodeName
não estiver vazio, o escalonador ignora o Pod e o kubelet no nó nomeado
tenta alocar o Pod naquele nó. Usar nodeName sobrepõe o uso de
nodeSelector ou regras de afinidade e antiafinidade.
Algumas das limitações de usar nodeName para selecionar nós são:
nodeName é destinado para uso por escalonadores personalizados ou casos de uso avançados onde
você precisa ignorar quaisquer escalonadores configurados. Ignorar os escalonadores pode levar a
Pods com falha se os nós atribuídos ficarem sobrecarregados. Você pode usar afinidade de nó
ou o campo nodeSelector para atribuir um Pod a um nó específico sem ignorar os escalonadores.Aqui está um exemplo de uma especificação de Pod usando o campo nodeName:
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
containers:
- name: nginx
image: nginx
nodeName: kube-01
O Pod acima será executado apenas no nó kube-01.
Kubernetes v1.35 [beta](habilitado por padrão)nominatedNodeName pode ser usado por componentes externos para nomear um nó para um pod pendente.
Esta nomeação é de melhor esforço: ela pode ser ignorada se o escalonador determinar que o pod não pode ir para o nó nomeado.
Além disso, este campo pode ser escrito (ou sobrescrito) pelo escalonador:
nominatedNodeName é definido apenas quando o pod precisa passar pelos pontos de extensão WaitOnPermit ou PreBind.Aqui está um exemplo de um status de Pod usando o campo nominatedNodeName:
apiVersion: v1
kind: Pod
metadata:
name: nginx
...
status:
nominatedNodeName: kube-01
Você pode usar restrições de distribuição de topologia para controlar como os Pods são distribuídos pelo seu cluster entre domínios de falha como regiões, zonas, nós, ou entre quaisquer outros domínios de topologia que você definir. Você pode fazer isso para melhorar o desempenho, a disponibilidade esperada ou a utilização geral.
Leia Restrições de distribuição de topologia de Pod para saber mais sobre como elas funcionam.
Kubernetes v1.35 [beta](habilitado por padrão)Os Pods herdam os rótulos de topologia (topology.kubernetes.io/zone e topology.kubernetes.io/region) do nó atribuído se esses rótulos estiverem presentes. Esses rótulos podem então ser utilizados através da Downward API para fornecer à carga de trabalho a informação da topologia do nó.
Aqui está um exemplo de um Pod usando a Downward API para sua zona e região:
apiVersion: v1
kind: Pod
metadata:
name: pod-with-topology-labels
spec:
containers:
- name: app
image: alpine
command: ["sh", "-c", "env"]
env:
- name: MY_ZONE
valueFrom:
fieldRef:
fieldPath: metadata.labels['topology.kubernetes.io/zone']
- name: MY_REGION
valueFrom:
fieldRef:
fieldPath: metadata.labels['topology.kubernetes.io/region']
A seguir estão todos os operadores lógicos que você pode usar no campo operator para nodeAffinity e podAffinity mencionados acima.
| Operador | Comportamento |
|---|---|
In |
O valor do rótulo está presente no conjunto de strings fornecido |
NotIn |
O valor do rótulo não está contido no conjunto de strings fornecido |
Exists |
Um rótulo com esta chave existe no objeto |
DoesNotExist |
Nenhum rótulo com esta chave existe no objeto |
Os seguintes operadores só podem ser usados com nodeAffinity.
| Operador | Comportamento |
|---|---|
Gt |
O valor do campo será interpretado como um inteiro, e o inteiro resultante da interpretação do valor de um rótulo nomeado por este seletor é maior que esse inteiro |
Lt |
O valor do campo será interpretado como um inteiro, e o inteiro resultante da interpretação do valor de um rótulo nomeado por este seletor é menor que esse inteiro |
Gt e Lt não funcionarão com valores não inteiros. Se o valor fornecido
não puder ser interpretado como um inteiro, o Pod não conseguirá ser alocado. Além disso, Gt e Lt
não estão disponíveis para podAffinity.Afinidade de nó é uma propriedade dos Pods que os associa a um conjunto de nós (seja como uma preferência ou uma exigência). Taints são o oposto -- eles permitem que um nó repudie um conjunto de pods.
Tolerâncias são aplicadas em pods e permitem, mas não exigem, que os pods sejam alocados em nós com taints correspondentes.
Taints e tolerâncias trabalham juntos para garantir que pods não sejam alocados em nós inapropriados. Um ou mais taints são aplicados em um nó; isso define que o nó não deve aceitar nenhum pod que não tolera essas taints.
Você adiciona um taint a um nó utilizando kubectl taint. Por exemplo,
kubectl taint nodes node1 key1=value1:NoSchedule
define um taint no nó node1. O taint tem a chave key1, valor value1 e o efeito NoSchedule.
Isso significa que nenhum pod conseguirá ser executado no nó node1 a menos que possua uma tolerância correspondente.
Para remover o taint adicionado pelo comando acima, você pode executar:
kubectl taint nodes node1 key1=value1:NoSchedule-
Você especifica uma tolerância para um pod na especificação do Pod. Ambas as seguintes tolerâncias "correspondem" ao taint criado pelo kubectl taint acima, e assim um pod com qualquer uma delas poderia ser executado no node1:
tolerations:
- key: "key1"
operator: "Equal"
value: "value1"
effect: "NoSchedule"
tolerations:
- key: "key1"
operator: "Exists"
effect: "NoSchedule"
Aqui está um exemplo de um pod que utiliza tolerâncias:
apiVersion: v1
kind: Pod
metadata:
name: nginx
labels:
env: test
spec:
containers:
- name: nginx
image: nginx
imagePullPolicy: IfNotPresent
tolerations:
- key: "example-key"
operator: "Exists"
effect: "NoSchedule"
O valor padrão de operator é Equal.
Uma tolerância "casa" um taint se as chaves e efeitos são os mesmos, e:
operator é Exists (no caso nenhum value deve ser especificado), ouoperator é Equal e os valores de value são iguais.Existem dois casos especiais:
Uma key vazia com o operador Exists "casa" todas as chaves, valores e efeitos, o que significa que o pod irá tolerar tudo.
Um effect vazio "casa" todos os efeitos com a chave key1.
O exemplo acima usou effect de NoSchedule. De forma alternativa, você pode usar effect de PreferNoSchedule.
Nesse efeito, o sistema tentará evitar que o pod seja alocado ao nó caso ele não tolere os taints definidos, contudo a alocação não será evitada de forma obrigatória. Pode-se dizer que o PreferNoSchedule é uma versão permissiva do NoSchedule. O terceiro tipo de effect é o NoExecute que será descrito posteriormente.
Você pode colocar múltiplos taints no mesmo nó e múltiplas tolerâncias no mesmo pod. O jeito que o Kubernetes processa múltiplos taints e tolerâncias é como um filtro: começa com todos os taints de um nó, em seguida ignora aqueles para os quais o pod tem uma tolerância relacionada; os taints restantes que não foram ignorados indicam o efeito no pod. Mais especificamente,
NoSchedule, o Kubernetes não alocará o pod naquele nóNoSchedule, mas existe pelo menos um taint não tolerado com o efeito PreferNoSchedule, o Kubernetes tentará não alocar o pod no nóNoExecute, o pod será expulso do nó (caso já esteja em execução) e não será alocado ao nó (caso ainda não esteja em execução).Por exemplo, imagine que você tem um nó com os seguintes taints
kubectl taint nodes node1 key1=value1:NoSchedule
kubectl taint nodes node1 key1=value1:NoExecute
kubectl taint nodes node1 key2=value2:NoSchedule
E um pod com duas tolerâncias:
tolerations:
- key: "key1"
operator: "Equal"
value: "value1"
effect: "NoSchedule"
- key: "key1"
operator: "Equal"
value: "value1"
effect: "NoExecute"
Nesse caso, o pod não será alocado ao nó porque não possui uma tolerância para o terceiro taint. Porém, se ele já estiver rodando no nó quando o taint foi adicionado, não será afetado e continuará rodando, tendo em vista que o terceiro taint é o único não tolerado pelo pod.
Normalmente, se um taint com o efeito NoExecute é adicionado a um nó, qualquer pod que não o tolere será expulso imediatamente e pods que o toleram nunca serão expulsos. Contudo, uma tolerância com efeito NoExecute pode especificar de forma opcional o campo tolerationSeconds, que determina quanto tempo o pod continuará alocado ao nó depois que o taint é adicionado. Por exemplo,
tolerations:
- key: "key1"
operator: "Equal"
value: "value1"
effect: "NoExecute"
tolerationSeconds: 3600
significa que se esse pod está sendo executado e um taint correspondente é adicionado ao nó, o pod irá continuar rodando neste nó por 3600 segundos e depois será expulso. Se o taint for removido antes desse tempo acabar, o pod não será expulso.
Taints e tolerâncias são um modo flexível de conduzir pods para fora dos nós ou expulsar pods que não deveriam estar sendo executados. Alguns casos de uso são
Nós Dedicados: Se você quiser dedicar um conjunto de nós para uso exclusivo de um conjunto específico de usuários, poderá adicionar um taint nesses nós. (digamos, kubectl taint nodes nodename dedicated=groupName:NoSchedule) e em seguida adicionar uma tolerância correspondente para seus pods (isso seria feito mais facilmente com a escrita de um controlador de admissão customizado).
Os pods com tolerância terão sua execução permitida nos nós com taints (dedicados), assim como em qualquer outro nó no cluster. Se você quiser dedicar nós a esses pods e garantir que eles usem apenas os nós dedicados, precisará adicionar uma label similar ao taint para o mesmo conjunto de nós (por exemplo, dedicated=groupName), e o controle de admissão deverá adicionar uma afinidade de nó para exigir que os pods podem ser executados apenas nos nós definidos com a label dedicated=groupName.
Nós com hardware especial: Em um cluster no qual um pequeno grupo de nós possui hardware especializado (por exemplo, GPUs), é desejável manter pods que não necessitem desse tipo de hardware fora desses nós, dessa forma o recurso estará disponível para pods que precisem do hardware especializado. Isso pode ser feito aplicando taints nos nós com o hardware especializado (por exemplo, kubectl taint nodes nodename special=true:NoSchedule or kubectl taint nodes nodename special=true:PreferNoSchedule) e aplicando uma tolerância correspondente nos pods que usam o hardware especial. Assim como no caso de uso de nós dedicados, é provavelmente mais fácil aplicar as tolerâncias utilizando um controlador de admissão.
Por exemplo, é recomendado usar Extended Resources para representar hardware especial, adicione um taint ao seus nós de hardware especializado com o nome do recurso estendido e execute o controle de admissão ExtendedResourceToleration. Agora, tendo em vista que os nós estão marcados com um taint, nenhum pod sem a tolerância será executado neles. Porém, quando você submete um pod que requisita o recurso estendido, o controlador de admissão ExtendedResourceToleration irá adicionar automaticamente as tolerâncias necessárias ao pod que irá, por sua vez, ser alocado no nó com hardware especial. Isso garantirá que esses nós de hardware especial serão dedicados para os pods que requisitarem tal recurso e você não precisará adicionar manualmente as tolerâncias aos seus pods.
Expulsões baseadas em Taint: Um comportamento de expulsão configurada por pod quando problemas existem em um nó, o qual será descrito na próxima seção.
Kubernetes v1.18 [stable]
O efeito de taint NoExecute, mencionado acima, afeta pods que já estão rodando no nó da seguinte forma
tolerationSeconds em sua especificação de tolerância, ficam alocados para sempretolerationSeconds especificado, permanecem alocados pela quantidade de tempo definidaO controlador de nó automaticamente adiciona um taint ao Nó quando certas condições se tornam verdadeiras. Os seguintes taints são embutidos:
node.kubernetes.io/not-ready: Nó não está pronto. Isso corresponde ao NodeCondition Ready com o valor "False".node.kubernetes.io/unreachable: Nó é inalcançável a partir do controlador de nó. Isso corresponde ao NodeCondition Ready com o valor "Unknown".node.kubernetes.io/memory-pressure: Nó possui pressão de memória.node.kubernetes.io/disk-pressure: Nó possui pressão de disco.node.kubernetes.io/pid-pressure: Nó possui pressão de PID.node.kubernetes.io/network-unavailable: A rede do nó está indisponível.node.kubernetes.io/unschedulable: Nó não é alocável.node.cloudprovider.kubernetes.io/uninitialized: Quando o kubelet é iniciado com um provedor de nuvem "externo", esse taint é adicionado ao nó para que ele seja marcado como não utilizável. Após o controlador do cloud-controller-manager inicializar o nó, o kubelet remove esse taint.No caso de um nó estar prestes a ser expulso, o controlador de nó ou kubelet adicionam os taints relevantes com o efeito NoExecute. Se a condição de falha retorna ao normal, o kubelet ou controlador de nó podem remover esses taints.
Você pode especificar tolerationSeconds em um Pod para definir quanto tempo ele ficará alocado em um nó que está falhando ou está sem resposta.
Por exemplo, você talvez queira manter uma aplicação com vários estados salvos localmente alocado em um nó por um longo período na ocorrência de uma divisão na rede, esperando que essa divisão se recuperará e assim a expulsão do pod pode ser evitada. A tolerância que você define para esse Pod poderia ficar assim:
tolerations:
- key: "node.kubernetes.io/unreachable"
operator: "Exists"
effect: "NoExecute"
tolerationSeconds: 6000
O Kubernetes automaticamente adiciona uma tolerância para node.kubernetes.io/not-ready e node.kubernetes.io/unreachable com tolerationSeconds=300, a menos que você, ou um controlador, defina essas tolerâncias explicitamente.
Essas tolerâncias adicionadas automaticamente significam que Pods podem continuar alocados aos Nós por 5 minutos após um desses problemas ser detectado.
Pods do tipo DaemonSet são criados com tolerâncias NoExecute sem a propriedade tolerationSeconds para os seguintes taints:
node.kubernetes.io/unreachablenode.kubernetes.io/not-readyIsso garante que esses pods do DaemonSet nunca sejam expulsos por conta desses problemas.
A camada de gerenciamento, usando o controlador do nó, cria taints automaticamente com o efeito NoSchedule para condições de nó.
O agendador verifica taints, não condições de nó, quando realiza suas decisões de agendamento. Isso garante que as condições de nó não afetem diretamente o agendamento.
Por exemplo, se a condição de nó DiskPressure está ativa, a camada de gerenciamento adiciona o taint node.kubernetes.io/disk-pressure e não aloca novos pods no nó afetado. Se a condição MemoryPressure está ativa, a camada de gerenciamento adiciona o taint node.kubernetes.io/memory-pressure.
Você pode ignorar condições de nó para pods recém-criados adicionando tolerâncias correspondentes. A camada de controle também adiciona a tolerância node.kubernetes.io/memory-pressure em pods que possuem uma classe de QoS diferente de BestEffort. Isso ocorre porque o Kubernetes trata pods nas classes de QoS Guaranteed ou Burstable (até mesmo pods sem requisitos de memória definidos) como se fossem capazes de lidar com pressão de memória, enquanto novos pods com BestEffort não são alocados no nó afetado.
O controlador DaemonSet adiciona automaticamente as seguintes tolerâncias de NoSchedule para todos os daemons, prevenindo que DaemonSets quebrem.
node.kubernetes.io/memory-pressurenode.kubernetes.io/disk-pressurenode.kubernetes.io/pid-pressure (1.14 ou superior)node.kubernetes.io/unschedulable (1.10 ou superior)node.kubernetes.io/network-unavailable (somente rede do host)Adicionando essas tolerâncias garante retro compatibilidade. Você também pode adicionar tolerâncias de forma arbitrária aos DaemonSets.
Kubernetes v1.18 [beta]
Quando você executa um Pod num nó, o próprio Pod usa uma quantidade de recursos do sistema. Estes recursos são adicionais aos recursos necessários para executar o(s) contêiner(s) dentro do Pod. Sobrecarga de Pod, do inglês Pod Overhead, é uma funcionalidade que serve para contabilizar os recursos consumidos pela infraestrutura do Pod para além das solicitações e limites do contêiner.
No Kubernetes, a sobrecarga de Pods é definido no tempo de admissão de acordo com a sobrecarga associada à RuntimeClass do Pod.
Quando é ativada a Sobrecarga de Pod, a sobrecarga é considerada adicionalmente à soma das solicitações de recursos do contêiner ao agendar um Pod. Semelhantemente, o kubelet incluirá a sobrecarga do Pod ao dimensionar o cgroup do Pod e ao executar a classificação de prioridade de migração do Pod em caso de drain do Node.
Terá de garantir que o Feature Gate
PodOverhead esteja ativo (está ativo por padrão a partir da versão 1.18)
em todo o cluster, e uma RuntimeClass utilizada que defina o campo overhead.
Para usar a funcionalidade PodOverhead, é necessário uma RuntimeClass que define o campo overhead.
Por exemplo, poderia usar a definição da RuntimeClass abaixo com um agente de execução de contêiner virtualizado
que use cerca de 120MiB por Pod para a máquina virtual e o sistema operacional convidado:
---
kind: RuntimeClass
apiVersion: node.k8s.io/v1beta1
metadata:
name: kata-fc
handler: kata-fc
overhead:
podFixed:
memory: "120Mi"
cpu: "250m"
As cargas de trabalho que são criadas e que especificam o manipulador RuntimeClass kata-fc irão
usar a sobrecarga de memória e cpu em conta para os cálculos da quota de recursos, agendamento de nós,
assim como dimensionamento do cgroup do Pod.
Considere executar a seguinte carga de trabalho de exemplo, test-pod:
apiVersion: v1
kind: Pod
metadata:
name: test-pod
spec:
runtimeClassName: kata-fc
containers:
- name: busybox-ctr
image: busybox
stdin: true
tty: true
resources:
limits:
cpu: 500m
memory: 100Mi
- name: nginx-ctr
image: nginx
resources:
limits:
cpu: 1500m
memory: 100Mi
No tempo de admissão o controlador de admissão RuntimeClass
atualiza o PodSpec da carga de trabalho de forma a incluir o overhead como descrito na RuntimeClass. Se o PodSpec já tiver este campo definido
o Pod será rejeitado. No exemplo dado, como apenas o nome do RuntimeClass é especificado, o controlador de admissão muda o Pod de forma a
incluir um overhead.
Depois do controlador de admissão RuntimeClass, pode verificar o PodSpec atualizado:
kubectl get pod test-pod -o jsonpath='{.spec.overhead}'
A saída é:
map[cpu:250m memory:120Mi]
Se for definido um ResourceQuota, a soma das requisições dos contêineres assim como o campo overhead são contados.
Quando o kube-scheduler está decidindo que nó deve executar um novo Pod, o agendador considera o overhead do pod,
assim como a soma de pedidos aos contêineres para esse Pod. Para este exemplo, o agendador adiciona as requisições e a sobrecarga, depois procura um nó com 2.25 CPU e 320 MiB de memória disponível.
Assim que um Pod é agendado a um nó, o kubelet nesse nó cria um novo cgroup para o Pod. É dentro deste Pod que o agente de execução de contêiners subjacente vai criar contêineres.
Se o recurso tiver um limite definido para cada contêiner (QoS garantida ou Burstrable QoS com limites definidos),
o kubelet definirá um limite superior para o cgroup do Pod associado a esse recurso (cpu.cfs_quota_us para CPU
e memory.limit_in_bytes de memória). Este limite superior é baseado na soma dos limites do contêiner mais o overhead
definido no PodSpec.
Para CPU, se o Pod for QoS garantida ou Burstrable QoS, o kubelet vai definir cpu.shares baseado na soma dos
pedidos ao contêiner mais o overhead definido no PodSpec.
Olhando para o nosso exemplo, verifique as requisições ao contêiner para a carga de trabalho:
kubectl get pod test-pod -o jsonpath='{.spec.containers[*].resources.limits}'
O total de requisições ao contêiner são 2000m CPU e 200MiB de memória:
map[cpu: 500m memory:100Mi] map[cpu:1500m memory:100Mi]
Verifique isto comparado ao que é observado pelo nó:
kubectl describe node | grep test-pod -B2
A saída mostra que 2250m CPU e 320MiB de memória são solicitados, que inclui PodOverhead:
Namespace Name CPU Requests CPU Limits Memory Requests Memory Limits AGE
--------- ---- ------------ ---------- --------------- ------------- ---
default test-pod 2250m (56%) 2250m (56%) 320Mi (1%) 320Mi (1%) 36m
Verifique os cgroups de memória do Pod no nó onde a carga de trabalho está em execução. No seguinte exemplo, crictl
é usado no nó, que fornece uma CLI para agentes de execução compatíveis com CRI. Isto é um
exemplo avançado para mostrar o comportamento do PodOverhead, e não é esperado que os usuários precisem verificar
cgroups diretamente no nó.
Primeiro, no nó em particular, determine o identificador do Pod:
# Execute no nó onde o Pod está agendado
POD_ID="$(sudo crictl pods --name test-pod -q)"
A partir disto, pode determinar o caminho do cgroup para o Pod:
# Execute no nó onde o Pod está agendado
sudo crictl inspectp -o=json $POD_ID | grep cgroupsPath
O caminho do cgroup resultante inclui o contêiner pause do Pod. O cgroup no nível do Pod está um diretório acima.
"cgroupsPath": "/kubepods/podd7f4b509-cf94-4951-9417-d1087c92a5b2/7ccf55aee35dd16aca4189c952d83487297f3cd760f1bbf09620e206e7d0c27a"
Neste caso especifico, o caminho do cgroup do Pod é kubepods/podd7f4b509-cf94-4951-9417-d1087c92a5b2. Verifique a configuração cgroup de nível do Pod para a memória:
# Execute no nó onde o Pod está agendado
# Mude também o nome do cgroup para combinar com o cgroup alocado ao Pod.
cat /sys/fs/cgroup/memory/kubepods/podd7f4b509-cf94-4951-9417-d1087c92a5b2/memory.limit_in_bytes
Isto é 320 MiB, como esperado:
335544320
Uma métrica kube_pod_overhead está disponível em kube-state-metrics
para ajudar a identificar quando o PodOverhead está sendo utilizado e para ajudar a observar a estabilidade das cargas de trabalho
em execução com uma sobrecarga (Overhead) definida. Esta funcionalidade não está disponível na versão 1.9 do kube-state-metrics,
mas é esperado em uma próxima versão. Os usuários necessitarão entretanto construir o kube-state-metrics a partir do código fonte.