Skip to content

Instantly share code, notes, and snippets.

@nunesfb
Last active October 2, 2025 22:14
Show Gist options
  • Select an option

  • Save nunesfb/c241fa68c81c7cc98174df9d590413a1 to your computer and use it in GitHub Desktop.

Select an option

Save nunesfb/c241fa68c81c7cc98174df9d590413a1 to your computer and use it in GitHub Desktop.
Docker com Kubernets

Introdução ao Kubernetes

Contexto e Motivação

Limitações do Docker isolado e do Docker Compose em produção

**Docker isolado:**Arquitetura do Kubernetes

  • Muito útil para criar e rodar containers individualmente.
  • Escalar manualmente exige iniciar múltiplos containers com comandos repetitivos.
  • Dificuldade em monitorar e manter containers distribuídos em várias máquinas.
  • Não resolve problemas de alta disponibilidade, orquestração e rede complexa.

Docker Compose:

  • Permite definir múltiplos serviços (containers) em um único arquivo YAML.
  • Ótimo para desenvolvimento e testes locais.
  • Porém, não é ideal para produção porque:
    • Não escala automaticamente.
    • Não tem balanceamento de carga nativo.
    • Não possui tolerância a falhas: se um container cair, ele não se recupera sozinho.
    • Não gerencia clusters de múltiplas máquinas.

Problemas de escala, disponibilidade e gerenciamento manual de containers

  • Escala: em produção, precisamos de dezenas ou centenas de instâncias rodando. Fazer isso manualmente é impraticável.
  • Disponibilidade: aplicações críticas precisam se manter ativas mesmo em falhas. Sem mecanismos automáticos, a queda de um container ou servidor gera indisponibilidade.
  • Gerenciamento manual: administrar containers em várias máquinas exige lidar com:
    • Rede entre containers distribuídos.
    • Balanceamento de tráfego.
    • Monitoramento e reinício em caso de falha.
    • Atualizações sem downtime (rolling updates).

Esses desafios exigiram uma ferramenta capaz de automatizar e padronizar a execução de containers em larga escala.


🔹 Por que surgiu o Kubernetes (história: Google Borg → Kubernetes)

  • Google Borg (anos 2000):

    • Sistema interno do Google criado para rodar milhões de containers em seus datacenters.
    • Fornecia automação, escalabilidade e resiliência muito antes da popularização do Docker.
  • Omega: sucessor do Borg, trazendo ideias mais flexíveis de agendamento e gestão de workloads.

  • 2014: engenheiros do Google aproveitaram a experiência desses projetos e lançaram o Kubernetes como open-source.

Kubernetes herdou os conceitos de Borg e Omega, mas os tornou acessíveis à comunidade global, criando o padrão de fato para orquestração de containers.


🔹 Kubernetes como orquestrador de containers

O Kubernetes (ou K8s) é um sistema de orquestração de containers.
Seu papel é automatizar:

  • Implantação (deploy) de containers.
  • Escalonamento (scale up/down).
  • Recuperação automática em falhas (self-healing).
  • Balanceamento de carga.
  • Atualizações sem interrupções.

Ele abstrai a complexidade de gerenciar múltiplos containers em múltiplos servidores, oferecendo uma visão unificada do cluster.

Hoje, o Kubernetes é mantido pela Cloud Native Computing Foundation (CNCF) e está presente em praticamente todos os grandes provedores de nuvem (AWS, GCP, Azure).


🐳 Atividades Práticas de Docker

Atividade Básica

Enunciado

Crie dois containers usando Docker:

  • Um container rodando nginx (porta 8080 → 80).
  • Um container rodando httpd (Apache) (porta 8081 → 80).

Após subir os containers, acesse-os pelo navegador ou via curl.

Em seguida, pare manualmente um dos containers e observe o que acontece com o serviço.

Responda:

  1. O serviço continua disponível?
  2. O Docker sozinho possui algum mecanismo para reiniciar automaticamente o container?
  3. Que problema esse comportamento pode causar em um ambiente de produção?

Gabarito

Comandos esperados:

docker run -d --name nginx -p 8080:80 nginx
docker run -d --name apache -p 8081:80 httpd

Testes:

Parar container:

docker stop nginx

Respostas:

  • O serviço fica indisponível imediatamente após o container ser parado.
  • O Docker não possui mecanismo nativo de orquestração para reiniciar containers falhos de forma inteligente (exceto se configurado com --restart=always, mas ainda é limitado).
  • Em produção, se um container cair, o serviço ficaria fora do ar até intervenção manual → falta de resiliência e automação.

Conclusão: O Docker isolado não garante alta disponibilidade.


Atividade Intermediária

Enunciado

Crie um arquivo docker-compose.yml que defina:

  • Um serviço backend usando node:18 (ou outro app simples).
  • Um serviço db usando postgres:15, com usuário e senha definidos via variáveis de ambiente.

Suba os serviços com:

docker-compose up -d

Responda:

  1. O Docker Compose consegue escalar o backend automaticamente caso haja aumento de tráfego?
  2. O que acontece se o container do banco cair?
  3. Quais limitações do Docker Compose você identifica para rodar essa aplicação em produção?

Gabarito

docker-compose.yml esperado (exemplo simplificado):

version: '3.9'
services:
  backend:
    image: node:18
    command: ["node", "-e", "require('http').createServer((req,res)=>res.end('Hello')).listen(3000)"]
    ports:
      - "3000:3000"
    depends_on:
      - db

  db:
    image: postgres:15
    environment:
      POSTGRES_USER: user
      POSTGRES_PASSWORD: password
      POSTGRES_DB: appdb
    ports:
      - "5432:5432"

Execução:

docker-compose up -d

Respostas:

  • O Docker Compose não escala automaticamente; é preciso rodar manualmente:
    docker-compose up --scale backend=3 -d
  • Se o container do banco cair, o backend perde conexão até que o container seja reiniciado manualmente.
  • Limitações identificadas:
    • Não há balanceamento de carga nativo.
    • Não há auto-recovery em caso de falhas.
    • Não escala dinamicamente com base em métricas.
    • Não possui mecanismos de monitoramento integrado.
    • Não é ideal para clusters distribuídos em múltiplos hosts.

Conclusão: O Docker Compose é ótimo para desenvolvimento local, mas não atende aos requisitos de produção em larga escala.

Introdução ao Kubernetes

O Docker por si só não instala o Kubernetes automaticamente.
O Kubernetes é um orquestrador de containers e precisa de sua própria instalação ou de uma ferramenta que simule um cluster local.

Para usar Kubernetes no seu ambiente, você tem algumas opções:


Documentação Oficial

MiniKube


Usar o Kind (Kubernetes in Docker)

Alternativa ao Minikube, cria clusters Kubernetes dentro de containers Docker.

Instalação:

curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.23.0/kind-linux-amd64
chmod +x ./kind
sudo mv ./kind /usr/local/bin/kind

Criar cluster:

kind create cluster

Usar distribuições completas

  • K3s → versão leve do Kubernetes, ideal para testes/IoT.
  • Kubernetes oficial (kubeadm) → instala em múltiplas máquinas/VMs, recomendado para aprender produção.

Plataformas gerenciadas

Se quiser praticar já em nuvem:

  • Google Kubernetes Engine (GKE)
  • Amazon EKS
  • Azure AKS

Conceitos Fundamentais

image

Cluster

  • Um cluster é o conjunto de máquinas (físicas ou virtuais) que trabalham em conjunto para executar aplicações em containers.
  • Essas máquinas são chamadas de nós (nodes) e podem estar distribuídas em diferentes servidores, datacenters ou nuvens.
  • O cluster oferece uma visão unificada: para o desenvolvedor, não importa em qual máquina o container está rodando, apenas que ele está dentro do cluster.
  • Isso permite escalabilidade horizontal (mais máquinas adicionadas conforme a demanda cresce).

🔹 Master (Control Plane)

  • O Control Plane é o cérebro do Kubernetes.
  • Responsável por gerenciar o estado desejado do cluster, ou seja:
    • Quantos Pods devem existir.
    • Onde eles devem rodar.
    • Como se comunicar entre si.

Principais componentes:

  • API Server: ponto central de comunicação (kubectl → API Server).
  • etcd: banco chave-valor que guarda todo o estado do cluster.
  • Scheduler: decide em qual Node cada Pod será alocado.
  • Controller Manager: mantém o estado desejado (ex.: se 3 Pods caírem, cria 3 novos).

🔹 Nodes (Workers)

  • Os Workers são os nós onde os containers realmente rodam.

Cada Worker possui:

  • Kubelet: agente que recebe instruções do Control Plane e garante que os Pods estão rodando como esperado.
  • Container Runtime: engine que executa os containers (Docker, containerd, CRI-O, etc.).
  • Kube-Proxy: gerencia rede e balanceamento de tráfego entre Pods e Services.

Em resumo: o Control Plane decide o que precisa ser feito e os Workers executam.


🔹 Pod

  • Um Pod é a menor unidade do Kubernetes.
  • Pode conter um ou mais containers, que compartilham:
    • Rede (mesmo IP e porta).
    • Armazenamento (volumes).

Exemplo: um Pod pode ter um container de aplicação (Node.js) e outro de logging/monitoramento (sidecar).

Diferente do Docker isolado, o Kubernetes não gerencia containers individualmente, mas sim Pods.


🔹 Deployment

  • Um Deployment é um objeto que gerencia Pods de forma declarativa.

Funcionalidades:

  • Criar e manter um número desejado de réplicas (ReplicaSet).
  • Substituir Pods antigos por novos em atualizações (rolling updates).
  • Garantir alta disponibilidade da aplicação.

Exemplo: você define no Deployment que quer 3 réplicas do Pod Nginx.
Se 1 falhar, o Kubernetes cria outro automaticamente.


🔹 Service

  • Um Service é a forma de expor Pods na rede de forma estável.
  • Como os Pods são criados e destruídos dinamicamente, seus IPs mudam o tempo todo.
  • O Service cria um endpoint fixo.

Tipos principais:

  • ClusterIP: comunicação interna entre Pods.
  • NodePort: expõe a aplicação em uma porta de cada nó do cluster.
  • LoadBalancer: integração com balanceadores externos (usado em nuvem).

Exemplo: um Service expõe o Deployment do Nginx em http://node-ip:30000.


🔹 Namespace

  • Um Namespace permite dividir logicamente um cluster em múltiplos ambientes isolados.
  • Útil para organizar aplicações, equipes ou ambientes (ex.: dev, test, prod).

Permite:

  • Gerenciar permissões com mais granularidade (RBAC por namespace).
  • Evitar conflitos de nomes entre objetos (Pods, Services, etc.).
  • Limitar recursos (CPU/RAM) por namespace.

Exemplo: dois times podem rodar aplicações chamadas frontend, mas em namespaces diferentes (team1/frontend, team2/frontend).

image

☸️ Atividades Práticas de Kubernetes

Atividade Básica

Enunciado

Usando o comando kubectl, crie um Pod simples com a imagem Nginx.

  • O Pod deve rodar com o nome nginx-pod e expor a porta 80.
  • Depois de criado, verifique se o Pod está em execução.

Responda:

  1. Qual a diferença entre criar um Pod diretamente e criar um Deployment?
  2. O que acontece se o Pod for excluído manualmente?

Gabarito

Comando para criar Pod:

kubectl run nginx-pod --image=nginx --port=80

Verificar status:

kubectl get pods

Testar logs ou shell dentro do Pod:

kubectl logs nginx-pod
kubectl exec -it nginx-pod -- curl localhost

Respostas:

  • Criar um Pod diretamente é útil para testes, mas ele não se recupera automaticamente se falhar. Já o Deployment gerencia Pods por meio de ReplicaSets, garantindo escalabilidade e resiliência.
  • Se o Pod for excluído, ele não será recriado automaticamente → é efêmero.

📌 Conclusão: Pods isolados são frágeis, o recomendado em produção é sempre usar um Deployment.


Atividade Intermediária

Enunciado

  1. Crie um namespace chamado meu-ambiente.
  2. Crie um Deployment chamado nginx-deployment com 3 réplicas da imagem nginx.
  3. Exponha esse Deployment por meio de um Service do tipo NodePort.
  4. Acesse o Nginx pelo navegador ou via curl.

Responda:

  1. Qual a vantagem de rodar em um namespace separado?
  2. Como o Service ajuda no acesso às réplicas do Deployment?

Gabarito

Criar namespace:

kubectl create namespace meu-ambiente

Criar Deployment com 3 réplicas:

kubectl create deployment nginx-deployment   --image=nginx --replicas=3 -n meu-ambiente

Expor Deployment com NodePort:

kubectl expose deployment nginx-deployment   --type=NodePort --port=80 -n meu-ambiente

Verificar Service e obter porta:

kubectl get svc -n meu-ambiente

Saída esperada (exemplo):

NAME               TYPE       CLUSTER-IP     EXTERNAL-IP   PORT(S)        AGE
nginx-deployment   NodePort   10.96.12.34    <none>        80:30080/TCP   1m

Habilitar a porta no kube:

kubectl port-forward svc/nginx-deployment 8080:80 -n meu-ambiente

Testar acesso via navegador ou curl:

http://localhost:8080

Respostas:

  • O namespace isola recursos, evitando conflitos de nomes e permitindo aplicar políticas de segurança e quotas específicas.
  • O Service age como um balanceador interno, distribuindo requisições entre os 3 Pods do Deployment.

📌 Conclusão: usar Deployment + Service + Namespace é a base da organização e resiliência no Kubernetes.


Arquitetura do Kubernetes

O Kubernetes possui uma arquitetura distribuída organizada em dois grandes blocos:

  • Plano de Controle (Control Plane): responsável por orquestrar, tomar decisões e manter o estado desejado.
  • Plano de Execução (Data Plane / Nodes): responsável por executar os containers (via Pods).

🔹 API Server

  • É o ponto central de comunicação no Kubernetes.
  • Tudo no Kubernetes é controlado via API, e o kube-apiserver expõe essa interface.
  • Ferramentas como kubectl, dashboards ou aplicações externas falam sempre com o API Server.

Funções principais:

  • Validar e processar requisições.
  • Salvar o estado desejado no etcd.
  • Distribuir instruções para os outros componentes do Control Plane.

➡️ Analogia: é o “balcão de atendimento” do cluster, onde você faz os pedidos.


🔹 etcd

  • É o banco de dados chave-valor distribuído usado pelo Kubernetes.
  • Guarda o estado atual e desejado do cluster (todos os objetos: Pods, Deployments, ConfigMaps, etc.).
  • Possui alta consistência, usando o algoritmo Raft para consenso.

Funções:

  • Armazena toda a configuração.
  • Permite recuperar o cluster em caso de falhas.
  • Atua como a “memória” do Kubernetes.

➡️ Sem o etcd, o cluster perde a capacidade de lembrar o que deve estar rodando.


🔹 Controller Manager

  • É o gerente automático do Kubernetes.
  • Monitora constantemente o estado do cluster (no etcd) e garante que ele esteja conforme o estado desejado.

Funções principais:

  • Criar novos Pods quando há menos réplicas do que o especificado.
  • Substituir Pods que falharam.
  • Gerenciar Jobs, Endpoints, Service Accounts e outros recursos.

Exemplo: você definiu 3 réplicas no Deployment → se 1 Pod cair, o Controller Manager cria outro para manter as 3 ativas.


🔹 Scheduler

  • Responsável por decidir em qual nó (Worker) cada Pod vai rodar.

Critérios usados na decisão:

  • Recursos disponíveis (CPU, memória).
  • Restrições de afinidade ou anti-afinidade.
  • Políticas de balanceamento de carga.

➡️ O Scheduler não executa o Pod, apenas decide o melhor lugar.
➡️ A execução real é feita pelo Kubelet do nó escolhido.

Analogia: é como um “despachante” que encaminha cada carga para o caminhão certo.


🔹 Kubelet

  • É um agente que roda em cada nó do cluster.

Funções principais:

  • Recebe instruções do API Server (via Control Plane).
  • Garante que os Pods definidos estejam de fato rodando no nó.
  • Se um container cair, tenta reiniciá-lo.
  • Reporta o status dos Pods para o Control Plane.

➡️ É como o “supervisor local” de cada máquina.


🔹 Kube-Proxy

  • Responsável por gerenciar a rede do cluster.

Funções principais:

  • Implementar as regras de rede (iptables ou IPVS).
  • Balancear tráfego entre Pods que fazem parte de um mesmo Service.
  • Permitir que um Pod em um nó consiga se comunicar com outro Pod em outro nó.

➡️ Em resumo: garante que os Pods consigam conversar entre si e com o mundo externo.


📊 Resumindo a Arquitetura

  • Control Plane: API Server, etcd, Controller Manager, Scheduler.
  • Data Plane (Workers): Kubelet, Kube-Proxy, Container Runtime.

Fluxo simplificado:

  1. O usuário aplica uma configuração (kubectl apply).
  2. O API Server registra no etcd.
  3. O Controller Manager detecta mudanças e pede ao Scheduler a alocação de Pods.
  4. O Scheduler escolhe o nó.
  5. O Kubelet executa o Pod no nó.
  6. O Kube-Proxy garante comunicação em rede.

☸️ Kubernetes — Atividade: Verificação do Cluster e Fluxo do Control Plane

🔹 Atividade Básica

Enunciado

Utilize os comandos kubectl para verificar o estado dos componentes principais do cluster Kubernetes.

Execute:

kubectl get componentstatus
kubectl cluster-info

Observe os resultados e responda:

  1. Quais componentes críticos do Control Plane aparecem no status?
  2. O que o comando kubectl cluster-info mostra sobre o ambiente?
  3. Qual seria o impacto se o etcd ficasse indisponível?

Gabarito

Comandos esperados:

kubectl get componentstatus
kubectl cluster-info

Saída esperada (exemplo simplificado):

NAME                 STATUS    MESSAGE             ERROR
scheduler            Healthy   ok
controller-manager   Healthy   ok
etcd-0               Healthy   {"health":"true"}

Kubernetes control plane is running at https://127.0.0.1:6443
CoreDNS is running at https://127.0.0.1:6443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy

Respostas:

  • Os principais componentes visíveis são scheduler, controller-manager e etcd (parte do Control Plane).
  • O kubectl cluster-info exibe informações sobre o API Server e os serviços de DNS do cluster.
  • Se o etcd parar, o cluster perde a “memória” do estado desejado e estado atual, impossibilitando gerenciar os recursos.

📌 Conclusão: esses comandos permitem verificar rapidamente se o Control Plane está saudável.


🌐 Objetos do Kubernetes

🔹 Pod (definição básica)

  • É a menor unidade executável no Kubernetes.
  • Representa um ou mais containers que compartilham:
    • Rede (mesmo IP e portas).
    • Armazenamento (mesmos volumes).

Exemplo típico:

  • Container 1: aplicação Node.js.
  • Container 2: sidecar para logging ou proxy.

Características:

  • Pods são efêmeros: podem ser destruídos e recriados a qualquer momento.
  • Por isso, não devemos tratá-los como servidores fixos, mas como instâncias transitórias.
  • Não criamos Pods diretamente em produção, e sim via controllers como Deployment.

🔹 ReplicaSet

  • Objeto que garante que um número específico de réplicas de um Pod esteja sempre em execução.

Funções principais:

  • Substituir Pods que falham.
  • Escalar horizontalmente (aumentar/diminuir réplicas).

Exemplo: se definimos replicas: 3 no ReplicaSet, sempre haverá 3 instâncias ativas do Pod.

  • Atualmente, o ReplicaSet é geralmente gerenciado indiretamente por um Deployment.

🔹 Deployment

  • É o objeto mais usado no Kubernetes para aplicações stateless.
  • Abstrai e gerencia ReplicaSets e Pods.

Funcionalidades principais:

  • Declarar o estado desejado (ex.: 5 réplicas de um Pod).
  • Criar e atualizar réplicas.
  • Realizar rolling updates (atualizações sem downtime).
  • Suporte a rollbacks (reverter para versão anterior).

Exemplo:

kubectl apply -f deployment.yaml

O Kubernetes cria Pods, garante o número de réplicas e cuida das atualizações.


🔹 Service

  • Objeto responsável por expor os Pods de maneira estável na rede.
  • Como os Pods são efêmeros e seus IPs mudam, o Service fornece um endereço fixo.

Tipos principais:

  • ClusterIP (padrão): acessível apenas dentro do cluster.
  • NodePort: expõe o Service em uma porta específica de cada nó (http://node-ip:30000).
  • LoadBalancer: integra com provedores de nuvem para fornecer IP público e balanceamento de carga.

Exemplo:
Um Deployment de Nginx com 3 réplicas pode ser exposto por um Service NodePort em
http://localhost:30080.


🔹 ConfigMap e Secret

  • ConfigMap: armazena configurações não sensíveis (strings, variáveis de ambiente, arquivos de config).
  • Secret: armazena informações sensíveis (senhas, tokens, certificados).
  • Usados para separar código de configuração.

Exemplos de uso:

  • ConfigMap: URL do banco de dados, nome da aplicação.
  • Secret: senha do banco, chave de API, certificado TLS.

🛡️ Boas práticas: Nunca embutir segredos diretamente no Pod ou Deployment.
Sempre usar Secret.


🔹 Volumes e PersistentVolumeClaim (PVC)

  • Containers e Pods são efêmeros: se caírem, os dados desaparecem.
  • Volumes permitem associar armazenamento aos Pods.

Tipos de Volumes:

  • emptyDir: criado junto com o Pod, descartado ao morrer.
  • hostPath: usa diretório da máquina host.
  • PersistentVolume (PV) e PersistentVolumeClaim (PVC):
    • Armazenamento persistente, independente do ciclo de vida do Pod.

Exemplo:
Um banco de dados rodando no Kubernetes precisa de um PVC para garantir que os dados não sejam perdidos em reinícios.


🔹 Ingress

  • Objeto responsável por roteamento HTTP/HTTPS avançado.

Funcionalidades principais:

  • Roteamento baseado em hostnames ou paths (ex.: /api → backend, /app → frontend).
  • Terminação TLS/HTTPS (certificados).
  • Regras centralizadas de entrada para múltiplos Services.
  • Requer um Ingress Controller (como NGINX, Traefik, HAProxy).

Exemplo:

  • https://app.minhaempresa.com → encaminha tráfego para o Service frontend.
  • https://api.minhaempresa.com → encaminha tráfego para o Service backend.

📊 Resumo

Objeto Função
Pod Unidade mínima (containers agrupados).
ReplicaSet Garante número fixo de réplicas de Pods.
Deployment Gerencia Pods/ReplicaSets com atualizações automáticas.
Service Expõe Pods de forma estável (rede).
ConfigMap/Secret Gerenciamento de configuração e credenciais.
Volumes/PVC Armazenamento persistente.
Ingress Roteamento HTTP/HTTPS externo para múltiplos Services.

☸️ Kubernetes — Atividades com Deployments, Services, ConfigMaps e Secrets

🔹 Atividade Básica

Enunciado

Crie um Deployment chamado nginx-deployment no namespace default.

  • Ele deve ter 2 réplicas de Pods usando a imagem nginx:latest.
  • Exponha esse Deployment usando um Service do tipo ClusterIP na porta 80.

Verifique:

  1. Quantos Pods foram criados?
  2. O Service tem um ClusterIP fixo?
  3. Se um Pod for deletado manualmente, o que acontece?

Gabarito

Criar Deployment:

kubectl create deployment nginx-deployment   --image=nginx:latest --replicas=2

Expor Deployment com Service ClusterIP:

kubectl expose deployment nginx-deployment   --type=ClusterIP --port=80 --target-port=80

Verificar recursos criados:

kubectl get deployments
kubectl get pods
kubectl get svc

Respostas:

  • Foram criados 2 Pods pelo Deployment.
  • O Service possui um ClusterIP interno e estável dentro do cluster.
  • Se um Pod for deletado manualmente, o Deployment cria outro automaticamente → self-healing via ReplicaSet.

📌 Conclusão: Deployment + Service garantem escalabilidade e disponibilidade.


🔹 Atividade Intermediária

Enunciado

  1. Crie um ConfigMap chamado app-config com a variável:
    APP_MODE=production

  2. Crie um Secret chamado db-secret com a chave:
    DB_PASSWORD=kubepass123

  3. Crie um Pod chamado app-pod que:

    • Usa a imagem busybox.
    • Exporta as variáveis de ambiente a partir do ConfigMap e do Secret.
    • Executa o comando env para exibir as variáveis.

Responda:

  1. Qual a diferença entre ConfigMap e Secret?
  2. Por que não é recomendável armazenar credenciais em ConfigMaps?

Gabarito

Criar ConfigMap:

kubectl create configmap app-config --from-literal=APP_MODE=production

Criar Secret:

kubectl create secret generic db-secret --from-literal=DB_PASSWORD=kubepass123

Pod YAML (app-pod.yaml):

apiVersion: v1
kind: Pod
metadata:
  name: app-pod
spec:
  containers:
    - name: app
      image: busybox
      command: ["sh", "-c", "env && sleep 3600"]
      env:
        - name: APP_MODE
          valueFrom:
            configMapKeyRef:
              name: app-config
              key: APP_MODE
        - name: DB_PASSWORD
          valueFrom:
            secretKeyRef:
              name: db-secret
              key: DB_PASSWORD

Aplicar Pod:

kubectl apply -f app-pod.yaml

Verificar variáveis:

kubectl logs app-pod

Respostas:

  • ConfigMap: guarda configurações não sensíveis (ex.: URLs, modos de execução).
  • Secret: armazena dados sensíveis (senhas, tokens, certificados).
  • Não é recomendável usar ConfigMap para credenciais porque ele não oferece proteção extra (apenas texto puro), enquanto Secrets podem ser criptografados em repouso no cluster.

📌 Conclusão: ConfigMap e Secret ajudam a separar código de configuração, mas cada um tem um uso específico.


Ciclo de Vida de uma Aplicação no Kubernetes


🔹 1. Criar um Pod

O Pod é a menor unidade executável no Kubernetes.
Nele definimos o container (imagem, portas, recursos).

Exemplo: subir um servidor Nginx em um Pod:

apiVersion: v1
kind: Pod
metadata:
  name: meu-pod
spec:
  containers:
    - name: nginx-container
      image: nginx:1.23
      ports:
        - containerPort: 80

📌 Esse Pod já roda a aplicação, mas não é suficiente para produção (se ele cair, não se recupera).


🔹 2. Escalar com Deployment

O Deployment cria e gerencia múltiplas réplicas do Pod.
Garante alta disponibilidade e suporte a atualizações automáticas.

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

📌 Agora temos 3 réplicas do Pod rodando. Se uma falhar, o Kubernetes cria outra automaticamente.


🔹 3. Expor com Service

Os Pods são efêmeros e mudam de IP constantemente.
Um Service fornece um ponto fixo de acesso.

Podemos escolher o tipo: ClusterIP, NodePort, LoadBalancer.

apiVersion: v1
kind: Service
metadata:
  name: meu-service
spec:
  selector:
    app: nginx
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80
  type: NodePort

📌 Agora conseguimos acessar o Nginx externamente, via porta exposta no Node.


🔹 4. Atualizar versão (Rolling Update)

O Deployment permite atualizar a versão da imagem sem downtime.
Kubernetes substitui Pods antigos por novos, um por vez (rolling update).

spec:
  containers:
    - name: nginx-container
      image: nginx:1.25   # versão nova

📌 Se algo der errado, podemos usar rollback para voltar à versão anterior.


🔹 5. Persistir dados com Volumes

Containers e Pods são efêmeros: ao reiniciar, os dados se perdem.
Usamos PersistentVolume (PV) + PersistentVolumeClaim (PVC) para armazenamento persistente.

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: meu-pvc
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 1Gi
---
apiVersion: v1
kind: Pod
metadata:
  name: pod-com-volume
spec:
  containers:
    - name: app
      image: mysql:8
      volumeMounts:
        - mountPath: "/var/lib/mysql"
          name: dados
  volumes:
    - name: dados
      persistentVolumeClaim:
        claimName: meu-pvc

📌 Agora os dados do banco persistem mesmo que o Pod seja destruído.


🔹 6. Configurar variáveis de ambiente com ConfigMap/Secret

  • ConfigMap: armazena configs não sensíveis (ex.: URL de API).
  • Secret: armazena configs sensíveis (ex.: senha do banco).
apiVersion: v1
kind: ConfigMap
metadata:
  name: app-config
data:
  APP_ENV: "production"
  API_URL: "https://api.meuservico.com"
---
apiVersion: v1
kind: Secret
metadata:
  name: app-secret
type: Opaque
data:
  DB_PASSWORD: bXlzZW5oYTEyMw==   # base64
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: app-deployment
spec:
  replicas: 2
  template:
    spec:
      containers:
        - name: app
          image: minha-app:1.0
          env:
            - name: APP_ENV
              valueFrom:
                configMapKeyRef:
                  name: app-config
                  key: APP_ENV
            - name: DB_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: app-secret
                  key: DB_PASSWORD

📌 Assim separamos código da configuração, deixando a aplicação mais flexível e segura.


🔄 Resumindo o Ciclo

  1. Criamos o Pod.
  2. Escalamos com Deployment.
  3. Expomos com Service.
  4. Atualizamos com Rolling Update.
  5. Persistimos dados com Volumes/PVC.
  6. Configuramos com ConfigMap/Secret.

👉 Resultado: uma aplicação escalável, resiliente, segura e pronta para produção.

📘 Atividades – Ciclo de Vida de uma Aplicação no Kubernetes

🔹 Atividade Básica

Enunciado

Crie um Deployment chamado nginx-deploy com 2 réplicas da imagem nginx:1.23.

  • Exponha esse Deployment como um Service NodePort na porta 30080.
  • Realize um rolling update para atualizar a imagem do Nginx para 1.25.

Responda:

  1. O que acontece com os Pods durante o rolling update?
  2. Como verificar se a atualização foi concluída com sucesso?

Gabarito

Criar Deployment:

kubectl create deployment nginx-deploy   --image=nginx:1.23 --replicas=2

Expor como Service NodePort:

kubectl expose deployment nginx-deploy   --type=NodePort --port=80 --target-port=80   --name=nginx-service

Editar Deployment para rolling update:

kubectl set image deployment/nginx-deploy nginx=nginx:1.25

Verificar status:

kubectl rollout status deployment/nginx-deploy

Respostas:

  • Durante o rolling update, o Kubernetes cria Pods novos com a nova imagem e vai removendo os antigos gradualmente → sem downtime.
  • O comando kubectl rollout status mostra se a atualização foi concluída, e kubectl get pods confirma se os Pods usam a nova versão da imagem.

📌 Conclusão: Deployments + rolling updates permitem atualizar aplicações em produção sem interrupções.


🔹 Atividade Intermediária

Enunciado

  1. Crie um PersistentVolumeClaim (PVC) de 1Gi chamado meu-pvc.
  2. Crie um Deployment chamado app-deploy com 1 réplica usando a imagem nginx.
  3. Monte o PVC no diretório /usr/share/nginx/html.
  4. Monte também um ConfigMap chamado app-config contendo a chave:
    index.html = <h1>Aplicação rodando com PVC e ConfigMap!</h1>
    
    Esse arquivo deve substituir a página padrão do Nginx.

Responda:

  1. O que acontece se o Pod for destruído e recriado?
  2. Por que separar código (imagem) de configuração (ConfigMap)?

Gabarito

Criar PVC (pvc.yaml):

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: meu-pvc
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 1Gi
kubectl apply -f pvc.yaml

Criar ConfigMap:

kubectl create configmap app-config   --from-literal=index.html="<h1>Aplicação rodando com PVC e ConfigMap!</h1>"

Deployment (app-deploy.yaml):

apiVersion: apps/v1
kind: Deployment
metadata:
  name: app-deploy
spec:
  replicas: 1
  selector:
    matchLabels:
      app: minha-app
  template:
    metadata:
      labels:
        app: minha-app
    spec:
      containers:
        - name: nginx
          image: nginx
          volumeMounts:
            - name: dados
              mountPath: /usr/share/nginx/html
            - name: pagina
              mountPath: /usr/share/nginx/html/index.html
              subPath: index.html
      volumes:
        - name: dados
          persistentVolumeClaim:
            claimName: meu-pvc
        - name: pagina
          configMap:
            name: app-config
            items:
              - key: index.html
                path: index.html
kubectl apply -f app-deploy.yaml

Testar aplicação:

kubectl port-forward svc/app-deploy 8080:80
curl http://localhost:8080

Respostas:

  • O PVC garante que os dados persistem mesmo que o Pod seja destruído. Assim, o conteúdo não se perde.
  • Separar código da configuração permite flexibilidade (ex.: mudar mensagens, endpoints, variáveis) sem precisar reconstruir a imagem da aplicação.

📌 Conclusão: PVC + ConfigMap permitem aplicações resilientes, persistentes e configuráveis no Kubernetes.


Rede e Comunicação no Kubernetes


🔹 Conceito de Service Discovery

Problema:

  • Os Pods no Kubernetes são efêmeros (criados e destruídos dinamicamente).
  • Cada vez que um Pod é recriado, ele recebe um novo IP.
  • Isso inviabiliza depender de IPs fixos para comunicação.

Solução: Service Discovery

  • O Kubernetes implementa um mecanismo nativo de descoberta de serviços.
  • Quando criamos um Service, ele recebe um nome DNS estável dentro do cluster.
  • Qualquer Pod pode chamar outro usando esse nome, sem se preocupar com IPs que mudam.

📌 Exemplo:

  • Deployment com 3 Pods da aplicação backend.
  • Criamos um Service chamado backend-service.
  • Outro Pod pode acessar via http://backend-service:8080, independentemente de qual Pod atenda a requisição.

🔹 Balanceamento interno de tráfego entre réplicas

  • Quando um Service aponta para múltiplos Pods, ele também age como load balancer interno.
  • O tráfego é distribuído entre as réplicas, geralmente por Round Robin (cada Pod recebe parte das requisições).

Vantagens:

  • Escalabilidade: basta aumentar as réplicas no Deployment, o Service distribui automaticamente.
  • Resiliência: se um Pod falhar, o tráfego é redirecionado para os outros.

📌 Exemplo:

  • Temos 5 Pods de Nginx atrás de um Service ClusterIP.
  • Cada requisição feita para nginx-service é encaminhada para um Pod diferente.

🔹 Exposição externa com Ingress Controller

  • Service resolve comunicação interna, mas e para expor aplicações ao mundo externo?
    • NodePort: expõe via porta no nó (limitado, pouco prático).
    • LoadBalancer: integra com nuvens públicas (gera custo e depende do provedor).
    • Ingress: solução mais flexível e avançada.

Ingress é um recurso que define regras de roteamento HTTP/HTTPS.
Ele permite:

  • Roteamento baseado em hostname (api.minhaempresa.com → backend, app.minhaempresa.com → frontend).
  • Roteamento baseado em path (/api → backend, /app → frontend).
  • Terminação TLS (HTTPS com certificados).
  • Regras centralizadas em um único ponto.

➡️ Para funcionar, precisamos instalar um Ingress Controller (ex.: Nginx Ingress Controller, Traefik, HAProxy).

📌 Exemplo de regra Ingress:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: meu-ingress
spec:
  rules:
    - host: app.minhaempresa.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: frontend-service
                port:
                  number: 80
    - host: api.minhaempresa.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: backend-service
                port:
                  number: 8080

🔹 Integração com DNS (CoreDNS)

  • O Kubernetes integra nativamente com um serviço de DNS interno chamado CoreDNS.
  • Ele resolve os nomes de Services para IPs, permitindo que a comunicação seja feita por nomes estáveis.

Funcionamento:

  • Quando criamos um Service chamado backend no namespace prod, o CoreDNS gera um endereço como:
    backend.prod.svc.cluster.local

  • Esse DNS é resolvido automaticamente para o cluster IP do Service.

Benefícios:

  • Facilita comunicação interna entre aplicações.
  • Não há necessidade de descobrir IPs manualmente.
  • Garante portabilidade: workloads podem ser movidos entre clusters sem mudar a lógica de rede.

📌 Exemplo prático:
Um Pod no namespace prod pode acessar o backend com:

curl http://backend.prod.svc.cluster.local:8080

📊 Resumo da Rede no Kubernetes

  • Service Discovery: permite encontrar serviços por nome, sem depender de IPs.
  • Balanceamento interno: distribui tráfego entre réplicas de Pods automaticamente.
  • Ingress Controller: expõe aplicações externamente com regras HTTP/HTTPS.
  • CoreDNS: resolve nomes de serviços para IPs internos no cluster.

📘 Atividades – Rede e Comunicação no Kubernetes

🔹 Atividade Básica

Enunciado

Crie dois Deployments:

  • frontend-deploy com a imagem nginx, 1 réplica.
  • backend-deploy com a imagem hashicorp/http-echo que responde "Hello Backend".

Exponha os dois Deployments como Services ClusterIP (frontend-svc e backend-svc).

Entre no Pod do frontend e faça uma chamada HTTP para o backend usando o nome do Service (backend-svc).

Responda:

  1. Como o frontend consegue resolver o nome backend-svc sem conhecer o IP?
  2. O que aconteceria se o Pod do backend fosse recriado com outro IP?

Gabarito

Criar frontend:

kubectl create deployment frontend-deploy --image=nginx
kubectl expose deployment frontend-deploy --port=80 --name=frontend-svc

Criar backend (responde via http-echo):

kubectl create deployment backend-deploy   --image=hashicorp/http-echo --   -text="Hello Backend"

kubectl expose deployment backend-deploy --port=5678 --name=backend-svc

Entrar no Pod frontend e testar comunicação:

kubectl exec -it $(kubectl get pod -l app=frontend-deploy -o jsonpath='{.items[0].metadata.name}') -- sh

# Dentro do Pod
apt update && apt install -y curl   # se necessário
curl http://backend-svc:5678

Respostas:

  • O Kubernetes usa o CoreDNS, que converte automaticamente o nome do Service (backend-svc) em seu ClusterIP.
  • Mesmo que o Pod do backend seja recriado com outro IP, o Service continua válido, pois atua como uma camada estável de abstração.

📌 Conclusão: o Service Discovery via DNS garante comunicação confiável entre Pods.


🔹 Atividade Intermediária

Enunciado

  1. Instale o Ingress Controller NGINX no cluster.
  2. Crie dois Deployments e Services:
    • app-deploy exposto como app-svc (porta 80).
    • api-deploy exposto como api-svc (porta 80).
  3. Configure um Ingress para:
    • Roteamento de requisições /appapp-svc.
    • Roteamento de requisições /apiapi-svc.
  4. Teste acessando os endpoints.

Responda:

  1. O que o Ingress resolve que um Service NodePort não resolve?
  2. Por que ele é importante em produção?

Gabarito

Instalar NGINX Ingress Controller (Helm, minikube ou manifestos):

kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/main/deploy/static/provider/cloud/deploy.yaml

Criar app e api:

kubectl create deployment app-deploy --image=nginx
kubectl expose deployment app-deploy --port=80 --name=app-svc

kubectl create deployment api-deploy --image=hashicorp/http-echo -- --text="Hello API"
kubectl expose deployment api-deploy --port=5678 --target-port=5678 --name=api-svc

Ingress YAML (meu-ingress.yaml):

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: meu-ingress
spec:
  rules:
    - http:
        paths:
          - path: /app
            pathType: Prefix
            backend:
              service:
                name: app-svc
                port:
                  number: 80
          - path: /api
            pathType: Prefix
            backend:
              service:
                name: api-svc
                port:
                  number: 5678
kubectl apply -f meu-ingress.yaml

Testar Ingress (minikube):

minikube tunnel &
curl http://localhost/app
curl http://localhost/api

Respostas:

  • O Ingress permite um único ponto de entrada HTTP/HTTPS, com roteamento inteligente por path/host. Já o NodePort expõe apenas portas estáticas.
  • Em produção, o Ingress é fundamental porque permite balanceamento, TLS/HTTPS, roteamento avançado e integração com domínios reais.

📌 Conclusão: o Ingress Controller é a porta de entrada oficial para aplicações web no Kubernetes.


Escalabilidade e Resiliência no Kubernetes


🔹 Horizontal Pod Autoscaler (HPA)

O HPA (Horizontal Pod Autoscaler) é responsável por ajustar automaticamente o número de réplicas de um Deployment, ReplicaSet ou StatefulSet.

Ele toma decisões com base em métricas como:

  • Uso de CPU.
  • Uso de memória.
  • Métricas customizadas (ex.: fila de mensagens, requisições por segundo).

Como funciona:

  • O HPA monitora métricas em tempo real (via Metrics Server ou Prometheus).
  • Se a carga aumentar além do limite configurado, cria novas réplicas.
  • Se a carga cair, reduz o número de réplicas.

Exemplo (YAML):

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: hpa-exemplo
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: meu-deployment
  minReplicas: 2
  maxReplicas: 10
  metrics:
    - type: Resource
      resource:
        name: cpu
        target:
          type: Utilization
          averageUtilization: 70

📌 Nesse exemplo:

  • O HPA garante entre 2 e 10 réplicas.
  • Se o uso médio de CPU ultrapassar 70%, ele cria novos Pods.

🔹 Liveness Probe e Readiness Probe

No Kubernetes, as Probes são verificações automáticas para avaliar a saúde dos containers.

Liveness Probe

  • Verifica se o container ainda está vivo.
  • Se falhar, o Kubernetes mata o container e recria o Pod.
  • Útil para casos em que a aplicação trava ou entra em estado inconsistente.

Readiness Probe

  • Verifica se o container está pronto para receber tráfego.
  • Se falhar, o Pod não entra no balanceador de carga.
  • Evita que usuários recebam erros enquanto a aplicação inicializa.

Exemplo (YAML):

apiVersion: v1
kind: Pod
metadata:
  name: pod-com-probes
spec:
  containers:
    - name: app
      image: minha-app:1.0
      ports:
        - containerPort: 8080
      livenessProbe:
        httpGet:
          path: /healthz
          port: 8080
        initialDelaySeconds: 10
        periodSeconds: 5
      readinessProbe:
        httpGet:
          path: /ready
          port: 8080
        initialDelaySeconds: 5
        periodSeconds: 5

📌 Nesse exemplo:

  • O Liveness Probe checa /healthz → se falhar, o container é reiniciado.
  • O Readiness Probe checa /ready → só depois de passar, o Pod recebe tráfego.

🔹 Self-healing (Auto-recuperação)

O Kubernetes tem a capacidade de auto-recuperação.
Isso significa que, se um Pod ou nó falhar, ele automaticamente tenta corrigir o problema sem intervenção humana.

Mecanismos:

  • Se um Pod cai → o Controller recria outro baseado no Deployment/ReplicaSet.
  • Se um nó falha → os Pods daquele nó são reagendados em outros nós disponíveis.
  • Se um container trava → o Liveness Probe detecta e força um restart.

➡️ Resultado: a aplicação se mantém disponível mesmo diante de falhas inevitáveis em hardware, rede ou software.

📌 Exemplo real:

  • Um Deployment de 5 réplicas.
  • Se 2 Pods caírem, o Kubernetes imediatamente cria 2 novos em outros nós.
  • Para o usuário final, a aplicação continua disponível, pois o Service redireciona tráfego apenas para Pods saudáveis.

📊 Resumo

  • Horizontal Pod Autoscaler (HPA): garante escalabilidade automática com base em métricas.
  • Liveness Probe: reinicia containers não responsivos.
  • Readiness Probe: só libera tráfego para Pods prontos.
  • Self-healing: substitui Pods ou nós falhos automaticamente, garantindo resiliência.

📘 Atividades – Escalabilidade e Resiliência no Kubernetes

🔹 Atividade Básica

Enunciado

Crie um Deployment chamado app-deploy com 1 réplica da imagem nginx.

Adicione probes para verificar a saúde do container:

  • Liveness Probe: checar / na porta 80 a cada 10s.
  • Readiness Probe: checar / na porta 80 após 5s de delay.

Verifique:

  1. O que acontece se o container não responder ao Liveness Probe?
  2. O que acontece se falhar no Readiness Probe?

Gabarito

Deployment com probes (app-deploy.yaml):

apiVersion: apps/v1
kind: Deployment
metadata:
  name: app-deploy
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
        - name: nginx
          image: nginx
          ports:
            - containerPort: 80
          livenessProbe:
            httpGet:
              path: /
              port: 80
            initialDelaySeconds: 10
            periodSeconds: 10
          readinessProbe:
            httpGet:
              path: /
              port: 80
            initialDelaySeconds: 5
            periodSeconds: 5

Aplicar e verificar:

kubectl apply -f app-deploy.yaml
kubectl describe pod <nome-do-pod>

Respostas:

  • Se o Liveness Probe falhar, o Kubernetes mata e recria o container.
  • Se o Readiness Probe falhar, o Pod fica fora do Service (não recebe tráfego), mas não é destruído.

📌 Conclusão: Liveness = está vivo?, Readiness = está pronto?


🔹 Atividade Intermediária

Enunciado

  1. Crie um Deployment chamado api-deploy com 2 réplicas usando a imagem k8s.gcr.io/hpa-example.
  2. Exponha-o como um Service ClusterIP na porta 80.
  3. Configure um Horizontal Pod Autoscaler (HPA) que:
    • Mantenha entre 2 e 5 réplicas.
    • Escale quando o uso de CPU médio ultrapassar 50%.
  4. Gere carga de teste no serviço para forçar o autoscaling.

Responda:

  1. O que acontece com o número de Pods quando a carga aumenta?
  2. E quando a carga diminui?

Gabarito

Criar Deployment e Service:

kubectl create deployment api-deploy   --image=k8s.gcr.io/hpa-example --replicas=2

kubectl expose deployment api-deploy --port=80 --name=api-svc

Criar HPA:

kubectl autoscale deployment api-deploy   --cpu-percent=50 --min=2 --max=5

Gerar carga (testar com busybox):

kubectl run -i --tty load-generator --image=busybox --restart=Never -- /bin/sh

# Dentro do pod busybox:
while true; do wget -q -O- http://api-svc; done

Verificar HPA:

kubectl get hpa
kubectl get pods -w

Respostas:

  • Quando a carga aumenta e a CPU passa de 50%, o HPA cria novos Pods até o limite de 5.
  • Quando a carga diminui, o HPA reduz as réplicas de volta até o mínimo configurado (2).

📌 Conclusão: o HPA garante escalabilidade automática e o Kubernetes mantém resiliência com self-healing.


Prometheus + Grafana: Monitoramento no Kubernetes


🔹 Por que precisamos de monitoramento?

O Kubernetes é dinâmico e distribuído: Pods são criados, destruídos e movidos automaticamente.
Precisamos de visibilidade em tempo real sobre:

  • Estado do cluster (nodes, pods, serviços).
  • Uso de recursos (CPU, memória, disco, rede).
  • Métricas customizadas de aplicações.

➡️ Sem monitoramento → difícil detectar gargalos, incidentes e prever capacidade.
📌 Prometheus + Grafana se tornaram o padrão de fato para monitoramento cloud-native.


🔹 Prometheus: coleta e armazenamento de métricas

Prometheus é um sistema de monitoramento e alertas baseado em métricas numéricas.

Arquitetura principal:

  • Prometheus Server: coleta métricas via pull (/metrics).
  • Exporters: expõem métricas (ex.: node-exporter, kube-state-metrics).
  • Time-Series Database (TSDB): armazena métricas como séries temporais.
  • Alertmanager: dispara alertas (e-mail, Slack, PagerDuty).

Exemplo de métrica coletada:

http_requests_total{method="GET", handler="/api"} 1527
  • Nome: http_requests_total
  • Labels: method, handler
  • Valor: 1527 (requisições GET na rota /api)

Configuração básica de scrape:

scrape_configs:
  - job_name: 'kubernetes-pods'
    kubernetes_sd_configs:
      - role: pod
    relabel_configs:
      - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scrape]
        action: keep
        regex: true

📌 Assim o Prometheus descobre automaticamente Pods que expõem métricas via anotação.


🔹 Grafana: visualização e dashboards

Grafana é uma ferramenta de visualização e análise de métricas.
Permite criar dashboards dinâmicos a partir dos dados coletados pelo Prometheus (ou outras fontes).

Recursos principais:

  • Gráficos interativos (linhas, barras, gauges, heatmaps).
  • Filtros por labels (namespace, app, node, status).
  • Alertas visuais integrados.
  • Templates de dashboards prontos (Kubernetes, Nginx, MySQL, etc.).

Exemplo de consulta em PromQL:

rate(container_cpu_usage_seconds_total{namespace="prod", pod=~"api.*"}[5m])

➡️ Calcula a taxa de uso de CPU para Pods que começam com api no namespace prod.


🔹 Fluxo Prometheus + Grafana no Kubernetes

  1. Aplicações e componentes expõem métricas via /metrics.
  2. Prometheus coleta periodicamente essas métricas.
  3. Alertmanager dispara alertas com base em condições definidas.
  4. Grafana consome os dados do Prometheus e mostra em dashboards interativos.

📊 Diagrama simplificado:

[Apps / Pods / Nodes] --> [Prometheus Server] --> [Grafana]
                                     |
                                [Alertmanager]

🔹 Ferramentas auxiliares no Kubernetes

  • kube-state-metrics: expõe métricas sobre o estado de objetos do Kubernetes.
  • node-exporter: expõe métricas de hardware e sistema operacional.
  • cAdvisor (kubelet): expõe métricas de containers.
  • Prometheus Operator: facilita deploy e gestão via CRDs.

🔹 Exemplo prático: Deployment com Prometheus + Grafana via Helm

Instalar o Prometheus com Helm:

helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
helm install prometheus prometheus-community/kube-prometheus-stack

➡️ Isso instala:

  • Prometheus
  • Grafana
  • kube-state-metrics
  • node-exporter

Acessar Grafana:

kubectl port-forward svc/prometheus-grafana 3000:80

Depois abra em: http://localhost:3000
Usuário: admin, senha obtida no Secret do Helm.


🔹 Boas práticas de monitoramento no Kubernetes

  • Alertas inteligentes: CPU/Memória alta, Pods em CrashLoopBackOff, falhas em Deployments.
  • Dashboards úteis: saúde do cluster, tráfego de rede, métricas de aplicações.
  • Retenção de métricas: cuidado com armazenamento (Prometheus consome muito disco).
  • Segurança: proteja a UI do Grafana com autenticação forte e, se possível, OIDC.

📊 Resumo

  • Prometheus: coleta, armazena e gera alertas.
  • Grafana: visualiza e analisa métricas.

No Kubernetes:

  • Prometheus coleta métricas de Pods, Nodes e Services.
  • Grafana mostra a saúde do cluster e aplicações.
  • Alertmanager notifica em caso de problemas.

👉 Resultado: observabilidade completa com métricas, alertas e dashboards.

📘 Atividades – Prometheus + Grafana: Monitoramento no Kubernetes

🔹 Atividade Básica

Enunciado

Instale o Prometheus + Grafana no cluster usando o Helm Chart kube-prometheus-stack.

Após a instalação, verifique:

  • Os Pods criados no namespace (prometheus, grafana, alertmanager, etc.).
  • O acesso ao Grafana via kubectl port-forward.
  • Faça login no Grafana (usuário admin, senha do Secret).

Responda:

  1. Quais dashboards prontos já estão disponíveis?
  2. Como acessar métricas coletadas do cluster (ex.: CPU/memória dos Pods)?

Gabarito

Adicionar repositório Helm e instalar:

helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
helm repo update

helm install monitor prometheus-community/kube-prometheus-stack -n monitoring --create-namespace

Verificar recursos criados:

kubectl get pods -n monitoring
kubectl get svc -n monitoring

Acessar Grafana:

kubectl port-forward svc/monitor-grafana -n monitoring 3000:80

Acessar em: http://localhost:3000

Obter senha do Grafana:

kubectl get secret monitor-grafana -n monitoring -o jsonpath="{.data.admin-password}" | base64 --decode

Respostas:

  • Dashboards prontos incluem Cluster Health, Nodes, Pods, Kubernetes API Server, etcd, etc.
  • As métricas do cluster podem ser acessadas no Prometheus (kubectl port-forward svc/monitor-kube-prometheus-prometheus 9090:9090) e visualizadas no Grafana em gráficos de uso de CPU, memória e rede por Pod/namespace.

📌 Conclusão: Prometheus coleta métricas e Grafana fornece dashboards de visualização poderosos.


🔹 Atividade Intermediária

Enunciado

  1. Crie um Deployment chamado app-metrics com a imagem nginx.
  2. Configure o Pod com uma anotação para que o Prometheus faça o scrape de métricas:
    prometheus.io/scrape: "true"
    prometheus.io/port: "80"
  3. No Grafana, crie um dashboard personalizado que exiba:
    • Número de requisições HTTP feitas ao app-metrics.
    • Consumo de CPU/memória desse Deployment.

Responda:

  1. Como o Prometheus descobre os Pods que precisam ser monitorados?
  2. Qual vantagem de ter dashboards customizados por aplicação?

Gabarito

Deployment com anotação (app-metrics.yaml):

apiVersion: apps/v1
kind: Deployment
metadata:
  name: app-metrics
  labels:
    app: app-metrics
spec:
  replicas: 1
  selector:
    matchLabels:
      app: app-metrics
  template:
    metadata:
      labels:
        app: app-metrics
      annotations:
        prometheus.io/scrape: "true"
        prometheus.io/port: "80"
    spec:
      containers:
        - name: nginx
          image: nginx
          ports:
            - containerPort: 80
kubectl apply -f app-metrics.yaml

Criar Dashboard no Grafana:

  • Ir em Dashboards → New → Import/Build Custom.
  • Criar gráficos com consultas PromQL, por exemplo:

CPU Usage:

rate(container_cpu_usage_seconds_total{pod=~"app-metrics.*"}[2m])

Memory Usage:

container_memory_usage_bytes{pod=~"app-metrics.*"}

Respostas:

  • O Prometheus usa service discovery e as anotações nos Pods/Services para saber quais endpoints /metrics deve coletar.
  • Dashboards customizados permitem que cada equipe acompanhe métricas específicas da sua aplicação (ex.: requisições HTTP, filas de mensagens), indo além da visão geral do cluster.

📌 Conclusão: com Prometheus + Grafana, é possível ter observabilidade completa, tanto do cluster quanto de aplicações específicas.


1. Reflexões e Boas Práticas


🔹 Comparação: Docker Compose vs Kubernetes

Aspecto Docker Compose 🐳 Kubernetes ☸️
Objetivo Orquestração simples em um host (local/dev) Orquestração distribuída em clusters
Escopo Desenvolvimento, prototipagem, testes locais Produção em escala, clusters distribuídos
Rede Rede interna simples entre containers Rede complexa, DNS interno, Ingress, Service Discovery
Escalabilidade Manual (alterar docker-compose.yml) Automática (HPA, escalonamento dinâmico)
Resiliência Se um container cair, precisa reiniciar manualmente Self-healing: recria Pods automaticamente
Atualizações Sem suporte nativo a rolling updates Rolling updates e rollbacks nativos
Complexidade Baixa (um arquivo, poucos comandos) Alta (diversos objetos, YAMLs, operadores)
Monitoramento Básico, com ferramentas externas Integrado com Prometheus/Grafana, probes, métricas
Uso típico Times pequenos, POCs, dev local Produção em larga escala, microserviços, cloud-native

📌 Resumo:

  • Docker Compose → ótimo para desenvolvimento local e projetos pequenos.
  • Kubernetes → essencial para ambientes distribuídos, resilientes e escaláveis.

🔹 Quando usar Kubernetes (e quando não)

Quando faz sentido usar Kubernetes

  • Múltiplos serviços que precisam de escalabilidade horizontal.
  • Necessidade de alta disponibilidade.
  • Ambientes multi-cloud ou híbridos.
  • Times com expertise em DevOps/SRE.
  • Casos de microserviços com dependências complexas.
  • Necessidade de observabilidade integrada.

Quando não faz sentido usar Kubernetes

  • Projetos pequenos ou MVPs de rápida entrega.
  • Quando 1 servidor/VM é suficiente.
  • Times sem experiência em infraestrutura.
  • Situações onde simplicidade > escalabilidade.
  • Casos onde serverless resolve melhor (ex.: AWS Lambda).

📌 Muitas startups começam com Docker Compose + serviços gerenciados e só migram para Kubernetes quando a complexidade aumenta.


🔹 Complexidade x Benefício em diferentes ambientes

Ambientes pequenos (startup, POC, times reduzidos):

  • Kubernetes pode ser overkill.
  • Curva de aprendizado alta.
  • Alternativas: Docker Compose, Swarm, PaaS (Heroku, Render, Fly.io).

Ambientes médios:

  • Kubernetes começa a fazer sentido com resiliência e automação.
  • Clusters menores em nuvem podem equilibrar complexidade x benefício.

Ambientes grandes (enterprise, SaaS em escala):

  • Kubernetes é praticamente indispensável.
  • Oferece autoescala, tolerância a falhas, observabilidade, multi-tenant.
  • Benefícios superam a complexidade.

📌 Equação mental:

  • Menos de 3 serviços, poucas réplicas, tráfego baixo → Docker Compose é suficiente.
  • Muitos serviços, equipes grandes, SLA alto → Kubernetes é o padrão.

🔹 Kubernetes como padrão de fato para cloud-native

  • Tornou-se o padrão da indústria para aplicações cloud-native.
  • Suportado nativamente por todos os principais provedores de nuvem: EKS, GKE, AKS.
  • Fator chave: portabilidade → mesma aplicação roda em qualquer cluster.

Base para o ecossistema CNCF:

  • Service Mesh: Istio, Linkerd.
  • Observabilidade: Prometheus, Grafana, Loki, Jaeger.
  • CI/CD cloud-native: ArgoCD, Tekton.
  • Segurança: OPA, Kyverno, Falco.

📌 Em 2025, Kubernetes é considerado commodity: tão essencial quanto Linux ou redes para DevOps/SRE.


📊 Resumo final

  • Docker Compose vs Kubernetes: Compose é simples e prático; Kubernetes é poderoso, mas complexo.
  • Quando usar: Kubernetes brilha em sistemas distribuídos, mas é exagero para MVPs simples.
  • Complexidade vs benefício: quanto maior o sistema e equipe, maior o ganho do Kubernetes.
  • Padrão de fato: Kubernetes é a fundação da arquitetura cloud-native moderna.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment