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.
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:
Quando um Deployment é aplicado no cluster, o Kubernetes assume a responsabilidade de atingir e manter o estado desejado especificado no arquivo de configuração.
O Deployment oferece várias funcionalidades importantes:
Controle de Réplicas:
Atualizações de Aplicação:
Reversão:
Escalabilidade:
Autocorreção:
Controle Declarativo:
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:
minha-aplicacao
é criado.nginx:1.21.1
.Você deve usar um Deployment quando:
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.
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.
Criação do ReplicaSet:
Criação dos Pods:
Monitoramento e Reações:
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:
Durante um Rolling Update:
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}]’
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
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.Se o contêiner tentar usar mais memória do que o especificado em limits
:
restartPolicy
), o Kubernetes pode:Always
ou OnFailure
).Never
).Se o nó no qual os pods estão executando não tiver memória suficiente para suportar todos os contêineres:
O Kubernetes usa QoS (Quality of Service) para determinar quais pods serão desalocados, considerando:
requests
ou limits
definidos são os primeiros a serem desalocados.requests
menores que limits
vêm em seguida.requests
iguais aos limits
são os últimos a serem desalocados.kubectl get events --namespace=<namespace>
kubectl logs <pod-name>
kubectl describe pod <pod-name>
requests
e limits
adequados:Essas práticas ajudam a mitigar o impacto de falhas por falta de memória e garantem um ambiente mais resiliente.
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:
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
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.
Existem três tipos principais de probes no Kubernetes:
As probes utilizam diferentes métodos para verificar o estado dos containers:
livenessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 3
periodSeconds: 5
readinessProbe:
exec:
command:
- cat
- /tmp/health
initialDelaySeconds: 5
periodSeconds: 5
livenessProbe:
tcpSocket:
port: 8080
initialDelaySeconds: 10
periodSeconds: 5
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
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.