Manager, Client y Scheme de controller-runtime
Cada operador Go de producción se centra en un Manager de controller-runtime que comparte cachés y hooks de ciclo de vida entre reconciliadores, webhooks y endpoints de salud.
Busca en todas las páginas de la documentación
Cada operador Go de producción se centra en un Manager de controller-runtime que comparte cachés y hooks de ciclo de vida entre reconciliadores, webhooks y endpoints de salud.
El Client tipado y el Scheme son los dos objetos que los reconciliadores usan en cada bucle.
El Manager inicia cachés de informadores, expone GetClient() y GetScheme(), y se ejecuta hasta SIGTERM.
El Client realiza Get/List/Create/Update/Patch/Delete contra objetos de Kubernetes, prefiriendo lecturas de caché para tipos observados.
El Scheme registra tus tipos Go de CRD más los tipos de API principales para que el mapeador REST pueda decodificar objetos no estructurados en structs.
El arranque ocurre una vez en cmd/main.go; los reconciliadores reciben dependencias a través de campos de struct.
Tarjeta de receta de referencia rápida, lista para copiar y pegar.
mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{
Scheme: scheme,
Metrics: metricsserver.Options{BindAddress: ":8080"},
HealthProbeBindAddress: ":8081",
LeaderElection: true,
LeaderElectionID: "guestbook.example.com",
})Cuándo usar esto:
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 en producción
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)
}
}Lo que esto demuestra:
init() registra tipos de API integrados y personalizados en un Scheme compartido.client-go crudos.mgr.Start se bloquea hasta SIGINT/SIGTERM a través de SetupSignalHandler.AddToScheme vincula cada tipo Go a su GroupVersionKind para decodificar watches y listas.SetupWithManager en un reconciliador registra For(), Owns() y Watches() con el constructor de controladores del Manager.Guestbook a webapp.example.com/v1, Kind=Guestbook para llamadas genéricas a la API.| Opción | Propósito |
|---|---|
Scheme | Tipos que el Manager puede decodificar |
Metrics.BindAddress | Endpoint de scrapeo de Prometheus (:8080) |
HealthProbeBindAddress | /healthz y /readyz para sondeos de kube |
LeaderElection | Una réplica activa cuando replicas > 1 |
LeaderElectionID | Nombre del objeto Lease en la API de coordinación |
Cache.DefaultNamespaces | Restringe los informadores a los namespaces listados |
| Operación | Client de controller-runtime | Notas |
|---|---|---|
Get / List | Basado en caché para tipos observados | Rápido, consistentemente eventual |
Create / Update / Patch / Delete | API directa | Fuerte consistencia |
Status().Update | Escritura de subrecurso | Requiere subrecurso de estado en CRD |
// Usa APIReader cuando debas omitir la caché (lecturas críticas de consistencia)
apiReader := mgr.GetAPIReader()
// Operadores con ámbito de namespace: restringe la caché en las opciones del Manager
ctrl.Options{
Cache: cache.Options{
DefaultNamespaces: map[string]cache.Config{
"tenant-a": {},
},
},
}AddToScheme para tu tipo CRD - Get de reconciliación falla con "no kind is registered". Solución: llama a webappv1.AddToScheme(scheme) en init().mgr.GetCache().WaitForCacheSync(ctx).LeaderElection en despliegues de producción.:8080 sin actualizar los monitores de Servicio - Prometheus no realiza scrapeos. Solución: alinea BindAddress con los puertos de Servicio del chart y NetworkPolicy.client.Client nuevo a los reconciliadores - omite la caché compartida y duplica informadores. Solución: usa siempre mgr.GetClient().| Alternativa | Usar Cuando | No Usar Cuando |
|---|---|---|
| Manager de controller-runtime | Operadores estándar de kubebuilder | Solo necesitas una CLI de un solo uso contra la API |
| Informadores crudos de client-go | Máximo control sobre la configuración de informadores | Quieres webhooks, métricas y elección de líder integrados |
| Cliente dinámico de client-go | Controladores genéricos sin tipos Go | Tienes APIs tipadas generadas y subrecursos de estado |
| Operator SDK (Java) | Equipos estandarizados en JVM | Quieres la generación de código de kubebuilder y envtest |
Inicia cachés de informadores compartidos, registra controladores y webhooks, sirve métricas y comprobaciones de salud, y se bloquea en Start hasta el apagado.
Todos los reconciliadores en el proceso comparten una caché.
Las pruebas pueden sustituir un cliente falso.
La producción usa el cliente del Manager basado en caché sin que cada controlador abra sus propios informadores.
Cuando no puedes tolerar lecturas de caché obsoletas, como inmediatamente después de crear un objeto fuera de la ruta de observación.
La mayoría de las reconciliaciones deberían usar el cliente de caché.
Nombra el objeto Lease o ConfigMap de bloqueo en la API coordination.k8s.io.
Todas las réplicas deben usar el mismo ID para elegir un líder.
Establece Cache.DefaultNamespaces en las opciones del Manager y limita los RoleBindings de RBAC a ese namespace.
Debes llamar a clientgoscheme.AddToScheme y agregar cualquier grupo de API que referencies (apps, core, networking, tus CRDs).
Sí.
Ese es el diseño predeterminado de kubebuilder: un main.go, muchas llamadas a SetupWithManager.
SetupSignalHandler cancela el contexto del Manager, vacía los workers y libera los leases de elección de líder.
metricsserver.Options vincula los manejadores de Prometheus en el servidor HTTP del Manager junto con las comprobaciones de salud.
El Manager lo construye a partir del descubrimiento y tu Scheme.
Rara vez lo tocas a menos que escribas controladores genéricos sobre GVKs arbitrarios.
Versiones de Stack: Esta página fue escrita para Go 1.26.x (predeterminado de GC Green Tea, go fix modernizers - verificar parche en la compilación), chi (última - verificar en la compilación), gin (última - verificar en la compilación), echo (última - verificar en la compilación), google.golang.org/grpc (última - verificar en la compilación), sigs.k8s.io/controller-runtime (última - verificar en la compilación), kubebuilder (última - verificar en la compilación), tinygo (últimos objetivos de placa de verificación en la compilación), wazero (última - verificar en la compilación) y golangci-lint (último conjunto de linters de verificación en la compilación).
Revisado por Chris St. John·Última actualización: 16 jul 2026