No meu último post, demonstrei como isolar ambientes separando nosso cluster com namespaces. Dando continuidade a Jornada Kubernetes, hoje veremos como alocar e limitar recursos de memória e CPU em um Pod.

Mas antes, vale lembrar…

Recentemente, postei aqui no site que minha palestra na Trilha .NET sobre Implementando Métricas e Healthcheck em aplicações .NET foi aprovada para o The Developer’s Conference de Belo Horizonte. Portanto, no dia 15 de junho, temos um encontro marcado em solo mineiro.

Além disso, no dia 2 de maio, estarei no canal Coders in Rio para um talk coders com o tema AKS-Conhecendo o Kubernetes no Azure. Vou falar um pouco sobre o que aprendi criando a série Jornada Kubernetes, além de apresentar o serviço de Kubernetes no Azure. Não deixe de assistir e compartilhar pelo meetup do Coders in Rio.

Definir e Limitar para Proteger

Definir os recursos para cada contêineres que fazem parte do Pod é uma boa prática. Com isso, você garante que os Pods terão os recursos necessários para funcionar da forma correta.

Por outro lado, definir limites de consumo é igualmente importante. Pois irá garantir que caso um container, esteja consumindo uma quantidade de recursos muito a cima do esperado. Caso isso aconteça, ele será reiniciado ou encerrado.

Mensurando CPU

Os valores de CPU, são limitados ou mensurados em unidades de CPU. Isso significa, que se eu declarar 0.25, estou declarando um quarto de uma CPU, 0.5 representa a metade e assim por diante. É possível utilizar na forma de 100m, o que equivale a 100 milicpu ou 0.1.

Mensurando Memória

Os valores de memória, são limitados utilizando um valor numérico seguido de algum sufixo: E, Ei, P, Pi, T, Ti, G, Gi, M, Mi, K, Ki.

Exemplo de Configuração

Segue abaixo um manifesto de exemplo:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: resource-demo
spec:
  selector:
    matchLabels:
      app: resource-demo
  template:
    metadata:
      labels:
        app: resource-demo
    spec:
      containers:
      - name: container1
        image: vish/stress
        resources:
          requests:
            memory: "64Mi"
            cpu: "0.1"
          limits:
            memory: "128Mi"
            cpu: "0.25"
      - name: container2
        image: vish/stress
        resources:
          requests:
            memory: "128Mi"
            cpu: "0.25"
          limits:
            memory: "240Mi"
            cpu: "0.5"

No exemplo, vemos os seguintes valores de requisição e limitação:

ContainerMemória
Requisitada
CPU
Requisitada
Limite
Memória
Limite
CPU
container164Mi0.1128Mi0.25
container2128Mi0.25240Mi0.5

Com esses valores, vemos que para alocar esse pod é preciso 192Mi de memória e 0.35 de CPU.

Agora vamos fazer o deploy do nosso manifesto:

kubectl apply -f  resource-demo.yaml

E agora, verificar o consumo:

kubectl top pod <nome_do_pod>

Excedendo os limites

Nesse próximo exemplo, vou passar como argumento para o contêiner um valor que exceda o limite de alocação de memória:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: resource-demo
spec:
  selector:
    matchLabels:
      app: resource-demo
  template:
    metadata:
      labels:
        app: resource-demo
    spec:
      containers:
      - name: container1
        image: polinux/stress
        resources:
          requests:
            memory: "50Mi"
          limits:
            memory: "100Mi"
        command: ["stress"]
        args: ["--vm", "1", "--vm-bytes", "250M", "--vm-hang", "1"]

No exemplo, o contêiner tem um limite de 100m, porém, é solicitado 250m pela aplicação.

Vamos executar esse manifesto:

kubectl apply -f memory-limit.yaml

Após a execução, vamos verificar o status:

kubectl get pods

Como podem ver, o nosso Pod foi encerrado por conta do limite de memória excedido. E caso continuarmos a acompanhar, veremos que o Pod será sempre restartado.

Solicitando o que não tem

Agora como exemplo, teremos um Pod que nunca será criado. Pois será requisitada uma quantidade de memória, que nenhum Node do Cluster possui disponível.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: resource-demo
spec:
  selector:
    matchLabels:
      app: resource-demo
  template:
    metadata:
      labels:
        app: resource-demo
    spec:
      containers:
      - name: container1
        image: vish/stress
        resources:
          requests:
            memory: "2Gi"
            cpu: "0.1"
          limits:
            memory: "4Gi"
            cpu: "0.25"
kubectl apply -f memory-big-request.yaml

Agora, vamos verificar o pod:

kubectl get pod

Verificando a descrição do pod:

kubectl describe pod resource-demo-648df7dcb4-ccbmv

Verificamos que o Pod está pendente de criação e que o motivo é que nenhum Node possui memória suficiente para criar o Pod.

Com isso, abordamos como alocar e limitar recursos em nossos pods. Além da importância dessa prática em nossas aplicações.

Espero que ajude vocês a criar deployments mais otimizados. Lembrando que qualquer dúvida ou sugestão, basta comentarem aqui no site ou entrarem em contato comigo pelo Telegram.