Manager, Client & Scheme do controller-runtime
Todo operador Go de produção gira em torno de um Manager do controller-runtime que compartilha caches e hooks de ciclo de vida entre reconciliadores, webhooks e endpoints de saúde.
Busque em todas as páginas da documentação
Todo operador Go de produção gira em torno de um Manager do controller-runtime que compartilha caches e hooks de ciclo de vida entre reconciliadores, webhooks e endpoints de saúde.
O Client tipado e o Scheme são os dois objetos que os reconciliadores usam em cada loop.
O Manager inicia caches de informer, expõe GetClient() e GetScheme(), e executa até SIGTERM.
O Client realiza Get/List/Create/Update/Patch/Delete contra objetos Kubernetes, preferindo leituras de cache para tipos observados.
O Scheme registra seus tipos Go de CRD mais os tipos de API principais para que o mapeador REST possa decodificar objetos não estruturados em structs.
A inicialização acontece uma vez em cmd/main.go; os reconciliadores recebem dependências via campos de struct.
Cartão de receita de referência rápida - pronto para copiar e colar.
mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{
Scheme: scheme,
Metrics: metricsserver.Options{BindAddress: ":8080"},
HealthProbeBindAddress: ":8081",
LeaderElection: true,
LeaderElectionID: "guestbook.example.com",
})Quando usar isso:
package main
import (
"os"
appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/runtime"
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
clientgoscheme "k8s.io/client-go/kubernetes/scheme"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/healthz"
metricsserver "sigs.k8s.io/controller-runtime/pkg/metrics/server"
webappv1 "example.com/guestbook-operator/api/v1"
"example.com/guestbook-operator/internal/controller"
)
var scheme = runtime.NewScheme()
func init() {
utilruntime.Must(clientgoscheme.AddToScheme(scheme))
utilruntime.Must(appsv1.AddToScheme(scheme))
utilruntime.Must(corev1.AddToScheme(scheme))
utilruntime.Must(webappv1.AddToScheme(scheme))
}
func main() {
mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{
Scheme: scheme,
Metrics: metricsserver.Options{BindAddress: "0"},
HealthProbeBindAddress: "0",
LeaderElection: false, // true em produção
LeaderElectionID: "guestbook.example.com",
})
if err != nil {
panic(err)
}
if err := (&controller.GuestbookReconciler{
Client: mgr.GetClient(),
Scheme: mgr.GetScheme(),
}).SetupWithManager(mgr); err != nil {
panic(err)
}
if err := mgr.AddHealthzCheck("healthz", healthz.Ping); err != nil {
panic(err)
}
if err := mgr.AddReadyzCheck("readyz", healthz.Ping); err != nil {
panic(err)
}
if err := mgr.Start(ctrl.SetupSignalHandler()); err != nil {
os.Exit(1)
}
}O que isso demonstra:
init() registra tipos de API embutidos e personalizados em um Scheme compartilhadoclient-go brutosmgr.Start bloqueia até SIGINT/SIGTERM via SetupSignalHandlerAddToScheme vincula cada tipo Go ao seu GroupVersionKind para decodificar watches e listas.SetupWithManager em um reconciliador registra For(), Owns() e Watches() com o construtor de controller do Manager.Guestbook para webapp.example.com/v1, Kind=Guestbook para chamadas de API genéricas.| Opção | Propósito |
|---|---|
Scheme | Tipos que o Manager pode decodificar |
Metrics.BindAddress | Endpoint de scrape do Prometheus (:8080) |
HealthProbeBindAddress | /healthz e /readyz para sondas kube |
LeaderElection | Réplica ativa única quando replicas > 1 |
LeaderElectionID | Nome do objeto Lease na API de coordenação |
Cache.DefaultNamespaces | Restringe informers a namespaces listados |
| Operação | Client do controller-runtime | Notas |
|---|---|---|
Get / List | Baseado em cache para tipos observados | Rápido, consistentemente eventual |
Create / Update / Patch / Delete | API direta | Consistência forte |
Status().Update | Escrita de subrecurso | Requer subrecurso de status no CRD |
// Use APIReader quando precisar contornar o cache (leituras críticas de consistência)
apiReader := mgr.GetAPIReader()
// Operadores com escopo de namespace: restrinja o cache nas opções do Manager
ctrl.Options{
Cache: cache.Options{
DefaultNamespaces: map[string]cache.Config{
"tenant-a": {},
},
},
}AddToScheme para seu tipo CRD - Get de reconciliação falha com "nenhum kind registrado". Correção: chame webappv1.AddToScheme(scheme) em init().mgr.GetCache().WaitForCacheSync(ctx).LeaderElection em Deployments de produção.:8080 sem atualizar os monitores de Serviço - Prometheus perde os scrapes. Correção: alinhe BindAddress com as portas de Serviço do chart e NetworkPolicy.client.Client novo para os reconciliadores - contorna o cache compartilhado e duplica informers. Correção: sempre use mgr.GetClient().| Alternativa | Usar Quando | Não Usar Quando |
|---|---|---|
| Manager do controller-runtime | Operadores kubebuilder padrão | Você precisa apenas de um CLI one-shot contra a API |
| Informers brutos do client-go | Controle máximo sobre a fiação do informer | Você quer webhooks, métricas e eleição de líder integrados |
| Cliente dinâmico do client-go | Controladores genéricos sem tipos Go | Você tem APIs tipadas geradas e subrecursos de status |
| Operator SDK (Java) | Equipes padronizadas em JVM | Você quer codegen do kubebuilder e envtest |
Ele inicia caches de informer compartilhados, registra controllers e webhooks, serve métricas e verificações de saúde, e bloqueia em Start até o desligamento.
Todos os reconciliadores no processo compartilham um cache.
Testes podem substituir um cliente falso.
Produção usa o cliente do Manager com cache sem que cada controller abra seus próprios informers.
Quando você não pode tolerar leituras de cache desatualizadas, como imediatamente após criar um objeto fora do caminho de observação.
A maioria das reconciliações deve usar o cliente de cache.
Ele nomeia o objeto Lease ou ConfigMap de bloqueio na API coordination.k8s.io.
Todas as réplicas devem usar o mesmo ID para eleger um líder.
Defina Cache.DefaultNamespaces nas opções do Manager e escopo os RoleBindings RBAC para esse namespace.
Você deve chamar clientgoscheme.AddToScheme e adicionar quaisquer grupos de API que referencie (apps, core, networking, seus CRDs).
Sim.
Esse é o layout padrão do kubebuilder: um main.go, muitas chamadas SetupWithManager.
SetupSignalHandler cancela o contexto do Manager, drena workers e libera leases de eleição de líder.
metricsserver.Options vincula manipuladores Prometheus no servidor HTTP do Manager ao lado das sondas de saúde.
O Manager o constrói a partir da descoberta e do seu Scheme.
Você raramente o toca, a menos que esteja escrevendo controllers genéricos sobre GVKs arbitrários.
Versões da Stack: Esta página foi escrita para Go 1.26.x (GC padrão Green Tea, go fix modernizers - verifique o patch na compilação), chi (última - verifique na compilação), gin (última - verifique na compilação), echo (última - verifique na compilação), google.golang.org/grpc (última - verifique na compilação), sigs.k8s.io/controller-runtime (última - verifique na compilação), kubebuilder (última - verifique na compilação), tinygo (última - verifique os alvos de placa na compilação), wazero (última - verifique na compilação) e golangci-lint (última - verifique o conjunto de linters na compilação).
Revisado por Chris St. John·Última atualização: 16 de jul. de 2026