Kubernetes do Zero ao Profissional: 100 Exemplos com kubectl, Manifestos, Helm e GitOps

Kubernetes do Zero ao Profissional: 100 Exemplos com kubectl, Manifestos, Helm e GitOps

O Kubernetes executa contêineres em um conjunto de máquinas chamado cluster. Ele reinicia contêineres que falham, distribui-os entre os nós, publica novas versões sem interromper o serviço e os escala conforme a carga. Este artigo leva você do primeiro Pod até uma configuração pensada para produção, em 100 exemplos. Você vai aprender o kubectl e os contextos, Pods, Deployments e atualizações graduais, Services e Ingress, ConfigMaps e Secrets, armazenamento persistente, Jobs e CronJobs, StatefulSets e DaemonSets, escalonamento automático, requests de recursos e sondas, agendamento, RBAC e segurança de Pods, Helm e Kustomize, observabilidade e depuração, além de GitOps e backups. Nota de transparência: nenhum cluster Kubernetes nem o kubectl estavam instalados no computador usado para preparar este artigo, então nenhum dos 100 exemplos foi executado aqui. Os manifestos seguem a API atual do Kubernetes, mas aplique cada um em um cluster de teste antes de confiar nele.

O que você precisa

Docker Desktop com o Kubernetes integrado, ou kind ou minikube para um cluster local de prática, além do kubectl e do Helm. Conhecimentos básicos de contêineres ajudam; o artigo de Docker desta série é um bom começo. Alguns exemplos usam um provedor de nuvem, como o Azure Kubernetes Service, e um controlador de ingress. Use nomes de host de exemplo como shop.example.com e senhas de exemplo como <strong-password>, e nunca cole credenciais reais em manifestos ou comandos.

Como usar um exemplo

Os exemplos em bash usam kubectl, Helm e Kustomize. Os exemplos em YAML são salvos em um arquivo .yaml e aplicados com kubectl apply -f, usando o nome de arquivo indicado no texto. Os exemplos em Python usam o cliente oficial do Kubernetes para Python.

Tópico 1: Primeiros passos com o Kubernetes

O Kubernetes é um laço de controle. Você descreve o estado desejado em YAML, e o cluster continua trabalhando até que a realidade corresponda à descrição. Conheça as partes de um cluster, o cliente kubectl, os contextos e os namespaces.

Plano de controle e nós

O plano de controle guarda o estado desejado e toma decisões, e os nós de trabalho executam seus contêineres. Você se comunica com o cluster pelo servidor de API, e o kubectl é o cliente padrão que envia suas requisições.

Contextos e namespaces

Um contexto guarda qual cluster, usuário e namespace os seus comandos usam. Verifique com kubectl config current-context antes de alterar qualquer coisa, para nunca remover recursos do cluster errado.

Manifestos e mudança declarativa

Um manifesto tem apiVersion, kind, metadata e spec. O kubectl apply compara o seu arquivo com o cluster e altera apenas o que difere, o que torna as mudanças repetíveis e fáceis de revisar no Git.

Ilustrações

Como uma requisição chega a uma aplicação no Kubernetes: o usuário acessa um Ingress, o Ingress encaminha para um Service, e o Service envia o tráfego para Pods saudáveis que um Deployment mantém em execução
Como uma requisição chega a uma aplicação no Kubernetes: o usuário acessa um Ingress, o Ingress encaminha para um Service, e o Service envia o tráfego para Pods saudáveis que um Deployment mantém em execução

Exemplo 1: Verificar o cliente e o cluster

Confirme que o kubectl consegue falar com o cluster.

kubectl version --client
kubectl cluster-info
kubectl get nodes -o wide

*Este exemplo não foi executado aqui, porque nenhum cluster Kubernetes nem o kubectl estavam instalados no computador que preparou este artigo.*

Exemplo 2: Criar um cluster de prática com kind

Um cluster local no seu computador para aprender.

kind create cluster --name learn
kubectl config current-context
kubectl get nodes

*Este exemplo não foi executado aqui, porque nenhum cluster Kubernetes nem o kubectl estavam instalados no computador que preparou este artigo.*

Exemplo 3: Trocar de contexto

Escolha em qual cluster os comandos atuam.

kubectl config get-contexts
kubectl config use-context kind-learn
kubectl config view --minify --output "jsonpath={.current-context}"

*Este exemplo não foi executado aqui, porque nenhum cluster Kubernetes nem o kubectl estavam instalados no computador que preparou este artigo.*

Exemplo 4: Criar um namespace

Separe equipes e aplicações dentro de um único cluster.

kubectl create namespace shop
kubectl config set-context --current --namespace=shop
kubectl get pods

*Este exemplo não foi executado aqui, porque nenhum cluster Kubernetes nem o kubectl estavam instalados no computador que preparou este artigo.*

Exemplo 5: Ler um manifesto

Os quatro campos de nível superior de todo objeto.

apiVersion: v1
kind: Namespace
metadata:
  name: shop
  labels:
    team: platform

*Este exemplo não foi executado aqui, porque nenhum cluster Kubernetes nem o kubectl estavam instalados no computador que preparou este artigo.*

Exemplo 6: Aplicar um manifesto

Faça mudanças declarativas com kubectl apply.

kubectl apply -f namespace.yaml
kubectl get namespace shop --show-labels
kubectl describe namespace shop

*Este exemplo não foi executado aqui, porque nenhum cluster Kubernetes nem o kubectl estavam instalados no computador que preparou este artigo.*

Tópico 2: Pods: a menor unidade

Um Pod é um ou mais contêineres que compartilham endereço de rede e armazenamento. A maioria dos Pods executa um contêiner, mas um Pod também pode conter auxiliares que precisam rodar ao lado da aplicação principal.

O que é um Pod

Todos os contêineres de um Pod compartilham o mesmo endereço IP e se comunicam pelo localhost. Os Pods são temporários: quando um morre, o cluster cria outro com novo nome e novo endereço, por isso não dependa do endereço de um Pod.

Contêineres init e sidecar

Os contêineres init rodam até terminar antes de os contêineres principais iniciarem, o que é útil para esperar um banco de dados. Os contêineres sidecar rodam ao lado do principal para registrar logs, fazer proxy ou sincronizar arquivos, e compartilham seus volumes.

Logs, eventos e exec

O kubectl logs mostra a saída, o kubectl describe mostra eventos como erros ao baixar a imagem e falhas de agendamento, e o kubectl exec abre um shell. Leia primeiro o describe, porque ele explica a maioria das falhas na inicialização.

Exemplo 7: Executar um Pod rapidamente

Um comando imperativo, apenas para testes rápidos.

kubectl run hello --image=nginx:1.27 --port=80
kubectl get pod hello -o wide

*Este exemplo não foi executado aqui, porque nenhum cluster Kubernetes nem o kubectl estavam instalados no computador que preparou este artigo.*

Exemplo 8: Um Pod declarativo

A menor unidade que você implanta.

apiVersion: v1
kind: Pod
metadata:
  name: web
  labels:
    app: web
spec:
  containers:
    - name: web
      image: nginx:1.27
      ports:
        - containerPort: 80

*Este exemplo não foi executado aqui, porque nenhum cluster Kubernetes nem o kubectl estavam instalados no computador que preparou este artigo.*

Exemplo 9: Ler logs e eventos

Descubra o que aconteceu com um Pod.

kubectl logs web
kubectl logs web --previous
kubectl get events --sort-by=.lastTimestamp

*Este exemplo não foi executado aqui, porque nenhum cluster Kubernetes nem o kubectl estavam instalados no computador que preparou este artigo.*

Exemplo 10: Executar comandos dentro de um Pod

Depure por dentro.

kubectl exec -it web -- sh
kubectl exec web -- nginx -v

*Este exemplo não foi executado aqui, porque nenhum cluster Kubernetes nem o kubectl estavam instalados no computador que preparou este artigo.*

Exemplo 11: Port-forward para um Pod

Acesse um Pod pelo seu computador para testar.

kubectl port-forward pod/web 8080:80
curl http://localhost:8080

*Este exemplo não foi executado aqui, porque nenhum cluster Kubernetes nem o kubectl estavam instalados no computador que preparou este artigo.*

Exemplo 12: Dois contêineres compartilham um volume

O padrão sidecar.

apiVersion: v1
kind: Pod
metadata:
  name: sidecar-demo
spec:
  volumes:
    - name: logs
      emptyDir: {}
  containers:
    - name: app
      image: busybox:1.36
      command: ["sh", "-c", "while true; do date >> /logs/app.log; sleep 5; done"]
      volumeMounts:
        - name: logs
          mountPath: /logs
    - name: log-reader
      image: busybox:1.36
      command: ["sh", "-c", "tail -F /logs/app.log"]
      volumeMounts:
        - name: logs
          mountPath: /logs

*Este exemplo não foi executado aqui, porque nenhum cluster Kubernetes nem o kubectl estavam instalados no computador que preparou este artigo.*

Exemplo 13: Um contêiner init espera

Execute etapas de preparação antes de a aplicação iniciar.

apiVersion: v1
kind: Pod
metadata:
  name: init-demo
spec:
  initContainers:
    - name: wait-for-db
      image: busybox:1.36
      command: ["sh", "-c", "until nslookup db; do sleep 2; done"]
  containers:
    - name: app
      image: nginx:1.27

*Este exemplo não foi executado aqui, porque nenhum cluster Kubernetes nem o kubectl estavam instalados no computador que preparou este artigo.*

Exemplo 14: Excluir Pods de teste

Limpe os objetos que não são mais necessários.

kubectl delete pod hello web sidecar-demo init-demo --ignore-not-found
kubectl get pods

*Este exemplo não foi executado aqui, porque nenhum cluster Kubernetes nem o kubectl estavam instalados no computador que preparou este artigo.*

Tópico 3: Deployments e atualizações graduais

Você raramente cria Pods diretamente. Um Deployment gerencia um ReplicaSet, que mantém o número solicitado de Pods em execução, e faz atualizações graduais para que as novas versões substituam as antigas aos poucos.

Réplicas e seletores

O campo replicas define quantos Pods você quer. O seletor precisa corresponder aos rótulos dos Pods, para que o Deployment saiba quais Pods lhe pertencem. Uma divergência é rejeitada na criação.

Estratégia de atualização gradual

maxSurge define quantos Pods extras podem existir durante a atualização, e maxUnavailable define quantos podem faltar. Definir maxUnavailable como 0 mantém a capacidade total durante a publicação.

Histórico de rollout e rollback

Cada mudança cria um novo ReplicaSet e um número de revisão. O kubectl rollout undo volta para a versão anterior, e o kubectl rollout history lista as revisões para que você escolha uma específica.

Exemplo 15: Um Deployment mantém réplicas em execução

Atualizações graduais gerenciadas para você.

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

*Este exemplo não foi executado aqui, porque nenhum cluster Kubernetes nem o kubectl estavam instalados no computador que preparou este artigo.*

Exemplo 16: Criar e acompanhar um Deployment

Verifique o status do rollout.

kubectl apply -f deployment.yaml
kubectl rollout status deployment/web
kubectl get deploy,rs,pods -l app=web

*Este exemplo não foi executado aqui, porque nenhum cluster Kubernetes nem o kubectl estavam instalados no computador que preparou este artigo.*

Exemplo 17: Escalar manualmente

Altere o número de réplicas.

kubectl scale deployment web --replicas=5
kubectl get pods -l app=web -o wide

*Este exemplo não foi executado aqui, porque nenhum cluster Kubernetes nem o kubectl estavam instalados no computador que preparou este artigo.*

Exemplo 18: Lançar uma nova imagem

Atualize a versão da aplicação.

kubectl set image deployment/web web=nginx:1.27.2
kubectl rollout status deployment/web
kubectl rollout history deployment/web

*Este exemplo não foi executado aqui, porque nenhum cluster Kubernetes nem o kubectl estavam instalados no computador que preparou este artigo.*

Exemplo 19: Reverter um lançamento ruim

Desfaça um rollout que deu errado.

kubectl rollout undo deployment/web
kubectl rollout undo deployment/web --to-revision=1

*Este exemplo não foi executado aqui, porque nenhum cluster Kubernetes nem o kubectl estavam instalados no computador que preparou este artigo.*

Exemplo 20: Controlar a atualização gradual

maxSurge e maxUnavailable.

spec:
  replicas: 4
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 0

*Este exemplo não foi executado aqui, porque nenhum cluster Kubernetes nem o kubectl estavam instalados no computador que preparou este artigo.*

Exemplo 21: Pausar e retomar um rollout

Agrupe várias mudanças juntas.

kubectl rollout pause deployment/web
kubectl set resources deployment/web -c web --limits=memory=256Mi
kubectl rollout resume deployment/web

*Este exemplo não foi executado aqui, porque nenhum cluster Kubernetes nem o kubectl estavam instalados no computador que preparou este artigo.*

Exemplo 22: Uma sonda de prontidão

O tráfego espera até a aplicação estar pronta.

containers:
  - name: web
    image: nginx:1.27
    readinessProbe:
      httpGet:
        path: /
        port: 80
      initialDelaySeconds: 3
      periodSeconds: 5

*Este exemplo não foi executado aqui, porque nenhum cluster Kubernetes nem o kubectl estavam instalados no computador que preparou este artigo.*

Tópico 4: Services e redes

Os Pods surgem e desaparecem, então os clientes precisam de um nome e um endereço estáveis. Um Service seleciona Pods por rótulo e lhes dá um IP virtual e um nome DNS que não muda.

Tipos de Service

O ClusterIP só é acessível dentro do cluster. O NodePort abre uma porta em cada nó. O LoadBalancer pede ao provedor de nuvem um balanceador de carga externo. Escolha o tipo mais simples que atenda à necessidade.

DNS e endpoints

Cada Service recebe um nome DNS como web-svc.shop.svc.cluster.local, e dentro do mesmo namespace o nome curto funciona. O kubectl get endpoints mostra os endereços dos Pods por trás do Service, e é a primeira coisa a verificar quando um Service não responde.

Services headless

Com clusterIP definido como None, o DNS devolve os endereços dos Pods individuais em vez de um IP virtual. Bancos de dados e sistemas em cluster usam isso para que os clientes conversem com membros específicos.

Exemplo 23: Um Service ClusterIP

Um endereço estável dentro do cluster.

apiVersion: v1
kind: Service
metadata:
  name: web
spec:
  type: ClusterIP
  selector:
    app: web
  ports:
    - port: 80
      targetPort: 80

*Este exemplo não foi executado aqui, porque nenhum cluster Kubernetes nem o kubectl estavam instalados no computador que preparou este artigo.*

Exemplo 24: Expor com kubectl

Um jeito rápido de criar um Service.

kubectl expose deployment web --port=80 --target-port=80 --name=web-svc
kubectl get svc web-svc
kubectl get endpoints web-svc

*Este exemplo não foi executado aqui, porque nenhum cluster Kubernetes nem o kubectl estavam instalados no computador que preparou este artigo.*

Exemplo 25: Chamar um Service a partir de um Pod temporário

Teste o DNS dentro do cluster.

kubectl run tmp-client --rm -it --image=busybox:1.36 --restart=Never -- wget -qO- http://web-svc

*Este exemplo não foi executado aqui, porque nenhum cluster Kubernetes nem o kubectl estavam instalados no computador que preparou este artigo.*

Exemplo 26: Um Service NodePort

Abre uma porta em cada nó.

apiVersion: v1
kind: Service
metadata:
  name: web-nodeport
spec:
  type: NodePort
  selector:
    app: web
  ports:
    - port: 80
      targetPort: 80
      nodePort: 30080

*Este exemplo não foi executado aqui, porque nenhum cluster Kubernetes nem o kubectl estavam instalados no computador que preparou este artigo.*

Exemplo 27: Um Service LoadBalancer

Um balanceador de carga da nuvem para acesso público.

apiVersion: v1
kind: Service
metadata:
  name: web-public
  annotations:
    service.beta.kubernetes.io/azure-load-balancer-internal: "false"
spec:
  type: LoadBalancer
  selector:
    app: web
  ports:
    - port: 80
      targetPort: 80

*Este exemplo não foi executado aqui, porque nenhum cluster Kubernetes nem o kubectl estavam instalados no computador que preparou este artigo.*

Exemplo 28: Encontrar o endereço externo

Leia o endereço atribuído pela nuvem.

kubectl get svc web-public -o jsonpath="{.status.loadBalancer.ingress[0].ip}"
kubectl get svc web-public -w

*Este exemplo não foi executado aqui, porque nenhum cluster Kubernetes nem o kubectl estavam instalados no computador que preparou este artigo.*

Exemplo 29: Uma porta nomeada

Use nomes de porta para trocar números com segurança.

apiVersion: v1
kind: Service
metadata:
  name: api
spec:
  selector:
    app: api
  ports:
    - name: http
      port: 8000
      targetPort: http

*Este exemplo não foi executado aqui, porque nenhum cluster Kubernetes nem o kubectl estavam instalados no computador que preparou este artigo.*

Exemplo 30: Um Service headless

Obtenha os endereços de cada Pod.

apiVersion: v1
kind: Service
metadata:
  name: db-headless
spec:
  clusterIP: None
  selector:
    app: db
  ports:
    - port: 5432

*Este exemplo não foi executado aqui, porque nenhum cluster Kubernetes nem o kubectl estavam instalados no computador que preparou este artigo.*

Tópico 5: Configuração com ConfigMaps e Secrets

Mantenha a configuração fora da imagem. Os ConfigMaps guardam configurações comuns, e os Secrets guardam valores sensíveis. Ambos podem virar variáveis de ambiente ou arquivos dentro do Pod, então você altera configurações sem reconstruir a imagem.

ConfigMaps

Um ConfigMap guarda pares chave-valor ou arquivos inteiros. Use envFrom para carregar cada chave como variável de ambiente, ou monte o ConfigMap como diretório quando a aplicação lê um arquivo.

Secrets

Um Secret guarda valores codificados em base64. Base64 é codificação, não criptografia. Por isso, ative a criptografia em repouso no cluster, limite quem lê Secrets com RBAC e monte-os como arquivos sempre que possível.

Recarregando alterações

As variáveis de ambiente são lidas apenas na inicialização, então um ConfigMap alterado exige um novo rollout. Arquivos montados são atualizados com atraso, mas a aplicação precisa lê-los novamente. Planeje o recarregamento sempre que mudar a configuração.

Exemplo 31: Um ConfigMap a partir de valores literais

Guarde configurações que não são secretas.

kubectl create configmap app-config --from-literal=LOG_LEVEL=info --from-literal=FEATURE_X=on
kubectl get configmap app-config -o yaml

*Este exemplo não foi executado aqui, porque nenhum cluster Kubernetes nem o kubectl estavam instalados no computador que preparou este artigo.*

Exemplo 32: Um manifesto de ConfigMap

Configurações escritas em YAML.

apiVersion: v1
kind: ConfigMap
metadata:
  name: app-config
data:
  LOG_LEVEL: info
  FEATURE_X: "on"

*Este exemplo não foi executado aqui, porque nenhum cluster Kubernetes nem o kubectl estavam instalados no computador que preparou este artigo.*

Exemplo 33: ConfigMap como variáveis de ambiente

Carregue todas as chaves com envFrom.

containers:
  - name: api
    image: sample-api:1.4.2
    envFrom:
      - configMapRef:
          name: app-config

*Este exemplo não foi executado aqui, porque nenhum cluster Kubernetes nem o kubectl estavam instalados no computador que preparou este artigo.*

Exemplo 34: Montar um ConfigMap como arquivos

Arquivos de configuração dentro do contêiner.

containers:
  - name: web
    image: nginx:1.27
    volumeMounts:
      - name: site-config
        mountPath: /etc/nginx/conf.d
        readOnly: true
volumes:
  - name: site-config
    configMap:
      name: nginx-conf

*Este exemplo não foi executado aqui, porque nenhum cluster Kubernetes nem o kubectl estavam instalados no computador que preparou este artigo.*

Exemplo 35: Criar um Secret

Guarde uma senha sem gravá-la em um arquivo.

kubectl create secret generic db-secret --from-literal=DB_PASSWORD='<strong-password>'
kubectl get secret db-secret -o jsonpath="{.type}"

*Este exemplo não foi executado aqui, porque nenhum cluster Kubernetes nem o kubectl estavam instalados no computador que preparou este artigo.*

Exemplo 36: Um manifesto de Secret

stringData permite escrever texto simples.

apiVersion: v1
kind: Secret
metadata:
  name: db-secret
type: Opaque
stringData:
  DB_PASSWORD: <strong-password>

*Este exemplo não foi executado aqui, porque nenhum cluster Kubernetes nem o kubectl estavam instalados no computador que preparou este artigo.*

Exemplo 37: Ler o valor de um Secret

Verifique o valor decodificado e mantenha-o em sigilo.

kubectl get secret db-secret -o jsonpath="{.data.DB_PASSWORD}" | base64 --decode; echo
# Do not print secrets in shared logs or screenshots.

*Este exemplo não foi executado aqui, porque nenhum cluster Kubernetes nem o kubectl estavam instalados no computador que preparou este artigo.*

Exemplo 38: Montar um Secret como arquivos

Arquivos de credenciais somente leitura.

containers:
  - name: api
    image: sample-api:1.4.2
    volumeMounts:
      - name: db-creds
        mountPath: /var/run/secrets/db
        readOnly: true
volumes:
  - name: db-creds
    secret:
      secretName: db-secret

*Este exemplo não foi executado aqui, porque nenhum cluster Kubernetes nem o kubectl estavam instalados no computador que preparou este artigo.*

Tópico 6: Armazenamento persistente

Os contêineres perdem seus arquivos ao reiniciar. Um PersistentVolumeClaim pede armazenamento que sobrevive ao Pod, e um StorageClass diz ao cluster como criar esse armazenamento.

PV, PVC e StorageClass

Um PersistentVolume é o armazenamento em si, um PersistentVolumeClaim é o pedido por ele, e um StorageClass define como os volumes são criados sob demanda. A maioria dos clusters oferece um StorageClass padrão, então o claim costuma precisar apenas do tamanho.

Modos de acesso

ReadWriteOnce monta o volume em um nó por vez, o que serve para a maioria dos bancos de dados. ReadWriteMany permite que vários nós gravem, mas só alguns tipos de armazenamento suportam isso. Escolha o modo que o seu armazenamento oferece.

Política de reclaim

Delete remove o armazenamento quando o claim é excluído, e Retain mantém os dados para recuperação manual. Use Retain para dados que precisam sobreviver a uma exclusão acidental, e faça backup dos dados importantes em qualquer caso.

Exemplo 39: Um PersistentVolumeClaim

Peça armazenamento ao cluster.

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: data-pvc
spec:
  accessModes: ["ReadWriteOnce"]
  resources:
    requests:
      storage: 1Gi

*Este exemplo não foi executado aqui, porque nenhum cluster Kubernetes nem o kubectl estavam instalados no computador que preparou este artigo.*

Exemplo 40: Um Pod que usa o claim

Os dados sobrevivem a reinícios do Pod.

apiVersion: v1
kind: Pod
metadata:
  name: writer
spec:
  containers:
    - name: writer
      image: busybox:1.36
      command: ["sh", "-c", "echo hello >> /data/out.txt; sleep 3600"]
      volumeMounts:
        - name: data
          mountPath: /data
  volumes:
    - name: data
      persistentVolumeClaim:
        claimName: data-pvc

*Este exemplo não foi executado aqui, porque nenhum cluster Kubernetes nem o kubectl estavam instalados no computador que preparou este artigo.*

Exemplo 41: Verificar o armazenamento vinculado

Leia o status do claim e do volume.

kubectl get pvc data-pvc
kubectl get pv
kubectl describe pvc data-pvc

*Este exemplo não foi executado aqui, porque nenhum cluster Kubernetes nem o kubectl estavam instalados no computador que preparou este artigo.*

Exemplo 42: Escolher uma StorageClass

Escolha o tipo de disco.

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: fast-pvc
spec:
  storageClassName: managed-premium
  accessModes: ["ReadWriteOnce"]
  resources:
    requests:
      storage: 10Gi

*Este exemplo não foi executado aqui, porque nenhum cluster Kubernetes nem o kubectl estavam instalados no computador que preparou este artigo.*

Exemplo 43: Listar StorageClasses

Encontre a classe padrão.

kubectl get storageclass
kubectl get storageclass -o custom-columns=NAME:.metadata.name,DEFAULT:.metadata.annotations."storageclass\.kubernetes\.io/is-default-class"

*Este exemplo não foi executado aqui, porque nenhum cluster Kubernetes nem o kubectl estavam instalados no computador que preparou este artigo.*

Exemplo 44: Expandir um claim

Aumente o armazenamento quando a classe permitir.

kubectl patch pvc data-pvc -p '{"spec":{"resources":{"requests":{"storage":"2Gi"}}}}'
kubectl get pvc data-pvc

*Este exemplo não foi executado aqui, porque nenhum cluster Kubernetes nem o kubectl estavam instalados no computador que preparou este artigo.*

Exemplo 45: Política de reclaim

Mantenha os dados depois que o claim for excluído.

apiVersion: v1
kind: PersistentVolume
metadata:
  name: archive-pv
spec:
  capacity:
    storage: 5Gi
  accessModes: ["ReadWriteOnce"]
  persistentVolumeReclaimPolicy: Retain
  hostPath:
    path: /srv/archive

*Este exemplo não foi executado aqui, porque nenhum cluster Kubernetes nem o kubectl estavam instalados no computador que preparou este artigo.*

Exemplo 46: Limitar o armazenamento efêmero

Interrompa arquivos temporários que crescem sem controle.

containers:
  - name: worker
    image: busybox:1.36
    resources:
      limits:
        ephemeral-storage: 1Gi

*Este exemplo não foi executado aqui, porque nenhum cluster Kubernetes nem o kubectl estavam instalados no computador que preparou este artigo.*

Tópico 7: Ingress e roteamento de tráfego

Um Ingress expõe rotas HTTP e HTTPS de fora do cluster para os Services. Ele roteia por nome de host e caminho, e termina o TLS, então um único endereço público pode atender várias aplicações.

Ingress e o controlador

Um recurso Ingress não faz nada sozinho. Um controlador de ingress, como o ingress-nginx, lê os objetos Ingress e configura o proxy. Instale um controlador por cluster e defina ingressClassName em cada Ingress.

Certificados TLS

A seção tls aponta para um Secret que contém o certificado e a chave. O cert-manager pode solicitar e renovar certificados automaticamente, então você não precisa acompanhar a validade manualmente.

Roteamento por caminho e host

As regras comparam nome de host e prefixo de caminho, e vence o caminho mais específico. Assim, /api pode ir para a API enquanto / vai para o site. Mantenha as rotas simples para que a tabela de roteamento seja fácil de revisar.

Exemplo 47: Ingress por nome de host

Roteamento HTTP para Services.

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: web-ingress
spec:
  ingressClassName: nginx
  rules:
    - host: shop.example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: web
                port:
                  number: 80

*Este exemplo não foi executado aqui, porque nenhum cluster Kubernetes nem o kubectl estavam instalados no computador que preparou este artigo.*

Exemplo 48: Ingress com TLS

HTTPS usando um certificado guardado em um Secret.

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: web-tls
spec:
  ingressClassName: nginx
  tls:
    - hosts: [shop.example.com]
      secretName: shop-tls
  rules:
    - host: shop.example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: web
                port:
                  number: 80

*Este exemplo não foi executado aqui, porque nenhum cluster Kubernetes nem o kubectl estavam instalados no computador que preparou este artigo.*

Exemplo 49: Instalar um ingress controller

Instale o controlador com o Helm.

helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm repo update
helm install ingress ingress-nginx/ingress-nginx --namespace ingress --create-namespace

*Este exemplo não foi executado aqui, porque nenhum cluster Kubernetes nem o kubectl estavam instalados no computador que preparou este artigo.*

Exemplo 50: Rotear pelo caminho

Envie /api e / para Services diferentes.

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: shop-routes
spec:
  ingressClassName: nginx
  rules:
    - host: shop.example.com
      http:
        paths:
          - path: /api
            pathType: Prefix
            backend:
              service:
                name: api
                port:
                  number: 8000
          - path: /
            pathType: Prefix
            backend:
              service:
                name: web
                port:
                  number: 80

*Este exemplo não foi executado aqui, porque nenhum cluster Kubernetes nem o kubectl estavam instalados no computador que preparou este artigo.*

Exemplo 51: Anotações de Ingress para uploads

Aumente o limite de tamanho de upload e o tempo limite de um site.

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: upload-ingress
  annotations:
    nginx.ingress.kubernetes.io/proxy-body-size: "20m"
    nginx.ingress.kubernetes.io/proxy-read-timeout: "60"
spec:
  ingressClassName: nginx
  rules:
    - host: upload.example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: uploader
                port:
                  number: 80

*Este exemplo não foi executado aqui, porque nenhum cluster Kubernetes nem o kubectl estavam instalados no computador que preparou este artigo.*

Exemplo 52: Um ClusterIssuer do cert-manager

Peça certificados ao Let's Encrypt automaticamente.

apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt-prod
spec:
  acme:
    server: https://acme-v02.api.letsencrypt.org/directory
    email: [email protected]
    privateKeySecretRef:
      name: letsencrypt-prod-key
    solvers:
      - http01:
          ingress:
            ingressClassName: nginx

*Este exemplo não foi executado aqui, porque nenhum cluster Kubernetes nem o kubectl estavam instalados no computador que preparou este artigo.*

Exemplo 53: Pedir um certificado pelo Ingress

Use uma anotação para o TLS ser gerenciado para você.

metadata:
  annotations:
    cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
  tls:
    - hosts: [shop.example.com]
      secretName: shop-tls

*Este exemplo não foi executado aqui, porque nenhum cluster Kubernetes nem o kubectl estavam instalados no computador que preparou este artigo.*

Exemplo 54: NetworkPolicy para a API

Somente a camada web pode alcançar a API.

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: api-allow-web
spec:
  podSelector:
    matchLabels:
      app: api
  policyTypes: [Ingress]
  ingress:
    - from:
        - podSelector:
            matchLabels:
              app: web
      ports:
        - port: 8000

*Este exemplo não foi executado aqui, porque nenhum cluster Kubernetes nem o kubectl estavam instalados no computador que preparou este artigo.*

Tópico 8: Jobs e CronJobs

Nem toda carga de trabalho roda para sempre. Um Job executa uma tarefa até ela dar certo, e um CronJob inicia Jobs em um agendamento, como uma tabela cron que roda dentro do cluster.

Jobs e conclusões

Um Job cria Pods até que o número de conclusões solicitado tenha sucesso. O backoffLimit limita as tentativas. Use restartPolicy como Never ou OnFailure, porque Always não é permitido em Jobs.

Trabalho paralelo

O parallelism define quantos Pods rodam ao mesmo tempo, e o completions define quantas execuções bem-sucedidas são necessárias. Esse padrão processa um lote de itens com vários workers.

CronJobs e histórico

Um CronJob usa a sintaxe cron no agendamento. O concurrencyPolicy Forbid impede execuções sobrepostas, e os limites de histórico removem Jobs antigos para manter o cluster organizado.

Exemplo 55: Um Job roda até terminar

Tarefas pontuais, como migrações de banco de dados.

apiVersion: batch/v1
kind: Job
metadata:
  name: db-migrate
spec:
  backoffLimit: 2
  template:
    spec:
      restartPolicy: Never
      containers:
        - name: migrate
          image: sample-api:1.4.2
          command: ["python", "manage.py", "migrate"]

*Este exemplo não foi executado aqui, porque nenhum cluster Kubernetes nem o kubectl estavam instalados no computador que preparou este artigo.*

Exemplo 56: Executar um Job e esperar

Aguarde a conclusão da tarefa e depois leia os logs.

kubectl apply -f job.yaml
kubectl wait --for=condition=complete job/db-migrate --timeout=120s
kubectl logs job/db-migrate

*Este exemplo não foi executado aqui, porque nenhum cluster Kubernetes nem o kubectl estavam instalados no computador que preparou este artigo.*

Exemplo 57: Um Job paralelo

Processe muitos itens com vários workers.

apiVersion: batch/v1
kind: Job
metadata:
  name: thumbnails
spec:
  completions: 10
  parallelism: 3
  template:
    spec:
      restartPolicy: OnFailure
      containers:
        - name: worker
          image: thumbnailer:2.0

*Este exemplo não foi executado aqui, porque nenhum cluster Kubernetes nem o kubectl estavam instalados no computador que preparou este artigo.*

Exemplo 58: Um CronJob agendado

Gere um relatório todas as noites às 02:00.

apiVersion: batch/v1
kind: CronJob
metadata:
  name: nightly-report
spec:
  schedule: "0 2 * * *"
  concurrencyPolicy: Forbid
  jobTemplate:
    spec:
      template:
        spec:
          restartPolicy: OnFailure
          containers:
            - name: report
              image: reporter:1.1

*Este exemplo não foi executado aqui, porque nenhum cluster Kubernetes nem o kubectl estavam instalados no computador que preparou este artigo.*

Exemplo 59: Inspecionar e disparar CronJobs

Veja execuções anteriores e inicie uma manualmente.

kubectl get cronjob nightly-report
kubectl get jobs --sort-by=.metadata.creationTimestamp
kubectl create job --from=cronjob/nightly-report manual-report-1

*Este exemplo não foi executado aqui, porque nenhum cluster Kubernetes nem o kubectl estavam instalados no computador que preparou este artigo.*

Exemplo 60: Limites de histórico de Jobs

Evite que Jobs concluídos se acumulem.

spec:
  successfulJobsHistoryLimit: 3
  failedJobsHistoryLimit: 5
  startingDeadlineSeconds: 300

*Este exemplo não foi executado aqui, porque nenhum cluster Kubernetes nem o kubectl estavam instalados no computador que preparou este artigo.*

Tópico 9: StatefulSets e DaemonSets

Algumas cargas precisam de identidade estável ou de um Pod por nó. Um StatefulSet dá aos Pods nomes ordenados e armazenamento próprio, e um DaemonSet executa uma cópia de um Pod em cada nó que atende ao critério.

Identidade do StatefulSet

Os Pods são nomeados name-0, name-1 e assim por diante, e cada um mantém o seu próprio claim criado a partir de volumeClaimTemplates. O nome permanece com o Pod ao reiniciar, o que serve para bancos de dados e brokers de mensagens.

Operações ordenadas

Por padrão, um StatefulSet inicia e para os Pods em ordem. Atualizações com partition permitem alterar primeiro os Pods de número mais alto, o que oferece um canário controlado para um sistema com estado.

DaemonSets

Um DaemonSet mantém um Pod em cada nó, o que serve para coletores de log, agentes de monitoramento e plugins de rede. O nodeSelector ou as tolerations o restringem a nós específicos.

Exemplo 61: Um StatefulSet

Nomes e armazenamento estáveis para bancos de dados.

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: redis
spec:
  serviceName: redis
  replicas: 3
  selector:
    matchLabels:
      app: redis
  template:
    metadata:
      labels:
        app: redis
    spec:
      containers:
        - name: redis
          image: redis:7-alpine
          volumeMounts:
            - name: data
              mountPath: /data
  volumeClaimTemplates:
    - metadata:
        name: data
      spec:
        accessModes: ["ReadWriteOnce"]
        resources:
          requests:
            storage: 1Gi

*Este exemplo não foi executado aqui, porque nenhum cluster Kubernetes nem o kubectl estavam instalados no computador que preparou este artigo.*

Exemplo 62: Verificar um StatefulSet

Nomes ordinais e um claim por Pod.

kubectl get statefulset redis
kubectl get pods -l app=redis
kubectl get pvc

*Este exemplo não foi executado aqui, porque nenhum cluster Kubernetes nem o kubectl estavam instalados no computador que preparou este artigo.*

Exemplo 63: Um DaemonSet

Um Pod em cada nó, para agentes.

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: node-agent
spec:
  selector:
    matchLabels:
      app: node-agent
  template:
    metadata:
      labels:
        app: node-agent
    spec:
      containers:
        - name: agent
          image: busybox:1.36
          command: ["sh", "-c", "sleep 3600"]

*Este exemplo não foi executado aqui, porque nenhum cluster Kubernetes nem o kubectl estavam instalados no computador que preparou este artigo.*

Exemplo 64: Um DaemonSet em nós rotulados

Use nodeSelector para escolher os nós.

spec:
  template:
    spec:
      nodeSelector:
        workload: edge

*Este exemplo não foi executado aqui, porque nenhum cluster Kubernetes nem o kubectl estavam instalados no computador que preparou este artigo.*

Exemplo 65: Partição de um StatefulSet

Atualize primeiro apenas alguns Pods.

spec:
  updateStrategy:
    type: RollingUpdate
    rollingUpdate:
      partition: 2

*Este exemplo não foi executado aqui, porque nenhum cluster Kubernetes nem o kubectl estavam instalados no computador que preparou este artigo.*

Exemplo 66: Escalar um StatefulSet com cuidado

Verifique os claims depois de reduzir.

kubectl get statefulset redis -o jsonpath="{.spec.replicas}"; echo
kubectl scale statefulset redis --replicas=2
kubectl get pvc -l app=redis

*Este exemplo não foi executado aqui, porque nenhum cluster Kubernetes nem o kubectl estavam instalados no computador que preparou este artigo.*

Tópico 10: Escalonamento automático

A carga muda ao longo do dia. O escalonamento automático adiciona Pods quando a demanda sobe e os remove quando ela cai, então você paga pelo que usa e os usuários continuam recebendo respostas rápidas.

Horizontal Pod Autoscaler

O HPA compara uma métrica, como o uso médio de CPU, com um alvo e altera o número de réplicas. Ele precisa do metrics server e de requests de CPU nos Pods, porque o uso é medido em relação ao request.

Comportamento do escalonamento

O campo behavior controla a velocidade com que o HPA aumenta e reduz as réplicas. Uma janela de estabilização na redução evita oscilações rápidas depois de um pico curto.

Escalonamento orientado a eventos

O KEDA escala com base em sinais externos, como o tamanho de uma fila ou o atraso de mensagens, e pode reduzir até zero quando não há trabalho. Use-o para workers que consomem filas.

Exemplo 67: Uso de recursos em tempo real

O kubectl top precisa do metrics server.

kubectl top nodes
kubectl top pods -l app=web

*Este exemplo não foi executado aqui, porque nenhum cluster Kubernetes nem o kubectl estavam instalados no computador que preparou este artigo.*

Exemplo 68: Escalonamento automático por CPU

Adicione Pods quando a carga média estiver alta.

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

*Este exemplo não foi executado aqui, porque nenhum cluster Kubernetes nem o kubectl estavam instalados no computador que preparou este artigo.*

Exemplo 69: Criar um HPA pela linha de comando

Escalone automaticamente e acompanhe a reação.

kubectl autoscale deployment web --min=2 --max=10 --cpu-percent=70
kubectl get hpa web -w

*Este exemplo não foi executado aqui, porque nenhum cluster Kubernetes nem o kubectl estavam instalados no computador que preparou este artigo.*

Exemplo 70: Escalonamento automático por memória

Use mais de uma métrica.

spec:
  metrics:
    - type: Resource
      resource:
        name: memory
        target:
          type: Utilization
          averageUtilization: 75

*Este exemplo não foi executado aqui, porque nenhum cluster Kubernetes nem o kubectl estavam instalados no computador que preparou este artigo.*

Exemplo 71: Limitar a velocidade de redução do HPA

Evite oscilações com uma janela de estabilização.

spec:
  behavior:
    scaleDown:
      stabilizationWindowSeconds: 300
      policies:
        - type: Pods
          value: 1
          periodSeconds: 60

*Este exemplo não foi executado aqui, porque nenhum cluster Kubernetes nem o kubectl estavam instalados no computador que preparou este artigo.*

Exemplo 72: Escalonamento orientado a eventos

Escale um worker pelo tamanho da fila com KEDA.

apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
  name: worker-scaler
spec:
  scaleTargetRef:
    name: worker
  minReplicaCount: 0
  maxReplicaCount: 20
  triggers:
    - type: rabbitmq
      metadata:
        queueName: orders
        mode: QueueLength
        value: "50"

*Este exemplo não foi executado aqui, porque nenhum cluster Kubernetes nem o kubectl estavam instalados no computador que preparou este artigo.*

Tópico 11: Recursos, sondas e agendamento

Informe ao Kubernetes quanta CPU e memória cada contêiner precisa, e como saber se ele está saudável. O agendador usa os requests para posicionar os Pods, e as sondas decidem quando reiniciar ou quando enviar tráfego.

Requests e limits

Um request é o que o agendador reserva para o contêiner. Um limit é o máximo que ele pode usar. Memória acima do limit faz o contêiner ser encerrado, e CPU acima do limit é limitada. Defina os dois com base no uso medido.

Sondas

A liveness probe reinicia um contêiner travado. A readiness probe remove o contêiner dos endpoints do Service enquanto ele não está pronto. A startup probe adia as outras sondas para aplicações que demoram a iniciar.

Distribuição e interrupções

As restrições de distribuição por topologia colocam as réplicas em nós ou zonas diferentes. O PodDisruptionBudget limita quantos Pods ações voluntárias, como o drain, podem remover ao mesmo tempo.

Exemplo 73: requests e limits

Como o escalonador e o kernel os usam.

containers:
  - name: api
    image: sample-api:1.4.2
    resources:
      requests:
        cpu: 250m
        memory: 256Mi
      limits:
        cpu: "1"
        memory: 512Mi

*Este exemplo não foi executado aqui, porque nenhum cluster Kubernetes nem o kubectl estavam instalados no computador que preparou este artigo.*

Exemplo 74: Uma sonda de liveness

Reinicie um contêiner travado.

livenessProbe:
  httpGet:
    path: /healthz
    port: 8000
  initialDelaySeconds: 10
  periodSeconds: 15
  failureThreshold: 3

*Este exemplo não foi executado aqui, porque nenhum cluster Kubernetes nem o kubectl estavam instalados no computador que preparou este artigo.*

Exemplo 75: Uma sonda de startup

Dê tempo para uma aplicação lenta iniciar.

startupProbe:
  httpGet:
    path: /healthz
    port: 8000
  failureThreshold: 30
  periodSeconds: 10

*Este exemplo não foi executado aqui, porque nenhum cluster Kubernetes nem o kubectl estavam instalados no computador que preparou este artigo.*

Exemplo 76: Um PodDisruptionBudget

Mantenha réplicas suficientes durante a manutenção.

apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
  name: web-pdb
spec:
  minAvailable: 2
  selector:
    matchLabels:
      app: web

*Este exemplo não foi executado aqui, porque nenhum cluster Kubernetes nem o kubectl estavam instalados no computador que preparou este artigo.*

Exemplo 77: Espalhar réplicas entre nós

Evite colocar todas as réplicas em uma única máquina.

spec:
  topologySpreadConstraints:
    - maxSkew: 1
      topologyKey: kubernetes.io/hostname
      whenUnsatisfiable: ScheduleAnyway
      labelSelector:
        matchLabels:
          app: web

*Este exemplo não foi executado aqui, porque nenhum cluster Kubernetes nem o kubectl estavam instalados no computador que preparou este artigo.*

Exemplo 78: Um PriorityClass

Mantenha Pods importantes agendados quando o cluster lotar.

apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
  name: business-critical
value: 100000
globalDefault: false
description: "Keep these Pods running when the cluster is full."

*Este exemplo não foi executado aqui, porque nenhum cluster Kubernetes nem o kubectl estavam instalados no computador que preparou este artigo.*

Tópico 12: Segurança: RBAC e segurança de Pods

O privilégio mínimo se aplica a pessoas e a aplicações. O RBAC decide quem pode fazer o quê, e as configurações de segurança do Pod limitam o que um contêiner pode fazer no nó.

ServiceAccounts, Roles e vínculos

Um ServiceAccount é a identidade de um Pod. Um Role lista os verbos permitidos sobre recursos em um namespace, e um RoleBinding o associa. Conceda apenas os verbos que a aplicação precisa, e evite o cluster-admin para aplicações.

Verificando acessos

O kubectl auth can-i testa uma permissão, opcionalmente como outro usuário ou ServiceAccount. Execute-o na etapa de revisão para que um erro apareça antes da implantação, e não depois de um incidente.

Segurança de Pods

Rótulos de namespace aplicam os Pod Security Standards, como o restricted, que bloqueia contêineres root e escalonamento de privilégios. Combine-os com um securityContext que remove capacidades e define o sistema de arquivos raiz como somente leitura.

Exemplo 79: Um ServiceAccount

Uma identidade para os Pods, com o token desativado.

apiVersion: v1
kind: ServiceAccount
metadata:
  name: api-sa
automountServiceAccountToken: false

*Este exemplo não foi executado aqui, porque nenhum cluster Kubernetes nem o kubectl estavam instalados no computador que preparou este artigo.*

Exemplo 80: Um Role com privilégio mínimo

Ler ConfigMaps em um único namespace.

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: read-config
  namespace: shop
rules:
  - apiGroups: [""]
    resources: ["configmaps"]
    verbs: ["get", "list"]

*Este exemplo não foi executado aqui, porque nenhum cluster Kubernetes nem o kubectl estavam instalados no computador que preparou este artigo.*

Exemplo 81: Um RoleBinding

Vincule o role ao ServiceAccount.

apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: api-read-config
  namespace: shop
subjects:
  - kind: ServiceAccount
    name: api-sa
    namespace: shop
roleRef:
  kind: Role
  name: read-config
  apiGroup: rbac.authorization.k8s.io

*Este exemplo não foi executado aqui, porque nenhum cluster Kubernetes nem o kubectl estavam instalados no computador que preparou este artigo.*

Exemplo 82: Verificar permissões com auth can-i

Valide o RBAC antes de implantar.

kubectl auth can-i list configmaps --as=system:serviceaccount:shop:api-sa -n shop
kubectl auth can-i delete pods --as=system:serviceaccount:shop:api-sa -n shop

*Este exemplo não foi executado aqui, porque nenhum cluster Kubernetes nem o kubectl estavam instalados no computador que preparou este artigo.*

Exemplo 83: Padrões de segurança de Pods

Aplique o perfil restricted em um namespace.

kubectl label namespace shop pod-security.kubernetes.io/enforce=restricted
kubectl label namespace shop pod-security.kubernetes.io/warn=restricted

*Este exemplo não foi executado aqui, porque nenhum cluster Kubernetes nem o kubectl estavam instalados no computador que preparou este artigo.*

Exemplo 84: Um contexto de segurança reforçado

Não root, somente leitura, sem capacidades extras.

securityContext:
  runAsNonRoot: true
  runAsUser: 10001
  allowPrivilegeEscalation: false
  readOnlyRootFilesystem: true
  capabilities:
    drop: ["ALL"]
  seccompProfile:
    type: RuntimeDefault

*Este exemplo não foi executado aqui, porque nenhum cluster Kubernetes nem o kubectl estavam instalados no computador que preparou este artigo.*

Tópico 13: Helm e Kustomize

Aplicações reais têm muitos manifestos e vários ambientes. O Helm os empacota como charts com values, e o Kustomize mantém uma base e aplica pequenos overlays para cada ambiente.

Charts e releases do Helm

Um chart é um pacote de templates com valores padrão. Um release é uma instalação. Instale, atualize e reverta com o helm, e use --atomic para que uma atualização que falha seja revertida automaticamente.

Values por ambiente

Mantenha um arquivo de values por ambiente e passe-o com -f. Confira a saída renderizada com helm template antes de instalar, para saber exatamente o que vai chegar ao cluster.

Overlays do Kustomize

O Kustomize combina uma base com overlays que alteram réplicas, imagens ou rótulos sem templates. O kubectl apply -k aplica o resultado, e o kubectl diff mostra a mudança antes.

Exemplo 85: Instalar uma aplicação com Helm

Use um chart de um repositório.

helm repo add bitnami https://charts.bitnami.com/bitnami
helm repo update
helm install shop-cache bitnami/redis --namespace shop --set architecture=standalone

*Este exemplo não foi executado aqui, porque nenhum cluster Kubernetes nem o kubectl estavam instalados no computador que preparou este artigo.*

Exemplo 86: Renderizar e verificar um chart

Visualize o YAML e valide-o no servidor.

helm template shop-web ./chart --values values-prod.yaml > rendered.yaml
kubectl apply --dry-run=server -f rendered.yaml

*Este exemplo não foi executado aqui, porque nenhum cluster Kubernetes nem o kubectl estavam instalados no computador que preparou este artigo.*

Exemplo 87: Um arquivo de values do Helm

Configurações de um ambiente.

replicaCount: 3
image:
  repository: registry.example.com/team/web
  tag: "1.4.2"
resources:
  limits:
    memory: 512Mi
ingress:
  enabled: true
  host: shop.example.com

*Este exemplo não foi executado aqui, porque nenhum cluster Kubernetes nem o kubectl estavam instalados no computador que preparou este artigo.*

Exemplo 88: Atualizar e reverter com Helm

Atualizações atômicas que se desfazem em caso de falha.

helm upgrade shop-web ./chart -n shop -f values-prod.yaml --atomic --wait
helm history shop-web -n shop
helm rollback shop-web 1 -n shop

*Este exemplo não foi executado aqui, porque nenhum cluster Kubernetes nem o kubectl estavam instalados no computador que preparou este artigo.*

Exemplo 89: Um overlay do Kustomize

Diferenças de ambiente sem templates.

# overlays/prod/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
  - ../../base
replicas:
  - name: web
    count: 5
images:
  - name: web
    newTag: "1.4.2"

*Este exemplo não foi executado aqui, porque nenhum cluster Kubernetes nem o kubectl estavam instalados no computador que preparou este artigo.*

Exemplo 90: Aplicar um overlay do Kustomize

Veja o diff primeiro e depois aplique.

kubectl kustomize overlays/prod | kubectl diff -f -
kubectl apply -k overlays/prod

*Este exemplo não foi executado aqui, porque nenhum cluster Kubernetes nem o kubectl estavam instalados no computador que preparou este artigo.*

Tópico 14: Observabilidade e depuração

Quando um Pod se comporta mal, as respostas estão no seu status, nos eventos, nos logs e nas métricas. Uma rotina calma e ordenada encontra a maioria das falhas rapidamente, e os mesmos sinais alimentam painéis e alertas.

Status, eventos e describe

O kubectl get pod mostra a fase e a contagem de reinícios. O kubectl describe lista eventos como ImagePullBackOff, CrashLoopBackOff ou FailedScheduling, e explica por que o Pod está parado.

Logs de vários Pods

Selecione Pods por rótulo com kubectl logs -l e use --prefix para ver qual Pod escreveu cada linha. Use --previous para ler os logs de um contêiner que travou e reiniciou.

Contêineres de depuração efêmeros

O kubectl debug anexa um contêiner temporário a um Pod em execução, para que você use ferramentas que não estão na imagem da aplicação, sem reiniciar a aplicação.

Exemplo 91: Logs de vários Pods

Selecione Pods por rótulo.

kubectl logs -l app=web --all-containers --prefix --tail=20
kubectl logs -l app=web -f --max-log-requests=10

*Este exemplo não foi executado aqui, porque nenhum cluster Kubernetes nem o kubectl estavam instalados no computador que preparou este artigo.*

Exemplo 92: Por que um Pod não inicia

Leia a saída do describe e o estado do contêiner.

kubectl describe pod web-6d4cf56db6-abcde
kubectl get pod web-6d4cf56db6-abcde -o jsonpath="{.status.containerStatuses[0].state}"

*Este exemplo não foi executado aqui, porque nenhum cluster Kubernetes nem o kubectl estavam instalados no computador que preparou este artigo.*

Exemplo 93: Um contêiner de depuração efêmero

Depure um Pod em execução sem reiniciá-lo.

kubectl debug -it web-6d4cf56db6-abcde --image=busybox:1.36 --target=web -- sh

*Este exemplo não foi executado aqui, porque nenhum cluster Kubernetes nem o kubectl estavam instalados no computador que preparou este artigo.*

Exemplo 94: Eventos e pressão no nó

Encontre problemas de capacidade e de despejo.

kubectl get events -A --sort-by=.lastTimestamp | tail -20
kubectl describe node worker-1 | grep -A5 "Conditions"

*Este exemplo não foi executado aqui, porque nenhum cluster Kubernetes nem o kubectl estavam instalados no computador que preparou este artigo.*

Tópico 15: Operação em produção e GitOps

Produção significa publicações repetíveis, manutenção segura e recuperação. O GitOps mantém o cluster alinhado a um repositório Git, e os backups protegem os objetos e os dados que não podem ser recriados.

GitOps

Uma ferramenta de GitOps, como o Argo CD, observa um repositório e aplica seus manifestos ao cluster. Cada mudança passa por um pull request, e o selfHeal reverte alterações manuais que se desviam do Git.

Manutenção sem interrupção

O kubectl drain move os Pods para fora de um nó antes de você atualizá-lo, e o PodDisruptionBudget mantém réplicas suficientes em execução. Execute kubectl uncordon quando o nó estiver pronto de novo.

Backups e recuperação

O Velero faz backup dos objetos do cluster e dos volumes persistentes em armazenamento de objetos. Teste a restauração em um cluster separado, porque um backup que nunca foi restaurado não está comprovado.

Exemplo 95: GitOps com Argo CD

Mantenha o cluster sincronizado com um repositório Git.

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: shop
  namespace: argocd
spec:
  project: default
  source:
    repoURL: https://github.com/example/shop-deploy
    targetRevision: main
    path: overlays/prod
  destination:
    server: https://kubernetes.default.svc
    namespace: shop
  syncPolicy:
    automated:
      prune: true
      selfHeal: true

*Este exemplo não foi executado aqui, porque nenhum cluster Kubernetes nem o kubectl estavam instalados no computador que preparou este artigo.*

Exemplo 96: Um Deployment de produção

Sondas, limites e um rollout seguro juntos.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: api
  labels:
    app: api
spec:
  replicas: 3
  revisionHistoryLimit: 5
  selector:
    matchLabels:
      app: api
  strategy:
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 0
  template:
    metadata:
      labels:
        app: api
    spec:
      containers:
        - name: api
          image: registry.example.com/team/api:1.4.2
          ports:
            - containerPort: 8000
          resources:
            requests: {cpu: 250m, memory: 256Mi}
            limits: {memory: 512Mi}
          readinessProbe:
            httpGet: {path: /ready, port: 8000}
          livenessProbe:
            httpGet: {path: /healthz, port: 8000}

*Este exemplo não foi executado aqui, porque nenhum cluster Kubernetes nem o kubectl estavam instalados no computador que preparou este artigo.*

Exemplo 97: Backup com Velero

Salve objetos e volumes do cluster no armazenamento.

velero install --provider azure --plugins velero/velero-plugin-for-microsoft-azure:v1.10.0 --bucket k8s-backups
velero backup create shop-daily --include-namespaces shop
velero backup describe shop-daily

*Este exemplo não foi executado aqui, porque nenhum cluster Kubernetes nem o kubectl estavam instalados no computador que preparou este artigo.*

Exemplo 98: Drenar e liberar um nó

Manutenção sem interromper os Pods.

kubectl cordon worker-1
kubectl drain worker-1 --ignore-daemonsets --delete-emptydir-data
kubectl uncordon worker-1

*Este exemplo não foi executado aqui, porque nenhum cluster Kubernetes nem o kubectl estavam instalados no computador que preparou este artigo.*

Exemplo 99: Verificar réplicas com Python

Use o cliente oficial do Kubernetes.

from kubernetes import client, config

config.load_kube_config()
apps = client.AppsV1Api()
for d in apps.list_namespaced_deployment("shop").items:
    ready = d.status.ready_replicas or 0
    print(d.metadata.name, f"{ready}/{d.spec.replicas}")

*Este exemplo não foi executado aqui, porque nenhum cluster Kubernetes nem o kubectl estavam instalados no computador que preparou este artigo.*

Exemplo 100: Um script de checklist de lançamento

Interrompa o lançamento se uma verificação falhar.

#!/usr/bin/env bash
set -euo pipefail
NS="$1"
kubectl -n "$NS" rollout status deployment --timeout=180s
kubectl -n "$NS" get pdb
kubectl -n "$NS" auth can-i --list --as=system:serviceaccount:"$NS":default | grep -q "\*" && { echo "default account has wildcard rights"; exit 1; }
kubectl -n "$NS" get pods -o jsonpath="{range .items[*]}{.metadata.name}{' runAsRoot='}{.spec.securityContext.runAsNonRoot}{'\n'}{end}"
echo "release checks passed for namespace $NS"

*Este exemplo não foi executado aqui, porque nenhum cluster Kubernetes nem o kubectl estavam instalados no computador que preparou este artigo.*

Laboratório: implantar, expor e lançar uma pequena aplicação web

Reúna o artigo em um único cluster de prática: um Deployment com sondas e limites, um Service, um Ingress, um ConfigMap e um Secret, uma atualização gradual com rollback e uma checagem antes do lançamento.

1. Crie um cluster de prática com kind, depois crie o namespace shop e defina-o como padrão.

2. Aplique um Deployment com três réplicas, requests e limits de recursos, uma readiness probe e uma liveness probe.

3. Adicione um Service ClusterIP, verifique os endpoints e chame-o a partir de um Pod temporário.

4. Crie um ConfigMap para as configurações e um Secret para uma senha de exemplo, e monte os dois nos Pods.

5. Publique uma nova versão da imagem, acompanhe o rollout e desfaça com kubectl rollout undo.

6. Adicione um Ingress para shop.example.com e restrinja a API com uma NetworkPolicy.

7. Execute a checklist de lançamento do exemplo 100 no namespace e pare se alguma verificação falhar.

Próximos passos

Depois do laboratório, pratique em um cluster gerenciado em uma assinatura de sandbox, aprenda charts Helm para as suas próprias aplicações e configure o GitOps para que cada mudança seja revisada no Git. Guarde os exemplos em um repositório e execute-os de novo ao atualizar o cluster, porque as APIs do Kubernetes mudam entre versões.

Resumo

O Kubernetes mantém seus contêineres em execução, distribui-os entre os nós, os atualiza sem interromper o serviço e os escala conforme a demanda. Você aprendeu o kubectl e os contextos, Pods, Deployments e rollbacks, Services e Ingress, configuração e segredos, armazenamento, Jobs e CronJobs, StatefulSets e DaemonSets, escalonamento automático, requests de recursos e sondas, RBAC e segurança de Pods, Helm e Kustomize, depuração, e GitOps com backups para produção.