01 O que é o Kubernetes?
Conceitos fundamentais antes de começar
O Kubernetes (abreviado K8s — o "8" representa as 8 letras entre o K e o s) é um sistema open-source de orquestração de containers criado pela Google em 2014 e hoje mantido pela CNCF (Cloud Native Computing Foundation). Automatiza o deploy, o escalamento e a gestão de aplicações em containers.
Se o Docker te permite empacotar uma aplicação num container, o Kubernetes gere centenas ou milhares desses containers em múltiplos servidores — garantindo que estão sempre a correr, que escalam quando necessário e que as actualizações se fazem sem downtime.
Pod
A unidade mínima do Kubernetes. Contém um ou mais containers que partilham rede e armazenamento. É efémero — se morrer, o Kubernetes cria um novo.
unidade básicaNode
Máquina física ou virtual que executa os Pods. Pode ser um servidor on-premises, uma VM ou um nó gerido na cloud (GKE, EKS, AKS).
máquina de trabalhoCluster
Conjunto de Nodes geridos pelo Kubernetes. Tem um Control Plane (o "cérebro") e vários Worker Nodes (onde as apps correm).
conjunto de nodesDeployment
Descreve o estado desejado da aplicação: quantas réplicas, que imagem, que recursos. O Kubernetes garante que esse estado é sempre mantido.
estado desejadoService
Ponto de acesso estável para um conjunto de Pods. Os Pods mudam de IP constantemente — o Service dá um IP e DNS fixos para aceder a eles.
rede estávelNamespace
Partição virtual dentro do cluster. Isola recursos por equipa, ambiente (dev/prod) ou projecto. Diferentes namespaces podem ter os mesmos nomes de recursos.
isolamento lógicoConfigMap
Armazena configurações não sensíveis (variáveis de ambiente, ficheiros de config) separadas do código — facilita a portabilidade entre ambientes.
configuraçãoSecret
Armazena dados sensíveis (passwords, tokens, certificados) de forma codificada (base64). Injectados nos Pods como variáveis de ambiente ou volumes.
dados sensíveisIngress
Gere o tráfego HTTP/HTTPS externo para os serviços do cluster. Um Ingress Controller (nginx, traefik) implementa as regras de roteamento.
tráfego externoPersistentVolume
Armazenamento persistente para os Pods. Ao contrário dos dados em container, um PV sobrevive ao ciclo de vida dos Pods.
persistênciaHPA
Horizontal Pod Autoscaler — escala automaticamente o número de réplicas com base em métricas (CPU, memória, requests por segundo).
auto-escalamentoHelm Chart
Pacote reutilizável de manifests Kubernetes. O Helm é o "gestor de pacotes" do K8s — instala stacks complexas com um só comando.
gestor de pacotesArquitectura do Cluster Kubernetes
KUBERNETES CLUSTER ┌─────────────────────────────────────────────────────────────────────────┐ │ │ │ CONTROL PLANE (cérebro do cluster) │ │ ┌──────────────────────────────────────────────────────────────────┐ │ │ │ kube-apiserver etcd kube-scheduler │ │ │ │ (porta de entrada) (base de dados (decide onde correm │ │ │ │ do cluster) os Pods) │ │ │ │ │ │ │ │ controller-manager (reconcilia estado actual vs. desejado) │ │ │ └──────────────────────────────────────────────────────────────────┘ │ │ │ │ │ │ │ WORKER NODE 1 WORKER NODE 2 WORKER NODE 3 │ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ │ │ kubelet │ │ kubelet │ │ kubelet │ │ │ │ kube-proxy │ │ kube-proxy │ │ kube-proxy │ │ │ │ ┌──────────┐ │ │ ┌──────────┐ │ │ ┌──────────┐ │ │ │ │ │ Pod A │ │ │ │ Pod B │ │ │ │ Pod C │ │ │ │ │ │ nginx │ │ │ │ nginx │ │ │ │ postgres │ │ │ │ │ └──────────┘ │ │ └──────────┘ │ │ └──────────┘ │ │ │ │ ┌──────────┐ │ │ ┌──────────┐ │ │ │ │ │ │ │ Pod D │ │ │ │ Pod E │ │ │ │ │ │ │ │ api-app │ │ │ │ api-app │ │ │ │ │ │ │ └──────────┘ │ │ └──────────┘ │ │ │ │ │ └──────────────┘ └──────────────┘ └──────────────┘ │ │ │ │ kubectl (CLI do utilizador) ──► kube-apiserver │ └─────────────────────────────────────────────────────────────────────────┘
02 Instalação e Primeiros Passos
Colocar um cluster Kubernetes a funcionar localmente
Para aprender Kubernetes localmente, existem várias ferramentas. O minikube é a mais recomendada para iniciantes — cria um cluster de nó único no teu PC em segundos.
Opções para cluster local
minikube
Cluster local de nó único. Suporta múltiplos drivers (Docker, VirtualBox, Hyper-V). O mais fácil para começar.
recomendado iniciantesDocker Desktop
Inclui K8s integrado. Activa com um toggle nas preferências. Ideal se já tens o Docker Desktop instalado.
Windows / macOSkind
Kubernetes IN Docker — cria clusters dentro de containers Docker. Multi-nó no mesmo PC. Rápido e leve.
CI/CD localk3s
Kubernetes ultra-leve (apenas 50 MB). Ideal para edge computing, IoT e máquinas com poucos recursos.
lightweightInstalar minikube e kubectl
# ── kubectl (cliente de linha de comandos) ────────────────────────── curl -LO "https://dl.k8s.io/release/$(curl -sL https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl" sudo install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl kubectl version --client # ── minikube ──────────────────────────────────────────────────────── curl -LO https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64 sudo install minikube-linux-amd64 /usr/local/bin/minikube # ── iniciar cluster (usa Docker como driver por defeito) ───────────── minikube start 😄 minikube v1.33.0 on Ubuntu 22.04 ✨ Using the docker driver based on existing profile 🏄 Done! kubectl is now configured to use "minikube" cluster # verificar estado do cluster kubectl cluster-info Kubernetes control plane is running at https://127.0.0.1:49153 kubectl get nodes NAME STATUS ROLES AGE VERSION minikube Ready control-plane 2m v1.30.0
brew install kubectl minikube minikube start --driver=docker
# instalar kubectl e minikube via winget winget install Kubernetes.kubectl winget install Kubernetes.minikube # ou via Chocolatey choco install kubernetes-cli minikube # iniciar (requer Hyper-V ou Docker Desktop activo) minikube start --driver=docker
Comandos essenciais do minikube
minikube start # iniciar o cluster minikube stop # parar (preserva o estado) minikube delete # eliminar completamente o cluster minikube status # ver estado do cluster minikube dashboard # abrir dashboard web no browser minikube tunnel # expor Services LoadBalancer localmente minikube addons list # listar extensões disponíveis minikube addons enable ingress # activar Ingress Controller nginx minikube addons enable metrics-server # activar métricas (para HPA)
minikube dashboard para abrir uma interface web completa onde podes ver todos os recursos do cluster, ver logs dos Pods e fazer scaling sem usar o terminal. Muito útil para aprender.
03 kubectl — A CLI do Kubernetes
Dominar a ferramenta de linha de comandos
O kubectl é a ferramenta de linha de comandos para interagir com qualquer cluster Kubernetes. Comunica com o kube-apiserver do Control Plane via REST. Cada comando segue a estrutura: kubectl [verbo] [recurso] [nome] [flags].
| Comando | O que faz |
|---|---|
| 🔍 Ver e listar recursos | |
| kubectl get pods | Lista todos os Pods do namespace actual. Adiciona -A para todos os namespaces. |
| kubectl get pods -o wide | Lista Pods com informação adicional: IP, Node onde corre, imagem. |
| kubectl get all | Lista todos os recursos principais: Pods, Services, Deployments, ReplicaSets. |
| kubectl describe pod <nome> | Informação detalhada de um Pod — eventos, condições, variáveis de ambiente, volumes. |
| kubectl get nodes | Lista todos os Nodes do cluster com estado e versão. |
| kubectl get namespaces | Lista todos os namespaces existentes. |
| 📝 Criar e aplicar recursos | |
| kubectl apply -f ficheiro.yaml | Aplica a configuração definida num manifest YAML. Cria ou actualiza o recurso. Preferir sempre este método. |
| kubectl create -f ficheiro.yaml | Cria um recurso. Falha se já existir (usa apply em alternativa). |
| kubectl run nginx --image=nginx | Cria um Pod simples a partir de uma imagem. Útil para testes rápidos. |
| kubectl apply -f pasta/ | Aplica todos os ficheiros YAML numa directoria recursivamente. |
| 🗑️ Eliminar recursos | |
| kubectl delete -f ficheiro.yaml | Elimina os recursos definidos no manifest. Método preferido. |
| kubectl delete pod <nome> | Elimina um Pod (se for gerido por Deployment, será recriado automaticamente). |
| kubectl delete deployment <nome> | Elimina o Deployment e todos os Pods associados. |
| 🔧 Depuração e acesso | |
| kubectl logs <pod> | Ver logs de um Pod. Adiciona -f para seguir em tempo real. -c container para multi-container. |
| kubectl exec -it <pod> -- bash | Abrir terminal interactivo dentro de um Pod em execução. Usa sh se bash não existir. |
| kubectl port-forward pod/<nome> 8080:80 | Redirecionar porta do Pod para o localhost. Permite testar serviços sem expor externamente. |
| kubectl top pods | Ver consumo de CPU e memória dos Pods (requer metrics-server activo). |
| kubectl events --sort-by=.lastTimestamp | Ver todos os eventos do cluster ordenados por data — essencial para diagnóstico. |
| ⚙️ Configuração e contextos | |
| kubectl config get-contexts | Listar todos os clusters configurados (minikube, GKE, AKS, etc.). |
| kubectl config use-context <nome> | Mudar para outro cluster. Fundamental para trabalhar com múltiplos clusters. |
| kubectl -n <namespace> get pods | Especificar namespace. Equivalente a --namespace. -n kube-system para recursos do sistema. |
| kubectl explain deployment | Documentação inline de qualquer recurso K8s. Inclui todos os campos disponíveis. |
# Ver o estado geral de tudo kubectl get all -A NAMESPACE NAME READY STATUS RESTARTS AGE default pod/nginx-7f456874d9-xk2m4 1/1 Running 0 5m default pod/api-6b9f4c8d7f-p9n3r 1/1 Running 0 3m # Pod com erro? Descreve para ver o motivo kubectl describe pod api-6b9f4c8d7f-p9n3r Events: Warning BackOff 2m kubelet Back-off restarting failed container # Ver os logs do pod problemático kubectl logs api-6b9f4c8d7f-p9n3r --previous Error: Cannot connect to database at host 'db': connection refused # Entrar no container para diagnóstico manual kubectl exec -it api-6b9f4c8d7f-p9n3r -- sh / # env | grep DB_ DB_HOST=db DB_PORT=5432 / # ping db ping: bad address 'db'
04 Pods — A Unidade Básica
Criar, gerir e compreender os Pods do Kubernetes
Um Pod é a unidade de deployment mais pequena do Kubernetes. Contém um ou mais containers que partilham o mesmo namespace de rede (mesmo IP e portas) e podem partilhar volumes de armazenamento. Na maioria dos casos, um Pod tem exactamente um container.
Manifest YAML de um Pod
apiVersion: v1 kind: Pod metadata: name: meu-nginx labels: app: nginx versao: v1 spec: containers: - name: nginx image: nginx:1.25-alpine ports: - containerPort: 80 resources: # SEMPRE definir limites requests: memory: "64Mi" cpu: "100m" # 100 milliCPU = 0.1 CPU limits: memory: "128Mi" cpu: "200m" livenessProbe: # reinicia se ficar "stuck" httpGet: path: / port: 80 initialDelaySeconds: 5 periodSeconds: 10 readinessProbe: # só entra em serviço quando pronto httpGet: path: / port: 80 initialDelaySeconds: 3 periodSeconds: 5
# Criar o Pod a partir do manifest kubectl apply -f pod-nginx.yaml pod/meu-nginx created # Ver o estado do Pod (aguarda ficar Running) kubectl get pod meu-nginx -w NAME READY STATUS RESTARTS AGE meu-nginx 0/1 ContainerCreating 0 3s meu-nginx 1/1 Running 0 8s # Redirecionar porta para testar localmente kubectl port-forward pod/meu-nginx 8080:80 Forwarding from 127.0.0.1:8080 -> 80 # Abre http://localhost:8080 — deves ver a página Nginx # Ver logs em tempo real kubectl logs -f meu-nginx # Eliminar o Pod kubectl delete pod meu-nginx pod "meu-nginx" deleted
Probes — Monitorização de Saúde
livenessProbe
Verifica se o container está vivo. Se falhar, o container é reiniciado. Evita Pods "stuck" que não respondem.
reinicia se falharreadinessProbe
Verifica se o container está pronto para receber tráfego. Se falhar, é removido do Service (mas não reiniciado).
tráfego pausadostartupProbe
Para apps lentas a arrancar. Desactiva as outras probes até o container estar pronto — evita reinícios prematuros.
arranque lento05 Deployments — Gerir Réplicas
Manter o estado desejado da aplicação
Na prática nunca criamos Pods directamente — usamos Deployments. Um Deployment descreve o estado desejado (quantas réplicas, que imagem) e o ReplicaSet subjacente garante que esse estado é sempre mantido. Se um Pod morrer, o Deployment cria um novo automaticamente.
apiVersion: apps/v1 kind: Deployment metadata: name: api-deployment namespace: producao labels: app: api spec: replicas: 3 # 3 instâncias em paralelo selector: matchLabels: app: api # gere os Pods com este label strategy: type: RollingUpdate # actualização sem downtime rollingUpdate: maxUnavailable: 0 # nunca reduz a capacidade maxSurge: 1 # cria 1 Pod novo antes de remover o antigo template: # template de cada Pod metadata: labels: app: api spec: containers: - name: api image: meuregistry/api:1.5.0 # tag específica, nunca latest ports: - containerPort: 3000 envFrom: - configMapRef: name: api-config # vars de ambiente de ConfigMap - secretRef: name: api-secrets # vars sensíveis de Secret resources: requests: memory: "256Mi" cpu: "200m" limits: memory: "512Mi" cpu: "500m" readinessProbe: httpGet: path: /health port: 3000 initialDelaySeconds: 10 terminationGracePeriodSeconds: 30 # tempo para fechar conexões
# Aplicar o Deployment kubectl apply -f deployment-api.yaml deployment.apps/api-deployment created # Ver estado do rollout em tempo real kubectl rollout status deployment/api-deployment Waiting for deployment "api-deployment" rollout to finish: 1 of 3 updated... Waiting for deployment "api-deployment" rollout to finish: 2 of 3 updated... deployment "api-deployment" successfully rolled out # Actualizar a imagem (rolling update sem downtime) kubectl set image deployment/api-deployment api=meuregistry/api:1.6.0 # Ou editar directamente o manifest e aplicar de novo # Rollback para a versão anterior se algo correr mal kubectl rollout undo deployment/api-deployment deployment.apps/api-deployment rolled back # Ver histórico de revisões kubectl rollout history deployment/api-deployment REVISION CHANGE-CAUSE 1 image: api:1.5.0 2 image: api:1.6.0 # Escalar manualmente o número de réplicas kubectl scale deployment/api-deployment --replicas=5 deployment.apps/api-deployment scaled
RollingUpdate actualiza os Pods gradualmente — zero downtime. A estratégia Recreate elimina todos os Pods antes de criar os novos — gera downtime mas é útil quando a nova versão é incompatível com a anterior (ex: migrações de BD que não permitem duas versões em simultâneo).
06 Services — Rede e Descoberta
Expor e ligar aplicações de forma estável
Os Pods têm IPs dinâmicos que mudam constantemente. Um Service é uma abstracção que fornece um IP e DNS estáveis para um conjunto de Pods seleccionados por labels. O Service também faz balanceamento de carga entre os Pods.
Tipos de Services
ClusterIP
Expõe o serviço apenas dentro do cluster. É o tipo por defeito. Acesso por outros Pods via nome-servico:porta.
NodePort
Expõe o serviço numa porta estática em todos os Nodes (30000–32767). Acesso externo via IP-do-Node:NodePort.
LoadBalancer
Provisiona um balanceador de carga externo no fornecedor cloud (GCP, AWS, Azure). Em minikube, usa minikube tunnel.
ExternalName
Mapeia o serviço para um nome DNS externo. Útil para integrar serviços externos sem mudar a configuração das apps.
DNS externo# ── Service ClusterIP — acesso interno (outros Pods) ──────────────── apiVersion: v1 kind: Service metadata: name: api-service spec: type: ClusterIP # padrão — não precisa ser explicitado selector: app: api # liga aos Pods com label app=api ports: - port: 80 # porta do Service (vista de fora) targetPort: 3000 # porta do container protocol: TCP --- # ── Service LoadBalancer — acesso externo (Internet) ───────────────── apiVersion: v1 kind: Service metadata: name: frontend-service spec: type: LoadBalancer selector: app: frontend ports: - port: 80 targetPort: 8080
# Dentro de qualquer Pod, podes chamar outro serviço pelo nome: # http://api-service (mesmo namespace) # http://api-service:80 (com porta explícita) # http://api-service.producao.svc.cluster.local (FQDN completo) # Testar DNS de dentro de um Pod de debugging kubectl run debug --image=curlimages/curl --rm -it -- sh / # curl http://api-service/health {"status":"ok","version":"1.5.0"} / # nslookup api-service Server: 10.96.0.10 Address: 10.96.0.10#53 Name: api-service.default.svc.cluster.local Address: 10.100.42.137
07 ConfigMaps e Secrets
Separar configuração e segredos do código
Uma das melhores práticas cloud-native é separar a configuração do código. O Kubernetes fornece dois recursos para isso: ConfigMaps para configurações não sensíveis e Secrets para dados sensíveis.
# ── ConfigMap — configurações não sensíveis ────────────────────────── apiVersion: v1 kind: ConfigMap metadata: name: api-config data: NODE_ENV: "production" PORT: "3000" LOG_LEVEL: "info" DB_HOST: "postgres-service" DB_PORT: "5432" app.properties: | # ficheiro de configuração completo max.connections=100 timeout=30s retry.attempts=3 --- # ── Secret — dados sensíveis (codificados em base64) ───────────────── apiVersion: v1 kind: Secret metadata: name: api-secrets type: Opaque stringData: # escrever em texto simples (K8s codifica) DB_PASSWORD: "supersegredo123" JWT_SECRET: "chave-jwt-muito-secreta" API_KEY: "sk-live-xxxxxxxxxxx"
# Criar ConfigMap a partir de ficheiro .env kubectl create configmap api-config --from-env-file=.env # Criar ConfigMap a partir de valores directos kubectl create configmap app-config \ --from-literal=NODE_ENV=production \ --from-literal=PORT=3000 # Criar Secret (K8s codifica automaticamente em base64) kubectl create secret generic api-secrets \ --from-literal=DB_PASSWORD=supersegredo123 \ --from-literal=JWT_SECRET=chave-secreta # Verificar (os valores aparecem codificados) kubectl get secret api-secrets -o yaml data: DB_PASSWORD: c3VwZXJzZWdyZWRvMTIz # base64 # Descodificar para verificar (em base64) kubectl get secret api-secrets -o jsonpath='{.data.DB_PASSWORD}' | base64 -d supersegredo123
08 Volumes e Persistência
Guardar dados que sobrevivem ao ciclo de vida dos Pods
Os dados dentro de um container são perdidos quando o Pod é destruído. Para persistência, o Kubernetes usa PersistentVolumes (PV) — recursos de armazenamento do cluster — e PersistentVolumeClaims (PVC) — pedidos de armazenamento pelos Pods.
FLUXO DE ARMAZENAMENTO PERSISTENTE
Administrador cria: Programador define:
┌─────────────────────┐ ┌─────────────────────┐
│ PersistentVolume │◄─────────────│ PersistentVolume │
│ (PV) │ vincula │ Claim (PVC) │
│ │ │ │
│ capacity: 10Gi │ │ storage: 5Gi │
│ accessMode: RWO │ │ accessMode: RWO │
│ storageClass: ssd │ │ storageClass: ssd │
└─────────────────────┘ └──────────┬──────────┘
│ │ montado em
│ armazenamento real ▼
│ (NFS, cloud disk, ┌─────────────────────┐
│ hostPath...) │ Pod │
└────────────────────────►│ volumeMounts: │
│ /data → PVC │
└─────────────────────┘
# ── PersistentVolumeClaim — pedido de armazenamento ───────────────── apiVersion: v1 kind: PersistentVolumeClaim metadata: name: postgres-pvc spec: accessModes: - ReadWriteOnce # montado em leitura/escrita por 1 Node storageClassName: standard # classe de storage do cluster resources: requests: storage: 5Gi --- # ── Deployment do PostgreSQL usando o PVC ──────────────────────────── apiVersion: apps/v1 kind: Deployment metadata: name: postgres spec: replicas: 1 # BD = apenas 1 réplica (sem estado partilhado) selector: matchLabels: app: postgres template: metadata: labels: app: postgres spec: containers: - name: postgres image: postgres:16-alpine env: - name: POSTGRES_PASSWORD valueFrom: secretKeyRef: name: api-secrets key: DB_PASSWORD volumeMounts: - name: pgdata mountPath: /var/lib/postgresql/data volumes: - name: pgdata persistentVolumeClaim: claimName: postgres-pvc # referência ao PVC criado acima
09 Ingress — Tráfego HTTP Externo
Expor múltiplos serviços com um único ponto de entrada
Em produção, não vamos ter um LoadBalancer por serviço (seria muito caro e complexo). O Ingress é um recurso que define regras de roteamento HTTP/HTTPS — um único IP externo distribui o tráfego por múltiplos serviços com base no host ou no caminho da URL.
INGRESS — ROTEAMENTO HTTP Internet │ ▼ ┌──────────────────────────────────────────────────────┐ │ Ingress Controller (nginx) │ │ IP externo: 20.40.50.60 │ │ │ │ app.empresa.pt → frontend-service:80 │ │ api.empresa.pt → api-service:80 │ │ app.empresa.pt/admin → admin-service:80 │ └──────────────────────────────────────────────────────┘ │ │ │ ▼ ▼ ▼ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ frontend │ │ api │ │ admin │ │ Pods │ │ Pods │ │ Pods │ └──────────┘ └──────────┘ └──────────┘
apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: ingress-principal annotations: nginx.ingress.kubernetes.io/rewrite-target: / cert-manager.io/cluster-issuer: "letsencrypt-prod" # SSL automático spec: ingressClassName: nginx tls: # HTTPS com certificado automático - hosts: - app.empresa.pt - api.empresa.pt secretName: empresa-tls rules: - host: app.empresa.pt # roteamento por host http: paths: - path: / pathType: Prefix backend: service: name: frontend-service port: number: 80 - host: api.empresa.pt # roteamento por host diferente http: paths: - path: / pathType: Prefix backend: service: name: api-service port: number: 80
# Activar o addon nginx-ingress-controller minikube addons enable ingress 💡 ingress is an addon maintained by Kubernetes. 🌟 The 'ingress' addon is enabled # Aplicar o manifest do Ingress kubectl apply -f ingress.yaml # Ver IP do Ingress kubectl get ingress NAME CLASS HOSTS ADDRESS PORTS AGE ingress-principal nginx app.empresa.pt,api.emp... 192.168.49.2 80, 443 30s # Testar localmente (adicionar ao /etc/hosts): # 192.168.49.2 app.empresa.pt api.empresa.pt curl -H "Host: api.empresa.pt" http://192.168.49.2/health {"status":"ok"}
10 Escalamento Automático
HPA, VPA e Cluster Autoscaler
Uma das maiores vantagens do Kubernetes é o escalamento automático. Existem três tipos complementares: HPA (mais Pods), VPA (Pods maiores) e Cluster Autoscaler (mais Nodes).
HPA — Horizontal Pod Autoscaler
Aumenta/diminui o número de réplicas (Pods) com base em métricas. A forma mais comum de escalamento.
mais/menos PodsVPA — Vertical Pod Autoscaler
Ajusta automaticamente os requests/limits de CPU e memória dos Pods com base no uso real histórico.
Pods maiores/menoresCluster Autoscaler
Adiciona/remove Nodes do cluster quando os Pods não conseguem ser agendados por falta de recursos.
mais/menos NodesKEDA
Kubernetes Event-Driven Autoscaling. Escala com base em eventos externos (fila de mensagens, cron, métricas customizadas).
event-drivenHorizontal Pod Autoscaler (HPA)
apiVersion: autoscaling/v2 kind: HorizontalPodAutoscaler metadata: name: api-hpa spec: scaleTargetRef: apiVersion: apps/v1 kind: Deployment name: api-deployment minReplicas: 2 # mínimo sempre garantido maxReplicas: 10 # máximo de réplicas metrics: - type: Resource resource: name: cpu target: type: Utilization averageUtilization: 70 # escala se CPU > 70% - type: Resource resource: name: memory target: type: Utilization averageUtilization: 80 # escala se memória > 80%
# Activar metrics-server (necessário para HPA) minikube addons enable metrics-server # Aplicar o HPA kubectl apply -f hpa.yaml # Ver estado do HPA kubectl get hpa NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE api-hpa Deployment/api-deploy 23%/70%, 0%/80% 2 10 2 1m # Simular carga (em outro terminal) kubectl run carga --image=busybox --rm -it -- sh / # while true; do wget -q -O- http://api-service/; done # Observar o HPA escalar em tempo real kubectl get hpa -w api-hpa Deployment/api 85%/70% 2 10 2 2m api-hpa Deployment/api 92%/70% 2 10 4 3m # escalou para 4! api-hpa Deployment/api 67%/70% 2 10 4 5m api-hpa Deployment/api 12%/70% 2 10 2 8m # voltou a 2
11 Helm — Gestor de Pacotes
Instalar e gerir aplicações complexas com Charts
O Helm é o gestor de pacotes do Kubernetes — como o apt do Debian ou o npm do Node.js. Um Chart é um pacote Helm que contém todos os manifests Kubernetes necessários para deployar uma aplicação, parametrizados com templates.
# ── instalar Helm ─────────────────────────────────────────────────── # Linux / macOS curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash # macOS via Homebrew brew install helm # Windows via Winget winget install Helm.Helm # ── repositórios de Charts ────────────────────────────────────────── helm repo add stable https://charts.helm.sh/stable helm repo add bitnami https://charts.bitnami.com/bitnami helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx helm repo update # actualizar lista de charts # ── exemplos de instalação ────────────────────────────────────────── # Instalar nginx-ingress-controller helm install ingress-nginx ingress-nginx/ingress-nginx \ --namespace ingress-nginx --create-namespace # Instalar PostgreSQL com configuração customizada helm install meu-postgres bitnami/postgresql \ --set auth.postgresPassword=segredo \ --set primary.persistence.size=10Gi \ --namespace databases --create-namespace # Instalar Prometheus + Grafana (stack de monitorização) helm repo add prometheus-community https://prometheus-community.github.io/helm-charts helm install kube-prometheus prometheus-community/kube-prometheus-stack \ --namespace monitoring --create-namespace
| Comando Helm | O que faz |
|---|---|
| 📦 Gerir releases | |
| helm install nome chart/ | Instala um Chart como release. Cada instalação tem um nome único. |
| helm upgrade nome chart/ | Actualiza uma release existente. Usa --install para instalar se não existir. |
| helm rollback nome 1 | Volta a uma revisão anterior. O número é o número da revisão histórica. |
| helm uninstall nome | Remove completamente a release e todos os recursos criados. |
| helm list | Lista todas as releases instaladas no namespace actual. |
| helm status nome | Estado detalhado de uma release — recursos criados, notas de instalação. |
| 🔍 Explorar Charts | |
| helm search hub nginx | Pesquisa charts no Artifact Hub (repositório público central). |
| helm show values bitnami/nginx | Mostra todos os valores configuráveis de um chart. |
| helm template nome chart/ | Renderiza os manifests YAML sem instalar — útil para ver o que seria criado. |
| 🔨 Criar charts próprios | |
| helm create meu-chart | Cria a estrutura de pastas de um chart novo com templates de exemplo. |
| helm lint meu-chart/ | Valida a sintaxe e a estrutura do chart. |
| helm package meu-chart/ | Empacota o chart num ficheiro .tgz para distribuição. |
Criar um Chart personalizado
helm create minha-api Creating minha-api # Estrutura criada: minha-api/ ├── Chart.yaml # metadados do chart (nome, versão, descrição) ├── values.yaml # valores por defeito (configuráveis) ├── templates/ │ ├── deployment.yaml # template do Deployment (usa {{ .Values.* }}) │ ├── service.yaml # template do Service │ ├── ingress.yaml # template do Ingress │ ├── hpa.yaml # template do HPA │ └── _helpers.tpl # funções auxiliares reutilizáveis └── charts/ # dependências (sub-charts) # Instalar o chart em modo de desenvolvimento helm install minha-api ./minha-api \ --set image.tag=1.5.0 \ --set replicaCount=3 # Actualizar com novos valores helm upgrade minha-api ./minha-api \ --set image.tag=1.6.0
12 Boas Práticas
Produção-ready: o que fazer e o que evitar
Nunca usar imagens :latest
Em produção usa sempre tags específicas (ex: nginx:1.25.3). :latest pode introduzir mudanças inesperadas a qualquer momento.
Correr como utilizador não-root
Define securityContext.runAsNonRoot: true e readOnlyRootFilesystem: true no Pod spec para reduzir a superfície de ataque.
Sempre definir requests e limits
Sem resources.requests o scheduler não consegue tomar boas decisões. Sem limits, um Pod pode afogar todos os outros no Node.
Configurar Probes sempre
readinessProbe evita enviar tráfego para Pods não prontos. livenessProbe reinicia Pods que ficaram presos sem conseguir responder.
Usar Namespaces para isolamento
Separa ambientes (dev, staging, prod) e equipas em namespaces diferentes. Aplica ResourceQuotas por namespace para evitar abusos.
Pod Disruption Budgets
Define quantos Pods podem estar indisponíveis durante manutenções (maxUnavailable: 1). Evita que actualizações de Nodes deixem a app sem réplicas suficientes.
Infraestrutura como Código
Guarda todos os manifests YAML num repositório Git. Usa ArgoCD ou Flux para sincronizar automaticamente o cluster com o repositório.
Nunca fazer kubectl apply manual
Em produção, alterações ao cluster devem passar sempre por PR no Git e ser aplicadas pelo pipeline CI/CD — nunca directamente da máquina de um developer.
Logs estruturados (JSON)
As aplicações devem escrever logs em JSON para facilitar a indexação e pesquisa em ferramentas como Loki, Elasticsearch ou Datadog.
Expor métricas Prometheus
Todas as aplicações devem expor um endpoint /metrics no formato Prometheus. Usa client libraries (promclient para Node, Prometheus para Python...).
Network Policies
Por defeito, todos os Pods comunicam entre si. Define NetworkPolicy para implementar microsegmentação — cada Pod só comunica com quem precisa.
Multi-réplica + Anti-affinity
Com podAntiAffinity, garantes que as réplicas ficam em Nodes diferentes — se um Node cair, a app continua a servir tráfego.