05 - Deployment

No Kubernetes, um Deployment é um dos recursos mais utilizados para gerenciar e implantar aplicações de maneira declarativa. Ele abstrai e simplifica o gerenciamento de Pods (as unidades básicas de execução no Kubernetes), fornecendo uma forma confiável e escalável de implantar, atualizar, e manter aplicações em execução no cluster.

Indice

O que é um Deployment?

 Um Deployment é um recurso do Kubernetes definido por meio de um arquivo de configuração YAML ou JSON, que especifica como os Pods devem ser criados e gerenciados. Ele descreve o estado desejado de uma aplicação, incluindo:

  • Quantas réplicas da aplicação devem estar em execução.
  • A imagem do container a ser usada.
  • Configurações de rede, volumes e outras dependências.
  • Estratégias de atualização (como Rolling Update ou Recreate).

Quando um Deployment é aplicado no cluster, o Kubernetes assume a responsabilidade de atingir e manter o estado desejado especificado no arquivo de configuração.

 

Funções de um Deployment

O Deployment oferece várias funcionalidades importantes:

  1. Controle de Réplicas:

    • Ele garante que um número especificado de réplicas de Pods esteja em execução a qualquer momento. Caso algum Pod falhe, o Deployment recria automaticamente os Pods para restaurar o estado desejado.
  2. Atualizações de Aplicação:

    • Permite atualizar aplicações sem downtime, utilizando a estratégia de Rolling Update, que substitui gradualmente os Pods antigos por novos.
    • Também suporta reversão para versões anteriores caso algo dê errado.
  3. Reversão:

    • Mantém o histórico das versões aplicadas. Se uma nova versão de um Deployment causar problemas, é possível reverter rapidamente para uma versão anterior.
  4. Escalabilidade:

    • Pode escalar a aplicação horizontalmente aumentando ou diminuindo o número de réplicas conforme a demanda.
  5. Autocorreção:

    • Monitora o estado dos Pods e os substitui automaticamente se eles falharem ou forem excluídos.
  6. Controle Declarativo:

    • Facilita o gerenciamento por meio de arquivos YAML/JSON, permitindo descrever o estado desejado da aplicação de forma simples e repetível.
 
 

Exemplo de um Deployment

Abaixo um exemplo de configuração YAML para criar um Deployment:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: minha-aplicacao
spec:
  replicas: 3
  selector:
    matchLabels:
      app: minha-aplicacao
  template:
    metadata:
      labels:
        app: minha-aplicacao
    spec:
      containers:
      - name: meu-container
        image: nginx:1.21.1
        ports:
        - containerPort: 80

Nesse exemplo:

  • Um Deployment chamado minha-aplicacao é criado.
  • Ele gerencia 3 réplicas de Pods rodando um container baseado na imagem nginx:1.21.1.
  • Se um Pod falhar, ele será recriado automaticamente.
  • O Deployment pode ser escalado ou atualizado de forma declarativa.
 
 

Quando usar um Deployment?

Você deve usar um Deployment quando:

  • Precisa gerenciar o ciclo de vida de uma aplicação com múltiplas réplicas.
  • Deseja realizar atualizações de forma segura e automática.
  • Precisa de suporte para escalabilidade horizontal.
  • Busca autocorreção e alta disponibilidade.

Se o caso de uso for mais simples, como gerenciar apenas um único Pod sem réplicas ou atualização contínua, você pode usar um Pod ou um ReplicaSet diretamente, mas o Deployment é geralmente a escolha recomendada devido às suas funcionalidades adicionais.

 

Arquitetura

 

curso_K8S-Página-6

Como funciona?

a) O controlador do Deployment

O controlador de deployment no Kubernetes é responsável por criar e gerenciar o estado desejado especificado no manifesto. Ele faz isso interagindo com outros componentes do Kubernetes, como o ReplicaSet.

  • ReplicaSet: O Deployment cria um ReplicaSet, que é um controlador responsável por garantir que o número especificado de réplicas do Pod esteja em execução.

b) Ciclo de Vida

  1. Criação do ReplicaSet:

    • Quando o deployment é aplicado, ele cria um ReplicaSet com base no template especificado.
    • O ReplicaSet gerencia diretamente os Pods, garantindo que o número de réplicas esteja de acordo com a configuração.
  2. Criação dos Pods:

    • O ReplicaSet cria os Pods conforme especificado no template.
    • Esses Pods são agendados para nós disponíveis pelo kube-scheduler.
  3. Monitoramento e Reações:

    • O Deployment observa constantemente o estado dos Pods por meio do kube-controller-manager.
    • Se um Pod falha ou é excluído, o ReplicaSet cria um novo Pod para substituí-lo.
 

A cada update no Deployment, o Kubernetes cria um novo ReplicaSet. Isso ocorre para gerenciar as diferentes versões dos Pods durante o processo de atualização. Aqui está como funciona em detalhes:

1. Processo de Criação de ReplicaSets em Atualizações

  • Quando um Deployment é atualizado (por exemplo, ao alterar a imagem ou a configuração do Pod template), o controlador do Deployment cria um novo ReplicaSet para representar a nova versão.
  • O ReplicaSet antigo ainda permanece no cluster, mas o número de réplicas associadas a ele é gradativamente reduzido conforme os Pods da nova versão são criados.

2. Rolling Update e Gerenciamento de ReplicaSets

Durante um Rolling Update:

  1. Novo ReplicaSet é criado: Ele começa a criar Pods com a nova configuração ou imagem.
  2. ReplicaSet antigo é reduzido: Os Pods do ReplicaSet antigo são gradualmente removidos à medida que os Pods do novo ReplicaSet entram em execução.
  3. O Deployment gerencia a transição entre os ReplicaSets, controlando parâmetros como:
    • maxUnavailable: O número máximo de Pods indisponíveis durante o processo.
    • maxSurge: O número máximo de Pods extras permitidos temporariamente.

3. Manutenção de ReplicaSets

  • O ReplicaSet antigo não é removido imediatamente, mesmo após a conclusão do update. Ele permanece no cluster para permitir um rollback, caso seja necessário.
  • Se você fizer múltiplas atualizações consecutivas, o Deployment pode acumular vários ReplicaSets antigos, mas ele geralmente mantém apenas alguns, conforme especificado pela configuração de revisionHistoryLimit (padrão: 10 revisões):
spec:
  revisionHistoryLimit: 5

Podemos encontrar o número de ReplicatSets não utilizados executando:

kubectl get replicaset -A | awk ‘{if ($2 + $3 + $4 == 0) print $1}’ | wc -l

As colunas $2, $3 e $4 são os estados Desejado, Atual e Pronto, respectivamente, para os ReplicatSets

 

Para alterar o revisionHistoryLimit, podemos usar o comando de implantação do patch kubectl para corrigir essas implantações.

kubectl patch deployment -n <namespace> <deployment> --type=json -p=’[{“op”: “replace”, “path”: “/spec/revisionHistoryLimit”, “value”: 10}]’

Create deployment

Lab – Deployment na prática

Existem algumas formas nas quais podemos criar um artefato e neste caso do deployment vou citar 3 formar a primeira é rodando via cli (linha de comando) do kubernetes:

kubectl create deployment --image nginx nginx

Neste caso o kubectl é o comando da cli kubernetes o create a ação o depoyment o objeto o –image nginx a imagem a ser utilizada e o nginx o nome do deployment

Outra forma é criando o arquivo .yaml também chamado de manifesto dentro do contexto kubernetes, podemos copiar de algum já existente ou criar cada step na mão isso pode gerar erros de identação ou ortografia recomendo usar algum plugin por exemplo plugins dentro do vscode.

vim nginx.yaml
apiVersion: apps/v1 
kind: Deployment
metadata:
  labels: 
    app: nginx 
  name: nginx 
spec: 
  replicas: 1 
  selector: 
    matchLabels: 
      app: nginx 
  template: 
    metadata:
      labels:
        app: nginx 
    spec: 
      containers:
      - image: nginx
        name: nginx

Para aplicar:

kubectl create -f nginx.yaml

Gerenciando Rollouts

Labels, matchLabels e selectors - Destrichando um manifesto .YAML

MaxSurge e MaxUnavailable: Otimizando deployment

Escalando um deployment

Resources: Como delimitar recursos computacionais?

Request and Limits na prática

Goldilocks: Como descobrir o request/limits ideal para a aplicação:

Troubleshooting: Analisar OOM (Out Of Memory)

O processo de Out Of Memory (OOM) no Kubernetes ocorre quando um contêiner ou nó consome mais memória do que está disponível ou permitido, levando a uma interrupção no funcionamento normal para liberar recursos. O Kubernetes implementa mecanismos de controle e recuperação para lidar com situações de memória insuficiente. Aqui está como o processo funciona:
1. Limite de Memória do Contêiner
  • Configuração de memória nos pods:
    • Em Kubernetes, você pode definir limites de memória e solicitações de memória para os contêineres em um pod.
resources:
  requests:
    memory: "256Mi"
  limits:
    memory: "512Mi"
  • requests: Garante uma quantidade mínima de memória reservada para o contêiner.
  • limits: Define o limite máximo de memória que o contêiner pode usar.
2. Quando um Contêiner Excede o Limite

Se o contêiner tentar usar mais memória do que o especificado em limits:

  • O kernel do sistema operacional mata o processo principal do contêiner usando o recurso chamado Out-Of-Memory Killer (OOM Killer).
  • O Kubernetes detecta que o contêiner foi finalizado com um código de saída relacionado à falha por falta de memória (código 137).
  • Com base na política de reinício configurada (restartPolicy), o Kubernetes pode:
    • Reiniciar o contêiner automaticamente (Always ou OnFailure).
    • Não reiniciá-lo (Never).
3. OOM no Nível do Nó

Se o nó no qual os pods estão executando não tiver memória suficiente para suportar todos os contêineres:

  • O sistema operacional do nó executa o OOM Killer no nível do nó.
  • O Kubernetes pode realizar o eviction de pods, removendo pods com menor prioridade para liberar recursos.
Critérios de Eviction:

O Kubernetes usa QoS (Quality of Service) para determinar quais pods serão desalocados, considerando:

  1. BestEffort: Pods sem requests ou limits definidos são os primeiros a serem desalocados.
  2. Burstable: Pods com requests menores que limits vêm em seguida.
  3. Guaranteed: Pods com requests iguais aos limits são os últimos a serem desalocados.
4. Recuperação Automática
  • O kubelet no nó tenta recuperar a situação liberando recursos.
  • Pods desalocados ou finalizados podem ser recriados em outros nós disponíveis (se houver capacidade no cluster e as políticas de replicação permitirem).
5. Logs e Diagnóstico
  • É possível verificar os eventos relacionados ao OOM no Kubernetes:
kubectl get events --namespace=<namespace>
  • Para logs específicos de um pod ou nó:
kubectl logs <pod-name>
kubectl describe pod <pod-name>

Estratégias para Evitar OOM

  1. Configurar requests e limits adequados:
    • Defina valores apropriados baseados no consumo real da aplicação.
  2. Horizontal Pod Autoscaling (HPA):
    • Aumente automaticamente o número de réplicas com base no uso de recursos.
  3. Monitoramento e Alertas:
    • Use ferramentas como Prometheus, Grafana, ou Kubernetes Metrics Server para monitorar o uso de memória.
  4. Garantir nós suficientes:
    • Dimensione o cluster para suportar o volume de trabalho.

Essas práticas ajudam a mitigar o impacto de falhas por falta de memória e garantem um ambiente mais resiliente.

Lab – Analisando OOM (Out Of Memory)

Para simularmos esse problema vamos utilizar esta applicação desenvolvida pelo Valentino Miazzo, esta aplicação consiste em uma imagem docker rodando uma app em java que fica alocando memória repetitiva até estourar os limites do container.

Se quiser entender um pouco melhor segue o código fonte:

github

Primeiro passo vamos criar o yaml:

vim oom.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: oom-deployment
  name: oom-deployment
spec:
  replicas: 1
  selector:
    matchLabels:
      app: oom-deployment
  template:
    metadata:
      creationTimestamp: null
      labels:
        app: oom-deployment
    spec:
      containers:
      - image: valentinomiazzo/jvm-memory-test
        name: memorytest
        env:
          - name: "ALLOC_HEAP_MB"
            value: "100"
          - name: "MAX_HEAP_SIZE_MB"
            value: "2000"
        resources:
          requests:
            cpu: 100m
            memory: 512M
          limits:
            cpu: 1
            memory: 1G

Para acompanharmos em tempo real abra um outro terminal e digite:

kubectl get pods -w

Agora vamos executar a criação do deployment referente a aplicação:

kubectl apply -f oom.yaml

acompanhe o processo …

… podemos verificar através do describe do pod e tentar identificar o último estado que foi o terminate e o porque ele foi terminado, também podemos identificar em qual node (nó) ele executou e analisar mais a fundo os logs, se a distribuição for Ubuntu os logs estarão em /var/logs/kern.log se form CentOS em /var/log/messages.

 

Executar o describe com:

kubectl describe pod [POD]

Identificado o node, logar e executar:

cat /var/log/kern.log (Ubuntu) ou /var/log/messages.log

podemos analisar os recursos de memória do node pra saber se esse não é o problema:

free -m

Introdução aos probes (healthchecks) do Kubernetes

O que são probes?

No Kubernetes, probes são mecanismos que permitem verificar a saúde ou seja (HealthCheck) e a disponibilidade de containers que estão sendo executados em pods. Essas verificações ajudam o Kubernetes a tomar decisões sobre gerenciar os ciclos de vida dos containers, como reiniciar um container que falhou (Self-Healing) ou remover ele de uma lista de balanceamento de carga.

Diagrama sem nome-LOADBALANCER

Existem três tipos principais de probes no Kubernetes:


1. Liveness Probe (Prova de Liveness)

  • Objetivo: Verifica se o container está “vivo” ou em funcionamento.
  • Ação: Se a liveness probe falhar, o Kubernetes reinicia o container, pois assume que ele entrou em um estado irrecuperável.
  • Exemplo: Um container pode travar, mas seu processo principal ainda está em execução. A liveness probe identifica esses casos.
Diagrama sem nome-LIVENESS

2. Readiness Probe (Prova de Disponibilidade)

  • Objetivo: Determina se o container está pronto para receber tráfego.
  • Ação: Se a readiness probe falhar, o container é removido dos endpoints de serviço, e o tráfego não será direcionado para ele até que ele seja considerado saudável novamente.
  • Exemplo: O container está iniciando, mas ainda não está pronto para processar solicitações porque está carregando configurações ou dependências.
Diagrama sem nome-REDINESS


3. Startup Probe (Prova de Inicialização)

  • Objetivo: Verifica se o container inicializou corretamente.
  • Ação: É usada para containers com tempo de inicialização longo. Se essa probe falhar, o Kubernetes assume que o processo de inicialização do container falhou e o reinicia.
  • Exemplo: Um container que executa um serviço pesado pode demorar mais para inicializar do que o esperado.

 

Como funcionam as probes

As probes utilizam diferentes métodos para verificar o estado dos containers:

  • HTTP Request: Faz uma solicitação HTTP para um endpoint específico no container.
livenessProbe:
  httpGet:
    path: /health
    port: 8080
  initialDelaySeconds: 3
  periodSeconds: 5
  • Comando (exec): Executa um comando dentro do container e verifica o código de saída.
readinessProbe:
  exec:
    command:
    - cat
    - /tmp/health
  initialDelaySeconds: 5
  periodSeconds: 5
  • TCP Socket: Tenta se conectar a uma porta do container.
livenessProbe:
  tcpSocket:
    port: 8080
  initialDelaySeconds: 10
  periodSeconds: 5

Configuração de Probes no Pod

As probes são definidas na especificação do container dentro de um Pod, como no exemplo abaixo:

apiVersion: v1
kind: Pod
metadata:
  name: myapp
spec:
  containers:
  - name: myapp-container
    image: myapp:latest
    livenessProbe:
      httpGet:
        path: /healthz
        port: 8080
      initialDelaySeconds: 3
      periodSeconds: 5
    readinessProbe:
      tcpSocket:
        port: 8080
      initialDelaySeconds: 5
      periodSeconds: 10
    startupProbe:
      exec:
        command:
        - cat
        - /app/ready
      initialDelaySeconds: 10
      periodSeconds: 5

Resumo:

  • Liveness Probe: “O container ainda está funcionando?”
  • Readiness Probe: “O container está pronto para receber tráfego?”
  • Startup Probe: “O container conseguiu inicializar corretamente?”

 

Probes ajudam a aumentar a robustez e a confiabilidade das aplicações executadas no Kubernetes, garantindo que apenas containers saudáveis e prontos processem tráfego.

plugins premium WordPress