Ao meu ver, uma das maiores qualidades é o que faz o Kubernetes ser
a ferramenta padrão quando se fala de operar infraestrutura em larga escala,
seja ela em um cloud provider ou rodando on premisse é a sua abordagem
na implementação de infraestrutura declarativa. O que faz com que seja usada por organizações
de inúmeros tamanhos e áreas de atuação que desejam entregar uma plataforma de tecnologia
que seja confiável e atenda inúmeros casos de uso
Hoje, no mundo das ferramentas de infraestrutura como código (IaC) existem
duas abordagens principais para a implementação do conceito:
- Infraestrutura Imperativa: Nessa abordagem, é necessário especificar as etapas e comandos exatos para provisionar e orquestrar recursos
- Infraestrutura Declarativa: Ao contrário da forma imperativa, aqui o foco não está em como provisionar e orquestrar mas sim onde o ponto final da infraestrutura
Além disso, para garantir que o estado declarado no arquivo YAML,
ou outra linguagem de configuração, seja mantido ao longo do tempo,
os sistemas de orquestração historicamente adotavam abordagens baseadas em
Polling (varreduras periódicas) ou Edge-Triggered (reação a eventos pontuais):
- Modelo Baseado em Eventos (Edge-Triggered / Polling): O sistema depende da entrega perfeita de notificações de eventos ou de consultas periódicas (polling). Se uma notificação de "falha de Pod" for perdida devido a uma oscilação na rede, a plataforma perde o contexto e a infraestrutura se mantém em um estado inconsistente.
- Modelo Baseado no Estado Atual (Level-Triggered): Em vez de se focar no evento que passou, o Kubernetes se baseia no estado presente. Ele utiliza uma conexão contínua (Watch) para capturar alterações, mas a decisão do que fazer é tomada comparando a foto atual da infraestrutura com o estado desejado.
É exatamente a implementação desse modelo Level-Triggered que chamamos de
Reconciliation Loop.
Durante esse artigo, tentarei explicar o funcionamento dessa abordagem através
de um controller feito com kubebuilder (um framework Go para operator Kubernetes)
que apresenta uma mensagem sempre que um Pod é criado ou deletado
O motor por trás do Loop: Informers, Cache e WorkQue
Para implementar a abordagem Level-Triggered na prática sem sobrecarregar
o kube-apiserver, a biblioteca controller-runtime (base do Kubebuilder)
utiliza uma arquitetura baseada em três pilares fundamentais:
Informer, Cache Local e WorkQueue.
1. Informer: Escutando a API em Tempo Real
Em vez de fazer requisições periódicas (polling) para saber se algo mudou,
o controller utiliza o Informer. Ele estabelece uma conexão HTTP de
streaming de longa duração (Watch) com o apiserver.
No código Go de exemplo, esse registro é feito de forma declarativa dentro
do SetupWithManager:
Watches(&corev1.Pod{}, &handler.EnqueueRequestForObject{})
Sempre que um evento ocorre em um Pod no cluster, o apiserver notifica o
informer em tempo real.
2. Cache Local: Performance e Escalabilidade
Se em cada reconciliação, fosse preciso buscar os dados completos direto no
etcd, o cluster colapsaria em larga escala. Por isso, ao receber uma
notificação, o Informer atualiza um Cache In-Memory mantendo localmente
dentro do processo do controller.
Quando é executada a leitura do recurso dentro da função de reconciliação:
pod := &corev1.Pod{}
err := r.Get(ctx, req.NamespacedName, pod)
Essa consulta não faz uma request ao Kubernetes; ela lê instantaneamente
do cache local mantido pelo Informer.
3. WorkQueue: Garantindo Resiliência e Desduplicação
O Informer não chama a função Reconcile() diretamente. Em vez disso, o
utilitário handler.EnqueueRequestForObject{} extrai apenas os metadados
do recurso - a chave Namespace/Name - e a insere em uma fila de trabalho
(WorkQueue)
A WorkQueue resolve três grandes problemas de engenharia:
- Deduplicação: Se múltiplos eventos do mesmo Pod chegam em um curto espaço de tempo, a chave é inserida uma vez na fila, evitando execuções redundantes.
- Rate Limiting e Backoff: Se a reconciliação falhar, a fila reagenda a tentativa com tempo de espera exponencial (exponential backoff)
- Desacoplamento: O recebimento de eventos e processamento deles rodam de forma assíncrona.
Desmistificando o Reconcile(): O Código na Prática
Com Informer, Cache Local e WorkQueue implementadas no
SetupWithManager, a execução chega no coração de tudo: A função Reconcile().
Diferente de arquiteturas orientadas a eventos tradicionais, o parâmetro
recebido por essa função não contém o Pod inteiro e nem o tipo de evento
que ocorreu (como Create, Update ou Delete). O controller recebe apenas
a chave do recurso através do parâmetro ctrl.Request:
func (r *ExampleReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
log := logf.FromContext(ctx)
A seguir, vamos analisar como cada bloco da função interage com os componentes
internos e onde inspecionar os logs para validar o comportamento em tempo
real
1. Leitura via Cache In-Memory e Tratamento de Exclusão
O ciclo começa obtendo o estado atual do recurso
pod := &corev1.Pod{}
if err := r.Get(ctx, req.NamespacedName, pod); err != nil {
if client.IgnoreNotFound(err) != nil {
return ctrl.Result{}, err
}
log.Info("The pod was deleted", "name", req.Name, "namespace", req.Namespace)
return ctrl.Result{}, nil
}
-
Interação com o Cache: A chamada
r.Get()consulta diretamente o Cache In-Memory mantido pelo Informer -
Caso de Pod Deletado: Se o Pod foi removido do cluster, o Informer
atualiza o cache local. Quando o
r.Get()tenta buscar a chavereq.NamespacedName, ele retorna um erro do tipoNotFound -
Resposta ao WorkQueue: Ao usar
client.IgnoreNotFound(err), o código reconhece que a ausência do recurso é um estado válido final. Após isso, imprime o log e retornactrl.Result{}, nil, sinalizando para a WorkQueue que o item foi processado com sucesso e pode ser removido da fila.
2026-08-19T17:09:45-03:00 INFO The pod was deleted {"controller": "example", "namespace": "default", "name": "nginx", "reconcileID": "69af3331-bdd4-45c6-98dd-88eaf32f2439", "name": "nginx", "namespace": "default"}
2. Avaliação de Estado (Level-Triggered in Action)
Se o recurso foi encontrado no cache, o código prossegue para avaliar o seu
estado atual e tomar decisões
if controllerutil.ContainsFinalizer(pod, "my.domain/finalizer") {
log.Info("Pod was deleted", "name", pod.Name, "namespace", pod.Namespace)
} else {
log.Info("Pod created", "name", pod.Name, "namespace", pod.Namespace)
}
-
Lógica de Inspeção: Como o controller não recebe flags imperativas
(como
isCreate), ele deve deduzir o cenário inspecionando os metadados e oSpec/Statusdo Pod carregado da RAM - Uso de Finalizers: Inspecionar o array de Finalizers permite ao controller identificar se o objeto está em processo de graceful deletion ou se é uma reconciliação comum de criação/autorização
Podemos verificar esse comportamento, rodando o comando abaixo para criação
de um Pod:
kubectl run --image nginx nginx
Que vai gerar a seguinte ocorrência no log do controller
2026-08-19T19:33:07-03:00 INFO Pod created {"controller": "example", "namespace": "default", "name": "nginx", "reconcileID": "88f9cba6-502e-481e-b5a5-c9a01b72d880", "name": "nginx", "namespace": "default"}
Se colocarmos uma label nesse Pod recém criado:
kubectl label pod nginx env=prod
A WorkQueue dispara o Reconcile() novamente
2026-08-19T19:35:53-03:00 INFO Pod created {"controller": "example", "namespace": "default", "name": "nginx", "reconcileID": "55f7aa09-fd82-4905-b169-37b35bd1f908", "name": "nginx", "namespace": "default"}
3. Sinalizando o Fim do Loop para a WorkQueue
A instrução de encerramento do método define como a WorkQueue deve gerenciar aquela chave:
return ctrl.Result, nil
}
O retorno da função Reconcile dita o fluxo da fila de trabalho:
-
ctrl.Result{}, nil: O estado desejado é atingido (ou o recurso não existe mais). A chave é removida da WorkQueue -
ctrl.Result{}, err: Ocorreu uma falha. A WorkQueue retém a chave e reagenda a execução aplicando Exponential Backoff para evitar thundering herd. -
ctrl.Result{RequeueAfter: 10 * time.Second}, nil: Força um re-agendamento periódico (Polling/Health-check), útil quando o controller depende de externos ao Kubernetes.
Conclusão: A "Mágica" do Kubernetes Desmistificada
A capacidade do Kubernetes de manter clusters massivos operando de forma
resiliente não se deve a um passe de mágica, mas sim a elegância do
Reconciliation Loop e do modelo Level-Triggered.
Ao longo desse artigo, vimos que o modelo declarativo é sustentado por
componentes cirurgicamente projetados:
- O Informer reage a eventos sem sobrecarregar a rede com polling.
- O Cache Local In-Memory garante leituras de altíssima performance.
- A WorkQueue desacopla o recebimento de eventos da execução, garantindo resiliência, deduplicação e rate-limiting.
- A função
Reconcile()assume a responsabilidade de comparar o estado atual (Status) com o estado desejado (Spec), agindo até que ambos convirjam.
Entender essa engrenagem é o diferencial entre encarar o Kubernetes como
um "buraco negro de arquivos YAML" e utilizá-lo como a plataforma extensível que
ele realmente é. Quando você domina o funcionamento interno do
controller-runtime, criar seus próprios CRDs e Operators para automatizar
infraestrutura torna-se uma evolução natural na sua jornada de engenharia.













