A maioria dos tutoriais de Kubernetes começa com um cluster gerenciado na nuvem. Aqui é diferente: vamos montar o cluster em VMs, na sua rede, para você ver o encanamento. Isso dói um pouco — e é exatamente por isso que ensina.
O laboratório deste curso tem 3 masters e 3 workers. No capítulo 05 vamos deixar o control plane em HA; por enquanto, um master já é suficiente para aprender.
Selo do curso: testado em Ubuntu Server 24.04, Kubernetes 1.35 e containerd 2.x. IPs abaixo são fictícios (
192.168.56.x).
Topologia
| Nome | IP | vCPU | RAM | Disco | Papel |
|---|---|---|---|---|---|
| k8s-master-01 | 192.168.56.10 | 2 | 4 GB | 50 GB | control plane |
| k8s-master-02 | 192.168.56.11 | 2 | 4 GB | 50 GB | control plane (HA, cap. 05) |
| k8s-master-03 | 192.168.56.12 | 2 | 4 GB | 50 GB | control plane (HA, cap. 05) |
| k8s-worker-01 | 192.168.56.21 | 4 | 16 GB | 100 GB | worker |
| k8s-worker-02 | 192.168.56.22 | 4 | 16 GB | 100 GB | worker |
| k8s-worker-03 | 192.168.56.23 | 4 | 16 GB | 100 GB | worker |
Por que 16 GB nos workers? Porque vamos rodar banco, mensageria, object storage e observabilidade. Em laboratório, 8 GB funciona até você começar a testar carga e failover — e aí o OOM killer aparece. Aprendi isso da forma difícil.
Se você não tem 6 VMs, comece com 1 master + 1 worker. O importante é o processo.
1. Preparando as VMs
Crie as VMs no Proxmox (ou VirtualBox/UTM) com Ubuntu Server 24.04. Durante a instalação:
- Usuário com sudo.
- OpenSSH habilitado.
- Nada de swap (vamos desabilitar de qualquer forma).
Depois, em todas as VMs:
sudo hostnamectl set-hostname k8s-master-01 # ajuste por VM
sudo timedatectl set-timezone America/Sao_Paulo
sudo apt update && sudo apt upgrade -y
Configure /etc/hosts em todas (ou use DNS interno):
192.168.56.10 k8s-master-01
192.168.56.11 k8s-master-02
192.168.56.12 k8s-master-03
192.168.56.21 k8s-worker-01
192.168.56.22 k8s-worker-02
192.168.56.23 k8s-worker-03
Teste a resolução e o relógio. Relógio errado quebra TLS e o join:
getent hosts k8s-master-01
timedatectl
2. Pré-requisitos do nó
Em todas as VMs:
# swap off (agora e no boot)
sudo swapoff -a
sudo sed -i '/ swap / s/^/#/' /etc/fstab
# módulos de kernel
sudo tee /etc/modules-load.d/k8s.conf >/dev/null <<'EOF'
overlay
br_netfilter
EOF
sudo modprobe overlay
sudo modprobe br_netfilter
# sysctl de rede
sudo tee /etc/sysctl.d/k8s.conf >/dev/null <<'EOF'
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward = 1
EOF
sudo sysctl --system
Verifique:
free -h # swap deve ser 0
lsmod | grep -E 'overlay|br_netfilter'
sysctl net.ipv4.ip_forward
Não pule o swap. O kubelet se recusa a subir com swap ativo por padrão. É o erro nº 1 de quem monta o primeiro cluster.
3. containerd
O Kubernetes não fala com o Docker diretamente; ele fala com um runtime via CRI. Vamos usar o containerd.
sudo apt install -y containerd
sudo mkdir -p /etc/containerd
containerd config default | sudo tee /etc/containerd/config.toml >/dev/null
Edite /etc/containerd/config.toml e garanta:
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options]
SystemdCgroup = true
Reinicie:
sudo systemctl restart containerd
sudo systemctl enable containerd
systemctl status containerd --no-pager
4. kubeadm, kubelet e kubectl
sudo apt install -y apt-transport-https ca-certificates curl gpg
sudo mkdir -p /etc/apt/keyrings
curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.35/deb/Release.key \
| sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg
echo 'deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.35/deb/ /' \
| sudo tee /etc/apt/sources.list.d/kubernetes.list
sudo apt update
sudo apt install -y kubelet kubeadm kubectl
sudo apt-mark hold kubelet kubeadm kubectl
Confira:
kubeadm version
kubelet --version
kubectl version --client
5. kubeadm init
No master-01:
sudo kubeadm init \
--pod-network-cidr=10.244.0.0/16 \
--apiserver-advertise-address=192.168.56.10 \
--control-plane-endpoint=192.168.56.10
Ao final, ele imprime o comando de join. Guarde-o. Configure o kubeconfig do seu usuário:
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
kubectl get nodes
O master aparecerá NotReady até instalarmos a CNI. É normal.
6. CNI (flannel)
kubectl apply -f https://github.com/flannel-io/flannel/releases/latest/download/kube-flannel.yml
kubectl -n kube-flannel get pods -o wide
kubectl get nodes
Quando o flannel estiver Running em todos os nós, o master fica Ready.
Aviso: flannel resolve a rede, mas não aplica NetworkPolicy. Se você precisa de segmentação, o capítulo 06 explica Cilium/Calico. Descobri isso da pior forma: a política existia, mas não fazia efeito.
7. Join dos workers
No master, gere um novo token se precisar:
kubeadm token create --print-join-command
Rode o comando nos workers (como root):
sudo kubeadm join 192.168.56.10:6443 --token <token> \
--discovery-token-ca-cert-hash sha256:<hash>
Valide:
kubectl get nodes -o wide
kubectl get pods -A
Todos os nós devem estar Ready.
8. O primeiro “não subiu”
Alguns erros que você vai encontrar:
| Sintoma | Causa provável | Como resolver |
|---|---|---|
| kubelet não sobe | swap ativo | swapoff -a + /etc/fstab |
Node NotReady |
CNI ausente ou pod flannel com erro | kubectl -n kube-flannel logs <pod> |
join falha por TLS |
relógio dessincronizado | timedatectl, NTP |
connection refused no 6443 |
firewall ou apiserver fora | ss -lntp, crictl ps |
flannel sem subnet.env após reboot |
/run limpo e flannel subiu antes |
reinicie o DaemonSet/aguarde; verifique logs do flannel |
pods em Pending |
nó com taint ou poucos recursos | kubectl describe node |
9. Limpeza (quando precisar refazer)
sudo kubeadm reset -f
sudo rm -rf /etc/cni/net.d /var/lib/cni /var/lib/kubelet
sudo systemctl restart containerd kubelet
Faça isso em todos os nós e comece de novo. Laboratório é para isso.
Checklist
- [ ] 6 VMs com hostname, IP fixo e
/etc/hostscorretos. - [ ] Swap desativado e módulos carregados em todos os nós.
- [ ] containerd com
SystemdCgroup = true. - [ ] kubeadm/kubelet/kubectl na mesma versão.
- [ ]
kubeadm initconcluído e kubeconfig copiado. - [ ] CNI aplicada e master
Ready. - [ ] Workers com
joinconcluído eReady. - [ ]
kubectl get pods -Asem pods quebrados.
Glossário
- kubeadm: ferramenta de bootstrap do cluster.
- CRI: interface entre kubelet e runtime.
- CNI: plugin de rede dos pods.
- taint/toleration: regra de afinidade/repulsão entre pods e nós.
- join: comando que adiciona um nó ao cluster.
Próximo
Com o cluster no ar, vamos criar o primeiro Deployment, expor um Service e aprender a diagnosticar quando o pod não sobe.
Próximo: Curso Kubernetes 03 — O primeiro pod e o primeiro deploy
Continuar a ler
Leia também
KubernetesKubernetes de Verdade — do zero ao cluster em produção
Uma trilha prática para entender, montar e operar um cluster Kubernetes — do primeiro pod ao failover do Postgres.
4 min de leitura
KubernetesCurso Kubernetes 28 — DR e capstone: provar que o cluster volta
RPO, RTO e drills reais: cenários de desastre, runbook, restore medido e o capstone que fecha o curso com um cluster que se recupera.
5 min de leitura
KubernetesCurso Kubernetes 27 — SLO/SLI, on-call e postmortem blameless
O que prometer, como medir e o que fazer quando o erro estoura: SLI, SLO, error budget, alertas que acordam alguém e postmortem sem caça às bruxas.
4 min de leitura
Comentários
Ainda sem comentários
Seja o primeiro a compartilhar sua opinião sobre este artigo.

Deixe um comentário