Gerenciamento de recursos em Pods e contêineres

Ao criar a especificação de um Pod, você pode opcionalmente especificar quanto de cada recurso um contêiner precisa. Os recursos mais comuns a serem especificados são CPU e memória (RAM); há outros recursos que podem ser especificados.

Quando você especifica o requerimento de recursos em um Pod, o kube-scheduler utiliza esta informação para decidir a qual nó o Pod será atribuído. Quando você especifica um limite de recurso para um contêiner, o kubelet garante o cumprimento de tais limites, de modo que o contêiner em execução não consiga utilizar uma quantidade de tal recurso além do limite especificado. O kubelet também reserva pelo menos o requerimento daquele recurso de sistema especificamente para que este contêiner utilize.

Requerimentos e limites

Se o nó em que um Pod está rodando tem o suficiente de um recurso específico disponível, é possível (e permitido) a um contêiner utilizar mais do que o seu request para aquele recurso especifica. No entanto, não é permitido a um contêiner consumir mais do que o seu limit para um recurso.

Por exemplo, se você especificar um requerimento de memory de 256 MiB para um contêiner, e aquele contêiner está em um Pod atribuído a um nó com 8GiB de memória, sem outros Pods, então este contêiner pode tentar consumir mais memória RAM.

Se você especificar um limite de memory de 4GiB para aquele contêiner, o kubelet (e o agente de execução de contêiner) vão garantir o cumprimento do limite. O agente de execução impede que o contêiner utilize mais de um recurso do que seu limite configurado. Por exemplo, quando um processo no contêiner tenta consumir mais que o limite permitido de memória, o núcleo do sistema encerra o processo que tentou efetuar a alocação de memória com um erro de memória esgotada (out of memory (OOM) error).

Limites podem ser implementados de forma reativa (o sistema intervém quando uma violação ocorre) ou por garantia (o sistema previne o contêiner de exceder o limite). Diferentes agentes de execução implementam as mesmas restrições de maneiras diferentes.

Tipos de recursos

CPU e memória são tipos de recursos. Um tipo de recurso possui uma unidade básica. CPU representa processamento computacional e é especificada em unidades de CPU do Kubernetes. Memória é especificada em bytes. Em cargas de trabalho Linux, você pode especificar o recurso huge pages. Huge pages são uma funcionalidade específica do Linux que permite ao núcleo do sistema operacional alocar blocos de memória muito maiores que o tamanho de página de memória padrão.

Por exemplo, em um sistema onde o tamanho da página de memória padrão é de 4 KiB, você pode especificar um limite hugepages-2Mi: 80Mi. Se o contêiner tentar alocar mais de 40 huge pages de 2 MiB cada, ou um total de 80 MiB, essa alocação irá falhar.

CPU e memória são chamados coletivamente de recursos computacionais, ou apenas recursos. Recursos computacionais são quantidades mensuráveis que podem ser requisitadas, alocadas, e consumidas. Estes recursos diferem dos recursos de API. Recursos de API, como Pods e Services são objetos que podem ser lidos e modificados através do servidor da API do Kubernetes.

Requerimentos de recursos e limites de Pod e contêiner

Para cada contêiner, você pode especificar limites e requerimentos de recursos, incluindo os seguintes recursos:

  • spec.containers[].resources.limits.cpu
  • spec.containers[].resources.limits.memory
  • spec.containers[].resources.limits.hugepages-<size>
  • spec.containers[].resources.requests.cpu
  • spec.containers[].resources.requests.memory
  • spec.containers[].resources.requests.hugepages-<size>

Embora você possa especificar apenas requerimentos e limites para contêineres individuais, é útil também pensar sobre os requerimentos e limites gerais de um Pod. Para um recurso em particular, um requerimento ou limite de recurso de um Pod é a soma de todos os valores dos requerimentos ou limites de um recurso daquele tipo, especificados em cada um dos contêineres daquele Pod.

Unidades de recursos no Kubernetes

Unidades de recurso de CPU

Limites e requerimentos de recursos de CPU são mensurados em unidades de cpu. No Kubernetes, uma unidade de CPU é equivalente a um núcleo físico de CPU, ou um núcleo virtual, dependendo se o nó é uma máquina física ou uma máquina virtual rodando em uma máquina física.

Requerimentos fracionários são permitidos. Quando você define um contêiner cujo valor do campo spec.containers[].resources.requests.cpu é 0.5, você está solicitando metade da quantidade de CPU que teria sido solicitada caso o valor fosse 1.0. No caso de unidades de recurso de CPU, a expressão de quantidade 0.1 é equivalente à expressão 100m, que pode ser lida como "cem milicpus", ou "cem milinúcleos". "Milicpu" ou "milinúcleo" equivalem à milésima parte de um núcleo ou CPU, de modo que "100m" equivalem a 10% do tempo computacional de um processador.

Recursos de CPU são sempre especificados como uma quantidade absoluta de recurso, nunca como uma quantidade relativa. Por exemplo, 500m de CPU representam grosseiramente a mesma quantidade de poder computacional, independentemente do contêiner rodar em uma máquina com processador de núcleo único, de dois núcleos ou de 48 núcleos.

Unidades de recurso de memória

Limites e requerimentos de memory são medidos em bytes. Você pode expressar memória como um número inteiro ou como um número de ponto fixo, utilizando um destes sufixos de quantidade: E, P, T, G, M, k. Você também pode utilizar os equivalentes de potência de dois: Ei, Pi, Ti, Gi, Mi, Ki. Por exemplo, as quantidades abaixo representam, a grosso modo, o mesmo valor:

128974848, 129e6, 129M, 128974848000m, 123Mi

Tome cuidado com os sufixos. Se você solicitar 400m de memória, esta quantidade estará de fato requerendo o equivalente a 0,4 byte de memória. A intenção da pessoa que fez esta requisição provavelmente era solictar 400 mebibytes (400Mi) ou 400 megabytes (400M).

Exemplo de recursos de contêiner

O Pod seguinte tem dois contêineres. Ambos os contêineres têm um requerimento de 0,25 CPU e 64 MiB (ou 226 bytes) de memória. Cada contêiner tem um limite de 0,5 CPU e 128 MiB de memória. Você pode dizer que o Pod tem um requerimento de 0,5 CPU e 128 MiB de memória, e um limite de 1 CPU e 256 MiB de memória.

---
apiVersion: v1
kind: Pod
metadata:
  name: frontend
spec:
  containers:
  - name: app
    image: images.my-company.example/app:v4
    resources:
      requests:
        memory: "64Mi"
        cpu: "250m"
      limits:
        memory: "128Mi"
        cpu: "500m"
  - name: log-aggregator
    image: images.my-company.example/log-aggregator:v6
    resources:
      requests:
        memory: "64Mi"
        cpu: "250m"
      limits:
        memory: "128Mi"
        cpu: "500m"

Como Pods com requerimentos de recursos são agendados

Quando você cria um Pod, o escalonador do Kubernetes seleciona um nó para que o Pod rode. Cada nó possui uma capacidade máxima para cada um dos tipos de recurso: a quantidade de CPU e memória que o nó pode fornecer aos Pods. O escalonador garante que, para cada tipo de recurso, a soma dos requerimentos de recursos dos contêineres agendados seja menor que a capacidade do nó. Note que, embora o consumo de memória ou CPU real nos nós seja muito baixo, o escalonador ainda irá se recusar a agendar um Pod em um nó se a verificação de capacidade falhar. Isso protege contra a falta de um recurso em um nó quando o consumo de recursos aumenta com o passar do tempo, como por exemplo durante o pico diário de requisições a um serviço.

Como o Kubernetes aplica requisições e limites de recursos

Quando o kubelet inicia um contêiner como parte de um Pod, o kubelet envia as requisições e limites de memória e de CPU ao agente de execução de contêiner.

No Linux, o agente de execução de contêiner normalmente configura os cgroups que aplicam e garantem os limites que você definiu.

  • O limite de CPU determina um teto de quanto tempo de CPU o contêiner pode utilizar. A cada intervalo de agendamento, o núcleo do sistema operacional do Linux verifica se este limite foi excedido; se este for o caso, o núcleo aguarda antes de permitir que aquele cgroup continue sua execução.
  • O requerimento de CPU normalmente define um método de balanceamento. Se vários contêineres diferentes (cgroups) querem rodar em um sistema disputado, cargas de trabalho com requerimentos maiores de CPU têm mais tempo de CPU alocado para si do que cargas de trabalho com pequenos requerimentos.
  • O requerimento de memória é usado principalmente durante o agendamento de um Pod. Em um nó que utiliza cgroups v2, o agente de execução de contêiner pode utilizar o requerimento de memória como uma dica para definir valores para memory.min e memory.low.
  • O limite de memória define um limite de memória para aquele cgroup. Se o contêiner tenta alocar mais memória que aquele limite, o subsistema out-of-memory do núcleo do sistema operacional Linux é ativado e, normalmente, intervém encerrando um dos processos do contêiner que tentou alocar mais memória. Se o processo em questão for o PID 1 do contêiner, e o contêiner estiver marcado como reinicializável, então o Kubernetes irá reiniciar o contêiner.
  • O limite de memória para um Pod ou contêiner é também aplicado a páginas em volumes armazenados em memória, como um emptyDir. O kubelet considera sistemas de arquivos tmpfs em volumes do tipo emptyDir como uso de memória em um contêiner, ao invés de armazenamento efêmero local.

Se um contêiner exceder seu requerimento de memória e o nó em que esse contêiner está rodando ficar com pouca memória no total, é provável que o Pod a que este contêiner pertence seja removido.

A um contêiner pode ou não ser permitido exceder seu limite de CPU por períodos de tempo estendidos. No entanto, agentes de execução de contêiner não encerram Pods por uso excessivo de CPU.

A fim de determinar se um contêiner não pode ser agendado ou está sendo encerrado devido a limites de recursos, consulte a seção de solução de problemas.

Monitorando utilização de recursos computacionais e de memória

O kubelet relata a utilização de recursos de um Pod como parte do status do Pod.

Se ferramentas opcionais para monitoramento de recursos estiverem disponíveis em seu cluster, a utilização de recursos de um Pod pode ser verificada diretamente através de API de métricas ou através das suas ferramentas de monitoramento

Armazenamento efêmero local

ESTADO DA FUNCIONALIDADE: Kubernetes v1.10 [beta]

Nós possuem armazenamento efêmero local, através de dispositivos de escrita conectados localmente ou através de RAM. "Efêmero" significa que não há garantia de longo termo com relação a durabilidade.

Pods utilizam armazenamento local efêmero para dados temporários, cache e logs. O kubelet pode fornecer armazenamento temporário a Pods que utilizam armazenamento local efêmero para montar volumes do tipo emptyDir em contêineres.

O kubelet também utiliza este tipo de armazenamento para logs de contêineres a nível de nó, imagens de contêiner e camadas graváveis de contêineres em execução.

Com esta funcionalidade em fase beta, o Kubernetes permite que você rastreie, reserve e limite quanto armazenamento local efêmero um Pod pode consumir.

Configurações para armazenamento local efêmero

O Kubernetes suporta duas formas de configuração para o armazenamento local efêmero em um nó:

Nesta configuração, você armazena todos os tipos diferentes de dados locais efêmeros (volumes do tipo emptyDir, camadas graváveis, imagens de contêiner, logs) em um sistema de arquivos único. A forma mais efetiva de configurar o kubelet é dedicar este sistema de arquivos aos dados do Kubernetes (kubelet).

O kubelet também escreve logs de contêiner a nível de nó e trata estes logs de maneira semelhante ao armazenamento efêmero local.

O kubelet escreve logs em arquivos dentro do seu diretório de log configurado (/var/log por padrão) e possui um diretório base para outros dados armazenados localmente (/var/lib/kubelet por padrão).

Normalmente, ambos os diretórios /var/lib/kubelet e /var/log encontram-se no sistema de arquivos raiz, e o kubelet é projetado com este desenho em mente.

Seu nó pode ter tantos outros sistemas de arquivos não utilizados pelo Kubernetes quantos você desejar.

Você tem um sistema de arquivos no nó que você utiliza para dados efêmeros que vêm de Pods em execução: logs e volumes do tipo emptyDir. Você pode utilizar este sistema de arquivos para outros dados (por exemplo, logs de sistema não relacionados ao Kubernetes); este sistema de arquivos pode até mesmo ser o sistema de arquivos raiz.

O kubelet também escreve logs de contêiner a nível de nó no primeiro sistema de arquivos e os trata de forma semelhante ao armazenamento local efêmero.

Você também tem um segundo sistema de arquivos, separado, conectado a um dispositivo lógico de armazenamento distinto. Nesta configuração, o diretório que você configurou o kubelet para armazenar as camadas de imagens de contêiner e as camadas graváveis de contêineres em execução estará neste segundo sistema de arquivos.

O primeiro sistema de arquivos não armazena nenhuma camada de imagens de contêiner ou camada gravável.

Seu nó pode ter tantos outros sistemas de arquivos não utilizados pelo Kubernetes quantos você desejar.

O kubelet consegue medir quanto armazenamento local está sendo utilizado. O kubelet faz isso desde que:

  • o feature gate LocalStorageCapacityIsolation esteja habilitado (a funcionalidade está ligada por padrão), e
  • você tenha configurado o nó utilizando uma das configurações suportadas para o armazenamento local efêmero.

Se você tiver uma configuração diferente, o kubelet não irá aplicar limites de recursos para o armazenamento local efêmero.

Configurando requerimentos e limites para armazenamento local efêmero

Você pode especificar o recurso ephemeral-storage para gerenciar o armazenamento local efêmero. Cada contêiner de um Pod pode especificar um dos valores abaixo, ou ambos:

  • spec.containers[].resources.limits.ephemeral-storage
  • spec.containers[].resources.requests.ephemeral-storage

Limites e requerimentos de ephemeral-storage são medidos em quantidades de bytes. Você pode expressar armazenamento como um inteiro ou como um valor de ponto fixo utilizando um dos seguintes sufixos: E, P, T, G, M, k. Você pode também utilizar os equivalentes de potência de dois: Ei, Pi, Ti, Gi, Mi, Ki. Por exemplo, as quantidades abaixo representam grosseiramente o mesmo valor:

  • 128974848
  • 129e6
  • 129M
  • 123Mi

No exemplo a seguir, o Pod tem dois contêineres. Cada contêiner tem um requerimento de 2GiB de armazenamento efêmero local. Cada contêiner tem um limite de 4GiB de armazenamento efêmero local. Portanto, o Pod tem um requerimento de 4GiB e um limite de 8GiB de armazenamento efêmero local.

apiVersion: v1
kind: Pod
metadata:
  name: frontend
spec:
  containers:
  - name: app
    image: images.my-company.example/app:v4
    resources:
      requests:
        ephemeral-storage: "2Gi"
      limits:
        ephemeral-storage: "4Gi"
    volumeMounts:
    - name: ephemeral
      mountPath: "/tmp"
  - name: log-aggregator
    image: images.my-company.example/log-aggregator:v6
    resources:
      requests:
        ephemeral-storage: "2Gi"
      limits:
        ephemeral-storage: "4Gi"
    volumeMounts:
    - name: ephemeral
      mountPath: "/tmp"
  volumes:
    - name: ephemeral
      emptyDir: {}

Como Pods com requerimentos de ephemeral-storage são agendados

Quando você cria um Pod, o Kubernetes seleciona um nó para o Pod rodar. Cada nó tem uma quantidade máxima de armazenamento efêmero local que pode ser fornecida aos Pods. Para mais informações, consulte Node Allocatable.

O escalonador garante que a soma dos requerimentos de recursos dos contêineres agendados é menor que a capacidade do nó.

Gerenciamento do consumo do armazenamento efêmero

Se o kubelet estiver gerenciando armazenamento local efêmero como um recurso, o kubelet irá medir o consumo de armazenamento em:

  • volumes emptyDir, com exceção dos volumes do tipo tmpfs
  • diretórios que armazenem logs a nível de nó
  • camadas de contêiner graváveis

Se um Pod estiver utilizando mais armazenamento efêmero do que o permitido, o kubelet irá gerar um sinal de remoção para aquele Pod.

Para isolamento a nível de contêiner, se o consumo de armazenamento de um contêiner em camadas graváveis e logs exceder seu limite de armazenamento, o kubelet irá marcar o Pod para remoção.

Para isolamento a nível de Pod, o kubelet calcula um limite de armazenamento total para um Pod somando os limites de cada contêiner naquele Pod. Neste caso, se a soma do consumo de armazenamento efêmero local de todas os contêineres e também dos volumes emptyDir de um Pod exceder o limite de armazenamento total do Pod, então o kubelet marca o Pod para remoção.

O kubelet suporta formas diferentes de medir o uso de armazenamento dos Pods:

O kubelet executa verificações agendadas, em intervalos regulares, que varrem cada volume do tipo emptyDir, diretório de log de contêiner, e camada gravável de contêiner.

A varredura mede quanto espaço está sendo utilizado.

Quotas de projeto são uma funcionalidade a nível de sistema operacional para gerenciamento de uso do armazenamento em sistemas de arquivos. Com o Kubernetes, você pode habilitar quotas de projeto para o monitoramento de armazenamento em uso. Tenha certeza que o sistema de arquivos do nó que esteja sendo utilizado em volumes do tipo emptyDir possui suporte a quotas de projeto. Por exemplo, os sistemas de arquivos XFS e ext4fs oferecem suporte a quotas de projeto.

O Kubernetes utiliza IDs de projeto iniciando em 1048576. Os IDs em uso estão registrados nos diretórios /etc/projects e /etc/projid. Se os IDs de projeto nestes intervalos forem utilizados para outros propósitos no sistema, estes IDs de projeto deverão estar registrados nos diretórios especificados acima para que o Kubernetes não os tente utilizar.

Quotas fornecem melhor desempenho e mais precisão do que varredura de diretórios. Quando um diretório é atribuído a um projeto, todos os arquivos criados no diretório são também criados no projeto, e o núcleo do sistema pode simplesmente manter controle de quantos blocos estão em uso por arquivos daquele projeto. Se um arquivo é criado e apagado, mas possui um descritor de arquivo aberto, ele continua a consumir espaço. O rastreio de quotas registra este espaço de forma precisa, enquanto varreduras de diretório ignoram o uso de espaço de armazenamento por arquivos apagados.

Se você deseja utilizar quotas de projeto, você deve:

  • Habilitar o feature gate LocalStorageCapacityIsolationFSQuotaMonitoring=true utilizando o campo featureGates na configuração do kubelet ou a opção de linha de comando --feature-gates.

  • Garantir que o sistema de arquivos raiz (ou o sistema de arquivos opcional de tempo de execução) tem quotas de projeto habilitadas. Todos os sistemas de arquivos XFS suportam quotas de projeto. Em sistemas de arquivos ext4, você precisa habilitar a funcionalidade de rastreio de quotas de projeto enquanto o sistema de arquivos ainda não está montado.

    # Para sistema de arquivos ext4, com o volume /dev/block-device não montado
    sudo tune2fs -O project -Q prjquota /dev/block-device
    
  • Garanta que o sistema de arquivos raiz (ou sistema de arquivos opcional de tempo de execução) esteja montado com quotas de projeto habilitadas. Em ambos os sistemas XFS e ext4fs, a opção de montagem é chamada prjquota.

Recursos estendidos

Recursos estendidos são nomes de recursos absolutos fora do domínio kubernetes.io. Estes recursos permitem a operadores de cluster anunciar e a usuários consumir recursos que não são embutidos pelo Kubernetes.

Dois passos são necessários para a utilização de recursos estendidos. Primeiramente, o operador do cluster deve anunciar um recurso estendido. Em segundo lugar, os usuários devem solicitar o recurso estendido em Pods.

Gerenciando recursos estendidos

Recursos estendidos a nível de nó

Recursos estendidos a nível de nó são recursos ligados ao nó.

Recursos gerenciados por dispositivos conectados

Veja Device Plugin para mais informações sobre como anunciar recursos gerenciados por dispositivos conectados em cada nó.

Outros recursos

A fim de anunciar um novo recurso estendido a nível de nó, o operador do cluster pode enviar uma requisição HTTP com o método PATCH para o servidor da API do Kubernetes para especificar a quantidade disponível em um nó no cluster, através do campo status.capacity. Após a realização desta operação, o campo status.capacity do nó irá conter um novo recurso. O campo status.allocatable é atualizado automaticamente pelo kubelet, de forma assíncrona, com o novo recurso.

Como o escalonador utiliza o valor do campo status.allocatable do nó ao verificar a saúde do Pod, o escalonador somente considerará o novo valor do campo após esta atualização assíncrona. Pode haver um pequeno atraso entre a atualização da capacidade do nó com um novo recurso e o momento em que o primeiro Pod que requer o recurso poderá ser agendado naquele nó.

Exemplo:

Este exemplo demonstra como utilizar a ferramenta curl para criar uma requisição HTTP que anuncia cinco recursos "example.com/foo" no nó k8s-node-1, cujo nó da camada de gerenciamento é k8s-master.

curl --header "Content-Type: application/json-patch+json" \
  --request PATCH \
  --data '[{"op": "add", "path": "/status/capacity/example.com~1foo", "value": "5"}]' \
  http://k8s-master:8080/api/v1/nodes/k8s-node-1/status

Recursos estendidos a nível de cluster

Recursos estendidos a nível de cluster não são vinculados aos nós. Estes recursos são normalmente gerenciados por extensões do escalonador, que manipulam o consumo e as quotas de recursos.

Você pode especificar os recursos estendidos que são manipulados por extensões do escalonador nas configurações do kube-scheduler.

Exemplo:

A configuração abaixo para uma política do escalonador indica que o recurso estendido a nível de cluster "example.com/foo" é manipulado pelas extensões do escalonador.

  • O escalonador envia um Pod para a extensão do escalonador somente se o Pod solicitar "example.com/foo".
  • O campo ignoredByScheduler especifica que o escalonador não verifica o recurso "example.com/foo" em seu predicado PodFitsResources.
{
  "kind": "Policy",
  "apiVersion": "v1",
  "extenders": [
    {
      "urlPrefix":"<extender-endpoint>",
      "bindVerb": "bind",
      "managedResources": [
        {
          "name": "example.com/foo",
          "ignoredByScheduler": true
        }
      ]
    }
  ]
}

Consumindo recursos estendidos

Usuários podem consumir recursos estendidos em especificações de Pods como CPU e memória. O escalonador controla a contagem de recursos de modo que a quantidade alocada simultaneamente a Pods não seja maior que a quantidade disponível.

O servidor da API limita as quantidades de recursos estendidos a números inteiros. Exemplos de quantidades válidas são 3, 3000m e 3Ki. Exemplos de quantidades inválidas são 0.5 e 1500m.

Para consumir um recurso estendido em um Pod, inclua o nome do recurso como uma chave no mapa spec.containers[].resources.limits na especificação do contêiner.

Um Pod só é agendado se todos os seus requerimentos de recursos forem satisfeitos, incluindo CPU, memória e quaisquer recursos estendidos. O Pod permanece no estado PENDING enquanto seus requerimentos de recursos não puderem ser satisfeitos.

Exemplo:

O Pod abaixo requisita duas CPUs e um "example.com/foo" (um recurso estendido).

apiVersion: v1
kind: Pod
metadata:
  name: my-pod
spec:
  containers:
  - name: my-container
    image: myimage
    resources:
      requests:
        cpu: 2
        example.com/foo: 1
      limits:
        example.com/foo: 1

Limitação de PID

Limites de ID de processo (PID) permitem à configuração de um kubelet limitar o número de PIDs que um dado Pod pode consumir. Consulte PID Limiting para mais informações.

Solução de problemas

Meus pods estão pendentes com um evento FailedScheduling

Se o escalonador não conseguir encontrar nenhum nó que atenda aos requisitos de recursos do Pod, este Pod permanecerá não-agendado até que um local destino possa ser encontrado. Um Evento é produzido cada vez que o escalonador falhar em encontrar um local para agendar o Pod. Você pode utilizar o utilitário kubectl para ver os eventos de um Pod. Por exemplo:

kubectl describe pod frontend | grep -A 9999999999 Events
Events:
  Type     Reason            Age   From               Message
  ----     ------            ----  ----               -------
  Warning  FailedScheduling  23s   default-scheduler  0/42 nodes available: insufficient cpu

No exemplo acima, o Pod de nome "frontend" não pôde ser agendado devido à nenhum nó possuir CPU suficiente para suprir seu requerimento de CPU. Mensagens de erro semelhantes a essa podem sugerir falha devido a falta de memória (PodExceedsFreeMemory). De maneira geral, se um Pod estiver pendente com uma mensagem deste tipo, há diversas possibilidades de solução a serem tentadas:

  • Adicione mais nós ao cluster.
  • Encerre Pods desnecessários para liberar espaço para Pods pendentes.
  • Verifique se o Pod não é maior que todos os nós. Por exemplo, se todos os nós têm uma capacidade de cpu: 1, um Pod que requisita cpu: 1.1 nunca será agendado.
  • Verifique se os nós não possuem taints. Se a maioria dos seus nós possuem taints, e o novo Pod não tolera tal taint, o escalonador somente considera agendar o Pod nos nós que não possuem aquele taint.

Você pode verificar capacidades de nós e quantidades alocadas com o comando kubectl describe nodes. Por exemplo:

kubectl describe nodes e2e-test-node-pool-4lw4
Name:            e2e-test-node-pool-4lw4
[ ... linhas abreviadas para simplificação ...]
Capacity:
 cpu:                               2
 memory:                            7679792Ki
 pods:                              110
Allocatable:
 cpu:                               1800m
 memory:                            7474992Ki
 pods:                              110
[ ... linhas abreviadas para simplificação ...]
Non-terminated Pods:        (5 in total)
  Namespace    Name                                  CPU Requests  CPU Limits  Memory Requests  Memory Limits
  ---------    ----                                  ------------  ----------  ---------------  -------------
  kube-system  fluentd-gcp-v1.38-28bv1               100m (5%)     0 (0%)      200Mi (2%)       200Mi (2%)
  kube-system  kube-dns-3297075139-61lj3             260m (13%)    0 (0%)      100Mi (1%)       170Mi (2%)
  kube-system  kube-proxy-e2e-test-...               100m (5%)     0 (0%)      0 (0%)           0 (0%)
  kube-system  monitoring-influxdb-grafana-v4-z1m12  200m (10%)    200m (10%)  600Mi (8%)       600Mi (8%)
  kube-system  node-problem-detector-v0.1-fj7m3      20m (1%)      200m (10%)  20Mi (0%)        100Mi (1%)
Allocated resources:
  (Total limits may be over 100 percent, i.e., overcommitted.)
  CPU Requests    CPU Limits    Memory Requests    Memory Limits
  ------------    ----------    ---------------    -------------
  680m (34%)      400m (20%)    920Mi (11%)        1070Mi (13%)

No exemplo anterior, você pode verificar que se um Pod requisitar mais que 1,120 CPUs ou mais que 6,23Gi de memória, tal Pod não caberá neste nó.

Ao verificar a seção "Pods", você pode observar quais Pods estão consumindo espaço neste nó.

A quantidade de recursos disponível aos Pods é menor que a capacidade do nó, pois daemons do sistema utilizam uma parcela dos recursos disponíveis. Dentro da API do Kubernetes, cada nó tem um campo .status.allocatable (consulte NodeStatus para mais detalhes).

O campo .status.allocatable descreve a quantidade de recursos que está disponível a Pods naquele nó (por exemplo: 15 CPUs virtuais e 7538 MiB de memória). Para mais informações sobre recursos alocáveis do nó no Kubernetes, veja Reserve Compute Resources for System Daemons.

Você pode configurar quotas de recursos para limitar a quantidade total de recursos que um namespace pode consumir. O Kubernetes garante quotas para objetos em um namespace específico quando há uma ResourceQuota naquele namespace. Por exemplo, se você atribuir namespaces específicos a times diferentes, você pode adicionar ResourceQuotas nestes namespaces. Criar quotas de recursos ajuda a evitar que um time utilize tanto de um recurso que chegue a afetar outros times utilizando o mesmo cluster.

Você deve também considerar o nível de acesso fornecido aos usuários de qualquer namespace: acesso completo para escrita permite a alguém com este acesso remover qualquer recurso, incluindo uma configuração de ResourceQuota.

Meu contêiner foi terminado

Seu contêiner pode ser terminado se faltar recursos para que este rode. Para verificar se um contêiner está sendo terminado por chegar no limite de algum recurso, utilize o comando kubectl describe pod no Pod em questão:

kubectl describe pod simmemleak-hra99

A saída será semelhante a:

Name:                           simmemleak-hra99
Namespace:                      default
Image(s):                       saadali/simmemleak
Node:                           kubernetes-node-tf0f/10.240.216.66
Labels:                         name=simmemleak
Status:                         Running
Reason:
Message:
IP:                             10.244.2.75
Containers:
  simmemleak:
    Image:  saadali/simmemleak:latest
    Limits:
      cpu:          100m
      memory:       50Mi
    State:          Running
      Started:      Tue, 07 Jul 2019 12:54:41 -0700
    Last State:     Terminated
      Reason:       OOMKilled
      Exit Code:    137
      Started:      Fri, 07 Jul 2019 12:54:30 -0700
      Finished:     Fri, 07 Jul 2019 12:54:33 -0700
    Ready:          False
    Restart Count:  5
Conditions:
  Type      Status
  Ready     False
Events:
  Type    Reason     Age   From               Message
  ----    ------     ----  ----               -------
  Normal  Scheduled  42s   default-scheduler  Successfully assigned simmemleak-hra99 to kubernetes-node-tf0f
  Normal  Pulled     41s   kubelet            Container image "saadali/simmemleak:latest" already present on machine
  Normal  Created    41s   kubelet            Created container simmemleak
  Normal  Started    40s   kubelet            Started container simmemleak
  Normal  Killing    32s   kubelet            Killing container with id ead3fb35-5cf5-44ed-9ae1-488115be66c6: Need to kill Pod

No exemplo acima, o campo Restart Count: 5 indica que o contêiner simmemleak deste Pod foi terminado e reiniciado cinco vezes até o momento. A razão OOMKilled demonstra que o contêiner tentou consumir mais memória do que o seu limite.

O próximo passo neste cenário seria vasculhar e depurar o código da aplicação, procurando por vazamentos de memória. Se você determinar que a aplicação está se comportando conforme o esperado, considere aumentar o limite (e possivelmente o requerimento) de memória para aquele contêiner.

Próximos passos

Última modificação December 15, 2024 at 6:24 PM PST: Merge pull request #49087 from Arhell/es-link (2c4497f)