A história do Kubernetes: o leme do Borg

Mascote do LinuxPro ao timão do navio com os contêineres organizados no convés e o leme do Kubernetes

Em 6 de junho de 2014 Joe Beda fez o primeiro commit público do que viraria o Kubernetes: 250 arquivos, 47.501 linhas de Go, Bash e Markdown. Quatro dias depois Eric Brewer anunciou o projeto no DockerCon. Um ano depois, em 21 de julho de 2015, saiu a 1.0 — e o Google anunciou que doaria o código à recém-criada Cloud Native Computing Foundation. Doze anos depois, o Kubernetes 1.37.0 (26 de agosto de 2026), apelido Garhwal, ainda é o jeito padrão de orquestrar container em produção.

Anos 2000: Borg, Omega e um protótipo em Java

Antes do leme existia o Borg. Desde meados dos anos 2000 o Google já rodava jobs em um cluster interno que ninguém de fora via. O Omega (2013) tentou o próximo passo: um scheduler mais compartilhado, menos monolito. Nada disso saía do campus. Lá fora, em 2013, o mundo de nuvem ainda era script bash, imagem de VM imutável à la Netflix e pouquíssima orquestração de container.

Quem mudou o recorte foi o Docker. Brendan Burns, Craig McLuckie e Joe Beda, no Google Cloud, viram o runtime de uma máquina só e entenderam o buraco: faltava o orquestrador da frota. Burns fez um protótipo em Java. Reescreveram em Go. Vieram Ville Aikas, Tim Hockin, Dawn Chen, Brian Grant e Daniel Smith. Pod ainda se chamava Task; o nome mudou dois dias antes do anúncio, no commit de 8 de junho.

O nome de código interno, dado por Burns, era Seven of Nine: a Borg mais acessível de Star Trek. Daí o heptágono do logo: sete lados, sete raios no leme. Kubernetes, em grego, é o timoneiro — o piloto do navio. k8s é o mesmo truque do i18n: oito letras no meio.

Junho de 2014: o commit e o DockerCon

O primeiro commit público é de 6 de junho de 2014, 16:40:48 no horário do Pacífico. Beda limpou o repositório para o lançamento; o trabalho anterior já existia. Em 10 de junho Brewer subiu no palco do primeiro DockerCon. O recado era simples: Docker empacota; falta alguém para espalhar o pacote em dezenas de máquinas, replicar, descobrir serviço e curar o que morre.

O “orquestrador mínimo viável” que eles queriam tinha quatro peças: replicação, balanceamento e descoberta de serviço, health check com autorreparo, e um scheduler que trata a frota como um pool. O resto — Ingress, CRD, Operators, sidecar — veio depois, da comunidade.

Julho de 2015: a 1.0, o OSCON e a CNCF

A Red Hat chegou cedo e trouxe o que faltava: a experiência de vender software para empresa grande, acumulada no OpenShift. Sem esse recorte de mundo real — multi-tenancy, atualização sem downtime, autorização que sobrevive a auditoria — a 1.0 não saía. RBAC de verdade só viria na 1.6, em 2017. Em 21 de julho de 2015, no OSCON, o Kubernetes 1.0 foi declarado pronto para produção. No mesmo dia o Google cedeu o controle: nascia a Cloud Native Computing Foundation, braço da Linux Foundation, com AT&T, Cisco, Docker, IBM, Intel, Red Hat, Twitter, VMware e uma dezena de outros.

O projeto só entrou de fato como hosted project da CNCF em 10 de março de 2016 — o primeiro. Em 6 de março de 2018 foi o primeiro a graduar. Apache 2.0, Go, API declarativa: você descreve o estado desejado; o control loop tenta chegar lá. ReplicaSet, Deployment, Service, Namespace. Depois Job, DaemonSet, StatefulSet, Ingress, CRD.

O que o leme copiou do Borg — e o que não copiou

Pod é a unidade atômica: um ou mais containers que compartilham rede e volume, agendados juntos. No Borg isso já existia. Label e seletor, o Service como VIP estável na frente de Pods que morrem, o kubelet em cada nó, o etcd como fonte da verdade — isso é o desenho. O que o Borg não tinha, e o Kubernetes apostou, foi a API aberta e a extensibilidade: Custom Resource Definition, admission webhook, Container Runtime Interface.

O runtime, aliás, nunca foi “Docker obrigatório”. O dockershim (a ponte que falava com o daemon do Docker) foi marcado como deprecated no 1.20 e removido no 1.24 (maio de 2022). Quem ainda acha que “Kubernetes = Docker” está quatro anos atrasado, na melhor hipótese. CRI-O e containerd falam CRI direto. O Engine do Docker, por baixo, também usa containerd. A história da baleia está no post irmão.

Kubernetes e o Linux: a dívida que ninguém cita

O Kubernetes só existe porque o kernel Linux ganhou, anos antes, as duas primitivas que tornam o container possível — e uma delas saiu do mesmo lugar.

  • Namespaces respondem “o que este processo enxerga?”. O primeiro tipo entrou em 2002 (mount); o conjunto clássico — PID, rede, IPC, UTS, usuário — só fechou em 2013, com o user namespace no kernel 3.8. O cgroup namespace ainda viria em 2016, e o de tempo em 2020.
  • cgroups respondem “o que este processo pode consumir?”. Foram escritos por Paul Menage and Rohit Seth, do Google, a partir de 2006, e entraram na linha principal no kernel 2.6.24, lançado em janeiro de 2008. O nome original era process containers — trocado porque “container” já estava sobrecarregado no ecossistema Linux: Solaris Zones, Linux-VServer, OpenVZ.

Dois engenheiros do Google mexendo em limite de CPU e memória em 2006 não é coincidência: a empresa já rodava tudo em cluster compartilhado, a linhagem que desembocaria no Borg. O mesmo campus que produziu o Borg doou ao kernel a peça que, cinco anos depois, o Docker empacotou e o Kubernetes orquestrou. O leme não inventou isolamento — ele agendou, em escala, um isolamento que o Linux já sabia fazer.

Isso aparece no dia a dia: o limit de um Pod vira cgroup no nó (cpu.max, memory.max) e o request de CPU vira peso de escalonamento (cpu.weight) — o request de memória só vira cgroup com o Memory QoS ligado. O kubelet é um processo comum lendo e escrevendo em /sys/fs/cgroup. E o cgroup v2 (padrão nas distribuições atuais) trouxe o controlador de memória unificado — memory.min, memory.low, memory.high, memory.max —, que freia o workload em vez de só matá-lo no limite. É sob a hierarquia do v2 que o kernel expõe o PSI (pressure stall information, kernel 4.20, dezembro de 2018) por cgroup; o kubelet lê esse sinal de forma estável desde a 1.36. Quem entende o kernel por baixo depura Kubernetes muito mais rápido do que quem só sabe YAML.

2016–2017: a guerra que o Swarm perdeu

Enquanto o leme crescia, a Docker apostou no Swarm como orquestrador nativo — mais simples de aprender, integrado ao produto que todo mundo já tinha instalado. Em 2017 a própria Docker, Inc. jogou a toalha e anunciou suporte a Kubernetes. Mesos, Nomad, Cattle — todos sobreviveram em nicho. O padrão de fato ficou o heptágono. Não porque o YAML seja bonito (não é), mas porque todo provedor de nuvem passou a vender o mesmo objeto: um cluster Kubernetes gerenciado. GKE, EKS, AKS, o OpenShift da Red Hat, o Rancher. A API virou o Linux da nuvem: ninguém ama, todo mundo fala.

2016–2018: o que aconteceu com quem criou

Os três saíram do Google, cada um no seu tempo. Brendan Burns foi para a Microsoft em julho de 2016 e ajudou a construir o Azure Kubernetes Service. Joe Beda já tinha saído em 2015; Craig McLuckie saiu no fim de 2016, e os dois fundaram a Heptio em novembro, em Seattle, para vender Kubernetes para empresa. A VMware anunciou a compra em novembro de 2018 por cerca de US$ 550 milhões e a fechou em dezembro; a Heptio virou um dos pilares do Tanzu — Velero, Sonobuoy, Contour, o TKG. O projeto ficou onde deveria: numa fundação, com governança aberta e centenas de empresas empurrando.

2026: Garhwal, kube-dns e a limpeza do legado

O Kubernetes 1.37.0 saiu em 26 de agosto de 2026, ciclo de 15 semanas, release lead Dipesh Rawat. Apelido Garhwal (गढ़वाल), região himalaia de Uttarakhand. 67 melhorias: 16 estáveis, 23 beta, 27 alpha, uma depreciação. Destaques que importam no cluster de verdade:

  • O Dynamic Resource Allocation fechou o pacote: requisição de recurso estendido via driver, taint and toleration de dispositivo e o atributo resource.kubernetes.io/numaNode viraram Stable. O núcleo do DRA já era GA desde a 1.34 — é ele que tirou GPU, FPGA e dispositivo de IA da gambiarra de Device Plugin.
  • kube-dns está deprecated. CoreDNS é o DNS default desde o 1.13; pacote novo do kube-dns não deve sair depois do 1.40.
  • O modo IPVS do kube-proxy já vinha deprecated desde a 1.35; o caminho é iptables ou, de preferência, nftables — o modo sai de vez na 1.43.
  • HPA scale-to-zero entrou em beta, ligado por default — o autoscale agora pode zerar réplica.
  • Nó em cgroup v1 não sobe mais: o failCgroupV1 do kubelet é true por padrão desde a 1.35. Sem cgroup v2 não há Memory QoS, swap nem métrica de PSI — a dívida com o kernel virou requisito operacional.

As versões em suporte ativo em setembro de 2026 são 1.37, 1.36 e 1.35 — a 1.34 ainda recebe correção até 27 de outubro. A 1.37.1 está marcada para 15 de setembro. O etcd e as implementações de CRI e CNI continuam fora do binário: o leme orquestra; quem roda o container é outro processo.

Experimentar hoje, sem cluster e sem nuvem

Doze anos depois, subir um Kubernetes para estudar é questão de minutos numa máquina só. Três caminhos, do mais descartável ao mais parecido com produção:

# kind — cluster dentro de containers, o mais rápido de jogar fora
kind create cluster --name estudo
kubectl get nodes

# minikube — VM ou container, com addons (dashboard, ingress, registry)
minikube start
minikube addons enable ingress

# k3s — leve, criado pela Rancher (hoje SUSE) e doado à CNCF em 2020; roda de verdade em Raspberry Pi
curl -sfL https://get.k3s.io | sh -
sudo k3s kubectl get nodes

The kind and the minikube são laboratório. O k3s é outra coisa: um binário único, com o etcd trocado por SQLite por padrão (o etcd volta só em HA com vários servidores), usado em borda e em ambiente pequeno de produção. Se a ideia é ter um cluster de verdade num servidor caseiro, comece por ele.

Timeline

  • Meados dos anos 2000 — o Google já roda jobs no Borg, cluster interno que ninguém de fora vê.
  • 2006–2008 — Paul Menage e Rohit Seth, do Google, escrevem os cgroups; a funcionalidade chega ao kernel 2.6.24 em janeiro de 2008.
  • 2013 — o Omega tenta o passo seguinte dentro do Google; lá fora, o Docker torna o container óbvio.
  • 6 de junho de 2014 — primeiro commit público: 250 arquivos, 47.501 linhas.
  • 10 de junho de 2014 — Eric Brewer anuncia o projeto no primeiro DockerCon.
  • 21 de julho de 2015 — Kubernetes 1.0 no OSCON; no mesmo dia nasce a CNCF e o Google anuncia que cederá o controle.
  • 10 de março de 2016 — primeiro projeto hospedado da CNCF.
  • 2016 — Burns vai para a Microsoft; McLuckie e Beda fundam a Heptio.
  • 2017 — a Docker, Inc. anuncia suporte a Kubernetes; a disputa com o Swarm acaba.
  • 6 de março de 2018 — primeiro projeto a graduar na CNCF.
  • Novembro de 2018 — a VMware compra a Heptio por cerca de US$ 550 milhões.
  • Maio de 2022 — o dockershim é removido na versão 1.24; containerd e CRI-O assumem.
  • 26 de agosto de 2026 — 1.37.0 “Garhwal”: kube-dns depreciado, HPA scale-to-zero em beta, DRA completo, cgroup v1 barrado no kubelet.

O que ficou

Três engenheiros no Google Cloud, um runtime de uma máquina, um cluster interno que ninguém via. O resultado é o plano de controle que a indústria copiou. O heptágono na capa é o mesmo de 2014. O YAML, também — para o bem e para o mal.

A baleia que tornou o container óbvio está em A história do Docker. O hipervisor de servidor, em Proxmox and Xen. O kernel embaixo de tudo, em Linux faz 35 anos and A história de Linus Torvalds.

Do Borg ao Garhwal: o timoneiro ainda está no leme. 1.37.0, Apache 2.0, CRI, nftables. Sete raios, doze anos, e o YAML que ninguém gosta de escrever, mas todo mundo commita.