Manager Scope
Manager scope determines which namespace(s) your manager watches and manages resources in.
Overview
Kubebuilder supports three types of manager scope:
| Scope | Description | Use Case |
|---|---|---|
| Cluster-scoped (default) | Watches all namespaces in the cluster | Single manager managing resources cluster-wide |
| Namespace-scoped | Watches only specific namespace(s) | Multi-tenant, least-privilege deployments |
| Multi-namespace | Watches multiple specific namespaces | Manager managing resources in subset of namespaces |
Manager scope is configured through:
- RBAC resources (Role vs ClusterRole)
- Cache configuration in
cmd/main.go WATCH_NAMESPACEenvironment variable
Cluster-Scoped (Default)
By default, Kubebuilder scaffolds cluster-scoped managers that watch all namespaces in the cluster.
kubebuilder init --domain example.com
Characteristics:
- Uses
ClusterRoleandClusterRoleBindingfor RBAC - Manager watches all namespaces
- No cache configuration needed
When to use:
- Single manager instance for the entire cluster
- Managing cluster-scoped resources (Nodes, ClusterRoles, Namespaces)
- Simpler RBAC model when cluster-wide access is acceptable
Namespace-Scoped
Namespace-scoped managers watch only specific namespace(s), configured via the WATCH_NAMESPACE environment variable.
# New projects
kubebuilder init --domain example.com --namespaced
# Existing projects
kubebuilder edit --namespaced=true
Characteristics:
- Uses namespace-scoped
RoleandRoleBindingfor RBAC - Manager watches only specified namespace(s)
- Requires cache configuration in
cmd/main.go - Requires
namespace=parameter in controller RBAC markers
When to use:
- Multi-tenant environments (one manager per tenant/namespace)
- Security policies requiring least-privilege access
- Multiple manager instances in different namespaces
RBAC markers:
Controllers in namespace-scoped projects use the namespace= parameter in RBAC markers to generate namespace-scoped Role resources:
// +kubebuilder:rbac:groups=myapp.example.com,namespace=myproject-system,resources=mykinds,verbs=get;list;watch;create;update;patch;delete
// +kubebuilder:rbac:groups=myapp.example.com,namespace=myproject-system,resources=mykinds/status,verbs=get;update;patch
// +kubebuilder:rbac:groups=myapp.example.com,namespace=myproject-system,resources=mykinds/finalizers,verbs=update
When controller-gen sees the namespace= parameter, it generates kind: Role instead of kind: ClusterRole. The namespace field is added by kustomize during the build process (configured in config/default/kustomization.yaml).
Cache configuration:
Kubebuilder automatically scaffolds the cache configuration in cmd/main.go when using --namespaced flag:
// setupCacheNamespaces configures the cache to watch specific namespace(s).
// It supports both single namespace ("ns1") and multi-namespace ("ns1,ns2,ns3") formats.
func setupCacheNamespaces(namespaces string) cache.Options {
defaultNamespaces := make(map[string]cache.Config)
for ns := range strings.SplitSeq(namespaces, ",") {
defaultNamespaces[strings.TrimSpace(ns)] = cache.Config{}
}
return cache.Options{
DefaultNamespaces: defaultNamespaces,
}
}
// In main()
watchNamespace, err := getWatchNamespace()
if err != nil {
setupLog.Error(err, "Unable to get WATCH_NAMESPACE")
os.Exit(1)
}
mgrOptions := ctrl.Options{
Scheme: scheme,
Metrics: metricsServerOptions,
WebhookServer: webhookServer,
HealthProbeBindAddress: probeAddr,
LeaderElection: enableLeaderElection,
LeaderElectionID: "your-leader-election-id",
}
// Configure cache to watch namespace(s) specified in WATCH_NAMESPACE
mgrOptions.Cache = setupCacheNamespaces(watchNamespace)
setupLog.Info("Watching namespace(s)", "namespaces", watchNamespace)
mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), mgrOptions)
This configuration works for both single namespace (WATCH_NAMESPACE=my-namespace) and multi-namespace (WATCH_NAMESPACE=ns1,ns2,ns3) scenarios.
Multi-Namespace
Managers can watch multiple specific namespaces using comma-separated values in WATCH_NAMESPACE.
Characteristics:
- Requires
RoleandRoleBindingin each watched namespace - Uses the same
setupCacheNamespaceshelper function - Same code as single-namespace mode (KISS principle)
Example:
# Deploy manager to watch multiple namespaces
export WATCH_NAMESPACE=namespace1,namespace2,namespace3
kubectl apply -f dist/install.yaml
The setupCacheNamespaces helper function automatically handles both single and multiple namespaces without conditional logic.
See Also
- Understanding Scopes - Overview of manager and CRD scopes
- CRD Scope - Configuring CustomResourceDefinition scope
- Namespace-Scoped Migration - Detailed implementation guide
- Project Config - PROJECT file configuration