Essa é a versão completa de impressão dessa seção Clique aqui para imprimir.
Escalonamento
1 - Escalonador do Kubernetes
No Kubernetes, escalonamento refere-se a garantir que os Pods sejam correspondidos aos Nodes para que o Kubelet possa executá-los.
Visão geral do Escalonamento
Um escalonador observa Pods recém-criados que não possuem um Node atribuído. Para cada Pod que o escalonador descobre, ele se torna responsável por encontrar o melhor Node para execução do Pod. O escalonador chega a essa decisão de alocação levando em consideração os princípios de programação descritos abaixo.
Se você quiser entender por que os Pods são alocados em um Node específico ou se planeja implementar um escalonador personalizado, esta página ajudará você a aprender sobre escalonamento.
kube-scheduler
kube-scheduler é o escalonador padrão do Kubernetes e é executado como parte do control plane. O kube-scheduler é projetado para que, se você quiser e precisar, possa escrever seu próprio componente de escalonamento e usá-lo.
Para cada Pod recém-criado ou outros Pods não escalonados, o kube-scheduler seleciona um Node ideal para execução. No entanto, todos os contêineres nos Pods têm requisitos diferentes de recursos e cada Pod também possui requisitos diferentes. Portanto, os Nodes existentes precisam ser filtrados de acordo com os requisitos de escalonamento específicos.
Em um cluster, Nodes que atendem aos requisitos de escalonamento para um Pod são chamados de Nodes viáveis. Se nenhum dos Nodes for adequado, o Pod permanece não escalonado até que o escalonador possa alocá-lo.
O escalonador encontra Nodes viáveis para um Pod e, em seguida, executa um conjunto de funções para pontuar os Nodes viáveis e escolhe um Node com a maior pontuação entre os possíveis para executar o Pod. O escalonador então notifica o servidor da 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, localidade de dados, interferência entre cargas de trabalho e assim por diante.
Seleção do Node no kube-scheduler
O kube-scheduler seleciona um Node para o Pod em uma operação que consiste em duas etapas:
- Filtragem
- Pontuação
A etapa de filtragem localiza o conjunto de Nodes onde é possível alocar o Pod. Por exemplo, o filtro PodFitsResources verifica se um Node 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 Nodes contém quaisquer Nodes 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 Nodes restantes para escolher o mais adequado. O escalonador atribui uma pontuação a cada Node que sobreviveu à filtragem, baseando essa pontuação nas regras de pontuação ativa.
Por fim, o kube-scheduler atribui o Pod ao Node com a classificação mais alta. Se houver mais de um Node 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:
Políticas de Escalonamento permitem configurar Predicados para filtragem e Prioridades para pontuação.
Perfis de Escalonamento permitem configurar Plugins que implementam diferentes estágios de escalonamento, incluindo:
QueueSort
,Filter
,Score
,Bind
,Reserve
,Permit
, e outros. Você também pode configurar o kube-scheduler para executar diferentes perfis.
Qual é o próximo
- Leia sobre ajuste de desempenho do escalonador
- Leia sobre restrições de propagação da topologia de pod
- Leia a documentação de referência para o kube-scheduler
- Aprenda como configurar vários escalonadores
- Aprenda sobre políticas de gerenciamento de topologia
- Aprenda sobre Pod Overhead
- Saiba mais sobre o agendamento de pods que usam volumes em:
2 - Sobrecarga de Pod
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.
Habilitando a Sobrecarga de Pod
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
.
Exemplo de uso
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
Verificar os limites cgroup do Pod
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
Observabilidade
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.