Como acessar os recursos do pod do Kubernetes

A recompensa de Tohad



Ao começar com o Kubernetes, é comum esquecer a configuração de recursos de contêiner. Neste ponto, você só precisa se certificar de que a imagem Docker está funcionando e pode ser implantada em seu cluster do Kubernetes.



Mais tarde, porém, o aplicativo precisa ser implantado no cluster de produção junto com outros aplicativos. Para fazer isso, você precisa alocar recursos para o contêiner e certificar-se de que haja recursos suficientes para iniciar e executar o aplicativo, e em outros aplicativos em execução não haverá problemas.



A equipe Kubernetes aaS de Mail.ru traduziu um artigo sobre recursos de contêiner (CPU e MEM), solicitações e limites de recursos. Você aprenderá os benefícios dessas configurações e o que acontecerá se você não instalá-las.



Recursos de computação



Temos dois tipos de recursos com as seguintes unidades:



  • Unidade de processamento central (CPU) - núcleos;
  • Memória (MEM) - bytes.


Os recursos são especificados para cada contêiner. No seguinte arquivo pod YAML, você verá uma seção de recursos que contém os recursos solicitados e limitados:



  • Recursos de pod solicitados = a soma dos recursos solicitados de todos os pods;
  • Limite de recursos do pod = a soma dos recursos marginais de todos os contêineres.


apiVersion: v1
kind: Pod
metadata:
  name: backend-pod-name
  labels:
    application: backend
spec:
  containers:
    — name: main-container
      image: my-backend
      tag: v1
      ports:
      — containerPort: 8080
      resources:
        requests:
          cpu: 0.2 # REQUESTED CPU: 200m cores
          memory: "1Gi" # REQUESTED MEM: 1Gi
        limits:
          cpu: 1 # MAX CPU USAGE: 1 core
          memory: "1Gi" # MAX MEM USAGE:  1Gi
    — name: other-container
      image: other-app
      tag: v1
      ports:
      — containerPort: 8000
      resources:
        requests:
          cpu: "200m" # REQUESTED CPU: 200m cores
          memory: "0.5Gi" # REQUESTED MEM: 0.5Gi
        limits:
          cpu: 1 # MAX CPU USAGE: 1 core
          memory: "1Gi" # MAX MEM USAGE:  1Gi
Exemplo de recursos solicitados e de limite Um



campo resources.requestedda especificação do pod é um dos elementos usados ​​para encontrar o nó desejado. Já nele, você pode agendar uma implantação de pod. Como você encontra um nó adequado?



O Kubernetes consiste em vários componentes, incluindo o nó mestre ou nó mestre (plano de controle do Kubernetes). Existem vários processos no nó mestre: kube-apiserver, kube-controller-manager e kube-scheduler.



O processo kube-scheduler é responsável por examinar os módulos recém-criados e procurar por nós de trabalho possíveis que correspondam a todas as solicitações de módulo, incluindo o número de recursos solicitados. A lista de nós encontrados por kube-scheduler é classificada. O pod é planejado para o site com as pontuações mais altas.



Onde o Pod roxo será colocado?



A imagem mostra que o agendador de kube deve agendar um novo Pod roxo. O cluster Kubernetes contém dois nós: A e B. Como você pode ver, o kube-scheduler não pode agendar um pod para o nó A - os recursos disponíveis (não solicitados) não correspondem às solicitações do pod roxo. Por exemplo, o 1 GB de memória solicitado pelo pod roxo não caberá no nó A, pois a memória disponível é de 0,5 GB. Mas o Nó B tem recursos suficientes. Como resultado, o programador de kube decide que o destino do pod roxo é o nó B.



Agora sabemos como os recursos solicitados afetam a escolha do nó para iniciar o pod. Mas como os recursos marginais afetam?



Os recursos de limite são um limite que a CPU / MEM não pode cruzar. No entanto, a CPU é flexível, portanto, os contêineres que atingirem o limite da CPU não farão com que o pod seja encerrado. Em vez disso, o afogamento da CPU será iniciado. Se o limite de uso do MEM for atingido, o contêiner será interrompido devido ao OOM-Killer e reiniciado, se permitido pela configuração RestartPolicy.



Recursos solicitados e limitados em detalhes



Relacionamento de recursos entre o Docker e o Kubernetes A



melhor maneira de explicar como os recursos solicitados e limitados funcionam é representar a relação entre o Kubernetes e o Docker. Na imagem acima, você pode ver como os campos do Kubernetes e os sinalizadores de inicialização do Docker estão relacionados.



Memória: Solicitação e Limite



containers:
...
 resources:
   requests:
     memory: "0.5Gi"
   limits:
     memory: "1Gi"


Conforme mencionado acima, a memória é medida em bytes. Com base na documentação do Kubernetes , podemos especificar a memória como um número. Normalmente é um número inteiro, por exemplo 2678 - ou seja, 2678 bytes. Você também pode usar sufixos Ge Gi, o mais importante, lembre-se de que eles não são equivalentes. O primeiro é decimal e o segundo é binário. Como exemplo, mencionado nos K8S documentação: 128974848, 129e6, 129M, 123Mi- eles são praticamente equivalentes.



O parâmetro Kubernetes limits.memorycorresponde à sinalização --memorydo Docker. No caso derequest.memorynão há seta para o Docker porque o Docker não usa esse campo. Você pode perguntar se isso é necessário? Sim, preciso. Como eu disse antes, o campo é importante para o Kubernetes. Com base nas informações dele, o kube-scheduler decide para qual nó agendar o pod.



O que acontece se não houver memória suficiente instalada para uma consulta?



Se o contêiner atingir os limites da memória solicitada, o pod é colocado no grupo de pods, que para quando não há memória no nó.



O que acontece se você definir o limite de memória muito baixo?



Se o contêiner exceder o limite de memória, ele será encerrado devido a OOM-Killed. E será reiniciado, se possível, com base em RestartPolicy, onde o padrão é Always.



O que acontece se você não especificar a memória solicitada?



O Kubernetes pegará o limite e o definirá como padrão.



O que pode acontecer se você não especificar o limite de memória?



O container não tem limites, pode usar a quantidade de memória que quiser. Se ele começar a usar toda a memória disponível no nó, o OOM o matará. O contêiner será reiniciado se possível com base em RestartPolicy.



O que acontece se você não especificar os limites de memória?



Este é o pior cenário: o planejador não sabe de quantos recursos o contêiner precisa, e isso pode causar sérios problemas no nó. Nesse caso, seria bom ter restrições de namespace padrão (definidas por LimitRange). Por padrão, não há limites - o pod não tem limites e pode usar a quantidade de memória que desejar.



Se a memória solicitada for maior do que o nó pode oferecer, o pod não será programado. É importante lembrar que Requests.memorynão é um valor mínimo. Esta é uma descrição da quantidade de memória suficiente para o contêiner ser executado continuamente.



Geralmente, é recomendado definir o mesmo valor para request.memoryelimit.memory... Isso evita que o Kubernetes programe um pod em um nó que tem memória suficiente para executar o pod, mas não o suficiente para executá-lo. Lembre-se: ao programar um pod, o Kubernetes só conta requests.memory, limits.memorynão conta.



CPU: Solicitação e Limite



containers:
...
 resources:
   requests:
     cpu: 1
   limits:
     cpu: "1200m"


Com a CPU, tudo fica um pouco mais complicado. Voltando à imagem da relação entre o Kubernetes e o Docker, você pode ver que ele request.cpucorresponde --cpu-shares, embora limit.cpucorresponda ao sinalizador cpusno Docker.



A CPU solicitada pelo Kubernetes é multiplicada por 1.024, a proporção dos ciclos da CPU. Se você deseja solicitar 1 núcleo completo, deve adicionar cpu: 1conforme mostrado acima.



Solicitar um kernel completo (proporção = 1024) não significa que seu contêiner o receberá. Se sua máquina host tiver apenas um núcleo e você estiver usando mais de um contêiner, todos os contêineres devem compartilhar a CPU disponível entre eles. Como isso acontece? Vamos dar uma olhada na foto.





Solicitação de CPU - Sistema de núcleo único



Digamos que você tenha um sistema host de núcleo único executando contêineres. A mãe (Kubernetes) fez uma torta (CPU) e quer compartilhá-la com os filhos (contêineres). Três crianças querem um bolo inteiro (proporção = 1024), outra criança quer metade do bolo (512). A mãe quer ser justa e faz um cálculo simples.



#    ?
# 3           
cakesNumberKidsWant = (3 * 1) + (1 * 0.5) = 3.5
#   :
3 (/) * 1 ( / ) + 1 (/) * 0.5 ( / )
#   ?
availableCakesNumber = 1
#   ()    ?
newMaxRequest = 1 / 3.5 =~ 28%


Com base no cálculo, três crianças receberão 28% do kernel, e não o kernel inteiro. O quarto filho receberá 14% do kernel completo, não metade. Mas as coisas serão diferentes se você tiver um sistema multi-core.





Solicitação de CPU - Sistema Multi-core (4)



Na imagem acima, você pode ver que três crianças querem uma torta inteira e uma quer metade. Como a mãe assou quatro bolos, cada um dos filhos receberá o quanto quiser. Em um sistema com vários núcleos, os recursos do processador são distribuídos por todos os núcleos de processador disponíveis. Se um contêiner estiver limitado a menos de um núcleo de CPU completo, ele ainda poderá usá-lo 100%.



Os cálculos acima são simplificados para entender como a CPU é alocada entre os contêineres. Claro, além dos próprios contêineres, existem outros processos que também usam recursos da CPU. Quando os processos em um contêiner estão ociosos, outros podem usar seu recurso. CPU: "200m"corresponde CPU: 0,2, o que significa cerca de 20% de um núcleo.



Agora vamos falar sobrelimit.cpu... A CPU que limita o Kubernetes é multiplicada por 100. O resultado é a quantidade de tempo que o contêiner pode usar a cada 100 μs ( cpu-period).



limit.cpucorresponde à bandeira do Docker --cpus. Esta é uma nova combinação de antigo --cpu-periode --cpu-quota. Ao defini-lo, especificamos quantos recursos de CPU disponíveis o contêiner pode usar ao máximo até que comece a se limitar:



  • cpus é uma combinação de cpu-periode é cpu-quota. cpus = 1.5equivalente a definir cpu-period = 100000e cpu-quota = 150000;
  • cpu-period - período do agendador CFS da CPU , por padrão 100 microssegundos;
  • cpu-quota - o número de microssegundos dentro do cpu-periodqual o contêiner é limitado.


O que acontece se a CPU solicitada for insuficiente?



Se o contêiner precisar de mais do que está instalado, ele roubará a CPU de outros processos.



O que acontece se você definir um limite de CPU insuficiente?



Como o recurso da CPU é ajustável, a aceleração será ativada.



O que acontece se você não especificar uma solicitação de CPU?



Tal como acontece com a memória, o valor do pedido é igual ao limite.



O que acontece se você não especificar o limite da CPU?



O contêiner usará a quantidade de CPU necessária. Se uma política de CPU padrão (LimitRange) for definida no namespace, esse limite também será usado para o contêiner.



O que acontece se você não especificar a solicitação ou o limite da CPU?



Tal como acontece com a memória, este é o pior cenário. O planejador não sabe de quantos recursos seu contêiner precisa e isso pode causar sérios problemas no nó. Para evitar isso, você precisa definir os limites padrão para namespaces (LimitRange).



Lembre-se, se você solicitar mais CPU do que os nós podem fornecer, o pod não será programado. Requests.cpu- não um valor mínimo, mas um valor suficiente para iniciar o pod e funcionar sem problemas. Se seu aplicativo não executa cálculos complexos, a melhor opção é instalar request.cpu <= 1e executar quantas réplicas forem necessárias.



Quantidade ideal de recursos solicitados ou limite de recursos



Aprendemos sobre a limitação dos recursos de computação. Agora é hora de responder à pergunta: “De quantos recursos meu pod precisa para executar o aplicativo sem problemas? Qual é a quantidade ideal? "



Infelizmente, não há respostas definitivas para essas perguntas. Se você não sabe como está o desempenho do seu aplicativo, quanta CPU ou memória ele precisa, a melhor opção é dar ao aplicativo muita memória e CPU e depois executar benchmarks.



Além dos testes de desempenho, observe o comportamento de monitoramento do aplicativo por uma semana. Se os gráficos mostram que seu aplicativo está consumindo menos recursos do que você solicitou, você pode reduzir a quantidade de CPU ou memória solicitada.



Veja este painel do Grafana como exemplo .... Ele exibe a diferença entre os recursos solicitados ou o limite de recursos e o uso atual dos recursos.



Conclusão



Consultar e limitar recursos ajuda a manter o cluster do Kubernetes íntegro. A configuração correta dos limites minimiza os custos e mantém os aplicativos em execução o tempo todo.



Resumindo, existem algumas coisas a ter em mente:



  1. Os recursos solicitados são a configuração que é considerada durante a inicialização (quando o Kubernetes planeja hospedar o aplicativo). Em contraste, limitar os recursos é importante no tempo de execução - quando o aplicativo já está sendo executado no nó.
  2. Comparada à memória, a CPU é um recurso regulado. Em caso de CPU insuficiente, seu Pod não será desligado, ele começará a se estrangular.
  3. Os recursos solicitados e o limite de recursos não são valores mínimos e máximos! Ao identificar os recursos solicitados, você garante que seu aplicativo funcionará sem problemas.
  4. É uma boa prática definir a solicitação de memória igual ao limite de memória.
  5. É bom instalar conforme solicitado CPU <=1se o aplicativo não realizar cálculos complexos.
  6. Se você solicitar mais recursos do que o nó possui, o pod nunca será programado para esse nó.
  7. Use teste de carga e monitoramento para determinar a quantidade correta de recursos / limites de recursos solicitados.


Esperamos que este artigo o ajude a entender o conceito básico de limitação de recursos. E você poderá aplicar esse conhecimento em seu trabalho.



Boa sorte!



O que mais ler:



  1. Observabilidade SRE: namespaces e estrutura métrica .
  2. 90+ Kubernetes: , , , .
  3. Kubernetes .



All Articles