Dia 29: Kubernetes Básico no Linux — Pods, Deployments e kubectl
Chegámos ao penúltimo dia do curso Linux 30 Dias. Depois de aprender Docker no Dia 22 e contentorização, damos o salto para a orquestração de contentores. O Kubernetes é hoje a plataforma de facto para gerir aplicações contentorizadas em escala — mas para um sysadmin que vem de systemd e shell, a curva pode parecer íngreme. Este artigo cobre os conceitos essenciais, a instalação do kubectl, Pods, Deployments, Services, ConfigMaps, Secrets e os erros mais comuns que vão aparecer no primeiro contacto.
Audiência: sysadmins Linux que dominam Docker e querem começar a orquestrar contentores. Vamos usar o K3s — uma distribuição Kubernetes leve e ideal para laboratórios — mas todos os conceitos aplicam-se a qualquer cluster.
ℹ Neste artigo:
1. Introdução
O Kubernetes (pronuncia-se koo-ber-NET-ees) é um orquestrador de contentores código aberto, originalmente desenvolvido pelo Google e hoje mantido pela CNCF. O nome vem do grego e significa timoneiro — aquele que governa o leme do navio. A metáfora é apropriada: o Kubernetes assume o leme de uma frota de contentores, decidindo onde cada um corre, reiniciando os que falham e escalando conforme a carga.
Para um sysadmin, o Kubernetes resolve problemas que o Docker Compose (que cobrimos no Dia 22) não resolve bem: escalonamento automático, recuperação de falhas de nós, actualizações rolling sem downtime e descoberta de serviços entre múltiplas máquinas. O Docker Compose é excelente para desenvolvimento e stacks simples num único hospedeiro; o Kubernetes brilha quando se precisa de vários nós, alta disponibilidade e ciclos de vida complexos.
✓ Boa prática: Se a sua aplicação cabe num único servidor e não precisa de alta disponibilidade, o Docker Compose é suficiente. O Kubernetes acrescenta complexidade real — só vale a pena quando se justifica pela escala ou pela resiliência. Não é uma medalha; é uma ferramenta.
A versão actual do Kubernetes segue um ciclo de lançamento de aproximadamente quatro meses. Cada versão tem suporte durante 14 meses. A versão mais recente pode ser consultada na página oficial de releases. Para este artigo usaremos comandos compatíveis com versões 1.28+.
2. Conceitos do Kubernetes
Antes de instalar qualquer coisa, convém dominar o vocabulário. O Kubernetes tem a sua própria linguagem — entender estes conceitos é metade do trabalho.
Cluster, Nós e Control Plane
Um cluster Kubernetes é um conjunto de máquinas (físicas ou virtuais) que executam contentores em conjunto. Divide-se em dois tipos de nós:
- Control Plane (plano de controlo) — o cérebro do cluster. Corre componentes como o
kube-apiserver, oetcd(base de dados do estado do cluster), okube-schedulere okube-controller-manager. Nunca se correm cargas de trabalho aqui em produção. - Worker Nodes (nós de trabalho) — onde os contentores realmente executam. Cada Worker corre o
kubelet(agente que fala com o Control Plane) e um container runtime (containerd, CRI-O).
Pods, ReplicaSets e Deployments
O Pod é a unidade mínima do Kubernetes — não o contentor. Um Pod contém um ou mais contentores que partilham rede e armazenamento. Pensa num Pod como uma máquina virtual muito pequena: tem o seu próprio IP, porta e volumes. Na prática, a maioria dos Pods contém apenas um contentor.
O ReplicaSet garante que um número desejado de réplicas de um Pod está sempre a correr. O Deployment é uma camada por cima do ReplicaSet que acrescenta actualizações rolling e rollbacks. Raramente se cria um ReplicaSet directamente — usa-se sempre o Deployment.
Services, Ingress, ConfigMaps e Secrets
Um Service dá um IP estável e um nome DNS a um conjunto de Pods, mesmo que esses Pods sejam destruídos e recriados. O Ingress expõe serviços HTTP/HTTPS ao mundo exterior, tipicamente com terminação TLS. Os ConfigMaps guardam configuração não sensível; os Secrets guardam dados sensíveis (palavras-passe, tokens) codificados em base64.
| Conceito | Função | Equivalente Docker |
|---|---|---|
| Pod | Unidade mínima com 1+ contentores | container |
| Deployment | Gestão de réplicas e rolling updates | docker compose (parcial) |
| Service | IP estável e DNS para Pods | docker network + expose |
| Ingress | HTTP(S) routing externo | nginx proxy / Traefik |
| ConfigMap | Configuração não sensível | .env file / env_file |
| Secret | Dados sensíveis (base64) | docker secrets (Swarm) |
A documentação completa de todos os conceitos está no site oficial: Kubernetes Concepts.
3. Instalar o kubectl
O kubectl é a ferramenta de linha de comando para falar com o cluster Kubernetes. Instala-se na máquina de onde se administra — não necessariamente no próprio cluster.
Instalação directa (recomendada)
# Descarregar o binário mais recente
curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"
# Tornar executável e instalar em /usr/local/bin
sudo install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl
# Verificar a versão
kubectl version --client
Instalação via gestor de pacotes
# Debian/Ubuntu
sudo apt-get update && sudo apt-get install -y kubectl
# Fedora/RHEL
sudo dnf install -y kubectl
# Arch Linux
sudo pacman -S kubectl
Configurar o kubeconfig
O kubectl lê a configuração de acesso ao cluster a partir de ~/.kube/config. Este ficheiro contém os endpoints, certificados e tokens de autenticação. Quando se instala um cluster, o ficheiro é gerado automaticamente; para clusters remotos, copia-se do Control Plane:
# No Control Plane, copiar o kubeconfig para a máquina de administração
scp root@control-plane:/etc/kubernetes/admin.conf ~/.kube/config
# Proteger o ficheiro (contém credenciais)
chmod 600 ~/.kube/config
# Testar a ligação
kubectl cluster-info
kubectl get nodes
⚠ Atenção: O ficheiro ~/.kube/config dá acesso total ao cluster. Trata-o como uma palavra-passe de root — nunca o commits para git nem o partilhas por e-mail.
Atalhos úteis
Para escrever menos, activa a auto-compleção no bash:
# Auto-compleção bash
echo 'source <(kubectl completion bash)' >> ~/.bashrc
# Aliase k = kubectl
echo 'alias k=kubectl' >> ~/.bashrc
source ~/.bashrc
# Agora: k get pods
Guia completo de instalação em Install Tools e referência de comandos em kubectl Commands.
4. Pods e Deployments
É altura de meter as mãos no cluster. Vamos criar um cluster K3s (leve, single-binary) e lançar a primeira aplicação.
Instalar um cluster K3s (1 comando)
# Instalar K3s — Kubernetes leve num único binário
curl -sfL https://get.k3s.io | sh -
# O K3s cria automaticamente o kubeconfig
# Copiar para o local padrão para o kubectl encontrar
sudo cp /etc/rancher/k3s/k3s.yaml ~/.kube/config
sudo chown $(id -u):$(id -g) ~/.kube/config
chmod 600 ~/.kube/config
# Verificar que o cluster está a funcionar
kubectl get nodes
O K3s é a forma mais rápida de ter um cluster Kubernetes real. Em produção usa-se em edge computing, sites remotos e laboratórios. Documentação completa em docs.k3s.io e código no GitHub.
Criar um Pod imperativamente
A forma mais rápida de lançar um Pod — ideal para testes rápidos:
# Lançar um Pod nginx
kubectl run nginx --image=nginx:latest
# Ver os Pods em execução
kubectl get pods
# Obter detalhes de um Pod
kubectl describe pod nginx
# Abrir uma shell dentro do Pod
kubectl exec -it nginx -- /bin/bash
# Ver logs
kubectl logs nginx
# Eliminar o Pod
kubectl delete pod nginx
⚠ Atenção: Pods criados com kubectl run não são geridos por um Deployment. Se o Pod morrer, ninguém o reinicia. Em produção usa-se sempre um Deployment.
Criar um Deployment declarativamente
A forma correcta — escrever um ficheiro YAML e aplicar. Guarda-se em deployment.yaml:
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-deployment
labels:
app: web
spec:
replicas: 3
selector:
matchLabels:
app: web
template:
metadata:
labels:
app: web
spec:
containers:
- name: nginx
image: nginx:1.25
ports:
- containerPort: 80
resources:
requests:
memory: "64Mi"
cpu: "250m"
limits:
memory: "128Mi"
cpu: "500m"
Aplicar o ficheiro:
# Aplicar o Deployment
kubectl apply -f deployment.yaml
# Ver o Deployment
kubectl get deployments
kubectl get pods -l app=web
# Ver o estado do rollout
kubectl rollout status deployment/web-deployment
# Escalar para 5 réplicas
kubectl scale deployment web-deployment --replicas=5
# Actualizar a imagem (rolling update)
kubectl set image deployment/web-deployment nginx=nginx:1.26
# Fazer rollback se algo correr mal
kubectl rollout undo deployment/web-deployment
# Ver o histórico de revisões
kubectl rollout history deployment/web-deployment
A diferença entre abordagem imperativa (kubectl run) e declarativa (kubectl apply -f) é fundamental: a declarativa é reproduzível, versionável em git e idempotente — conceitos que já explorámos no Dia 24 (Git para Sysadmins). Documentação de Pods em kubernetes.io e de Deployments aqui.
5. Services e Ingress
Os Pods têm IPs efémeros — mudam a cada reinício. O Service resolve este problema, dando um IP estável e um nome DNS interno. O Ingress vai um passo além e encaminha tráfego HTTP exterior para serviços internos.
Tipos de Service
| Tipo | Acesso | Casos de uso |
|---|---|---|
| ClusterIP | Apenas dentro do cluster | Comunicação interna entre serviços |
| NodePort | Porta alta em todos os nós (30000-32767) | Testes rápidos, acesso externo simples |
| LoadBalancer | IP externo via cloud provider | Produção em cloud (AWS, GCP, Azure) |
| ExternalName | Alias DNS para serviço externo | Aceder a BD externa via DNS interno |
Expor um Deployment como Service
# Expor como NodePort (acessível fora do cluster)
kubectl expose deployment web-deployment \
--type=NodePort \
--port=80 \
--name=web-service
# Ver o Service e a porta atribuída
kubectl get svc web-service
# Testar o acesso (substituir a porta)
curl http://localhost:$(kubectl get svc web-service -o jsonpath='{.spec.ports[0].nodePort}')
Service declarativo
apiVersion: v1
kind: Service
metadata:
name: web-service
spec:
type: ClusterIP
selector:
app: web
ports:
- port: 80
targetPort: 80
protocol: TCP
Ingress
O Ingress é a forma correcta de expor serviços HTTP/HTTPS ao exterior. Precisa de um Ingress Controller (nginx-ingress, Traefik — que o K3s já traz instalado). Um Ingress simple:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: web-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
rules:
- host: web.exemplo.pt
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: web-service
port:
number: 80
# Aplicar e testar
kubectl apply -f ingress.yaml
kubectl get ingress
# Resolver o host localmente para testar
echo "127.0.0.1 web.exemplo.pt" | sudo tee -a /etc/hosts
curl http://web.exemplo.pt
Documentação de Services em kubernetes.io e de Ingress aqui.
6. ConfigMaps e Secrets
Configuração e segredos são a última peça do puzzle. O Kubernetes separa configuração não sensível (ConfigMaps) de dados sensíveis (Secrets), permitindo que a mesma imagem de contentor corra em diferentes ambientes apenas alterando os valores injectados.
ConfigMaps — configuração não sensível
# Criar um ConfigMap a partir de literais
kubectl create configmap app-config \
--from-literal=LOG_LEVEL=info \
--from-literal=MAX_CONNECTIONS=100 \
--from-literal=ENV=production
# Ver o ConfigMap
kubectl get configmap app-config -o yaml
# Criar a partir de um ficheiro
kubectl create configmap nginx-config --from-file=nginx.conf
De forma declarativa:
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
data:
LOG_LEVEL: "info"
MAX_CONNECTIONS: "100"
ENV: "production"
app.properties: |
debug=false
timeout=30
cache_size=256
Para consumir num Pod — como variáveis de ambiente:
spec:
containers:
- name: app
image: minha-app:latest
envFrom:
- configMapRef:
name: app-config
Secrets — dados sensíveis
Os Secrets guardam palavras-passe, tokens e chaves. São codificados em base64 — não são encriptados por defeito. Para segurança real em produção, usa-se SOPS + age ou External Secrets Operator.
# Criar um Secret (valores em base64)
kubectl create secret generic db-secret \
--from-literal=username=admin \
--from-literal=password=super-secreta
# Ver o Secret (mostra base64, não texto)
kubectl get secret db-secret -o yaml
# Descodificar um valor específico
kubectl get secret db-secret -o jsonpath='{.data.password}' | base64 -d
De forma declarativa — nota: os valores têm de estar em base64:
# Gerar base64 (não é encriptação!)
echo -n 'admin' | base64
echo -n 'super-secreta' | base64
apiVersion: v1
kind: Secret
metadata:
name: db-secret
type: Opaque
data:
username: YWRtaW4=
password: c3VwZXItc2NyZXRh
⚠ Atenção: base64 é codificação, não encriptação. Qualquer pessoa com acesso ao cluster consegue descodificar o Secret. Em produção, activa a encriptação de Secrets em descanso no etcd e usa ferramentas externas como SOPS, Vault ou Sealed Secrets.
Documentação de ConfigMaps em kubernetes.io e de Secrets aqui.
7. Erros Comuns e Checklist
Depois de dezenas de horas com Kubernetes, estes são os erros que aparecem repetidamente. Cada um tem uma causa directa e uma solução rápida.
| Causa | Problema | Solução |
|---|---|---|
| ImagePullBackOff | Imagem não existe ou sem permissão | Verificar nome/tag; criar imagePullSecret para registos privados |
| CrashLoopBackOff | Contentor arranca e morre repetidamente | Ver logs com kubectl logs; validar config e variáveis |
| Pending | Sem recursos ou sem node com taints compatíveis | Ver kubectl describe pod; ajustar requests/limits |
| Connection refused | Service a apontar para porta errada | Confirmar targetPort no Service vs containerPort no Pod |
| kubectl: command not found | kubectl não instalado ou não no PATH | Instalar via binário ou gestor de pacotes; verificar echo $PATH |
| The connection to the server was refused | kubeconfig em falta ou inválido | Verificar ~/.kube/config; copiar do Control Plane |
Comandos de diagnóstico essenciais
# Estado geral do cluster
kubectl get nodes
kubectl get pods --all-namespaces
kubectl get events --sort-by='.lastTimestamp'
# Diagnosticar um Pod problemático
kubectl describe pod NOME_DO_POD
kubectl logs NOME_DO_POD
kubectl logs NOME_DO_POD --previous
# Entrar num Pod em dificuldade
kubectl exec -it NOME_DO_POD -- /bin/sh
# Ver recursos consumidos
kubectl top nodes
kubectl top pods
# Ver todos os recursos de uma vez
kubectl get all
Checklist antes de production
✓ Checklist:
- Definir
resources.requestselimitsem todos os containers - Configurar
readinessProbeelivenessProbeem todos os Pods - Usar Deployments (nunca Pods isolados) para cargas de produção
- Versionar todos os YAMLs em git — Infrastructure as Code
- Activar encriptação de Secrets no etcd
- Configurar backups do etcd (é o estado do cluster)
- Definir
PodDisruptionBudgetspara garantir disponibilidade durante manutenções - Monitorizar com Prometheus + Grafana (ver Dia 25)
- Centralizar registos com Loki ou ELK (ver Dia 26)
O Kubernetes tem uma curva de aprendizagem real, mas os conceitos base — Pods, Deployments, Services, ConfigMaps — são estáveis e não mudam entre versões. Depois de dominar estes, o resto é profundidade: StatefulSets, DaemonSets, Jobs, CronJobs, Helm, Operators. O importante é começar pequeno, num cluster de laboratório como o K3s, e iterar.
ℹ Próximo passo: O Dia 30 (último do curso) fecha com um projecto completo — juntar Docker, monitorização, registos e Kubernetes num stack ponta-a-ponta. Se quiseres aprofundar Kubernetes agora, a referência oficial do kubectl é o melhor ponto de partida.
Artigos relacionados: