CRD scope with Operator SDK

Overview

The CustomResourceDefinition (CRD) scope can also be changed for cluster-scoped operators so that there is only a single instance (for a given name) of the CRD to manage across the cluster.

NOTE: Cluster-scoped CRDs are NOT supported with the Helm operator. While Helm releases can create cluster-scoped resources, Helm’s design requires the release itself to be created in a specific namespace. Since the Helm operator uses a 1-to-1 mapping between a CR and a Helm release, Helm’s namespace-scoped release requirement extends to Helm operator’s namespace-scoped CR requirement.

For each CRD that needs to be cluster-scoped, update its manifest to be cluster-scoped.

  • deploy/crds/<full group>_<resource>_crd.yaml
    • Set spec.scope: Cluster

To ensure that the CRD is always generated with scope: Cluster, add the marker // +kubebuilder:resource:path=<resource>,scope=Cluster, or if already present replace scope={Namespaced -> Cluster}, above the CRD’s Go type definition in pkg/apis/<group>/<version>/<kind>_types.go. Note that the <resource> element must be the same lower-case plural value of the CRD’s Kind, spec.names.plural.

CRD cluster-scoped usage

A cluster scope is ideal for operators that manage custom resources (CR’s) that can be created in more than one namespace in a cluster.

NOTE: When a Manager instance is created in the main.go file, it receives the namespace(s) as Options. These namespace(s) should be watched and cached for the Client which is provided by the Controllers. Only clients provided by cluster-scoped projects where the Namespace attribute is "" will be able to manage cluster-scoped CRD’s. For more information see the Manager topic in the user guide and the Manager Options.

Example for changing the CRD scope from Namespaced to Cluster

The following example is for Go based-operators. scope: Cluster must set manually for Helm and Ansible based-operators.

  • Check the spec.names.plural in the CRD’s Kind YAML file
  • deploy/crds/cache_v1alpha1_memcached_crd.yaml
    apiVersion: apiextensions.k8s.io/v1beta1
    kind: CustomResourceDefinition
    metadata:
      name: memcacheds.cache.example.com
    spec:
      group: cache.example.com
      names:
        kind: Memcached
        listKind: MemcachedList
        plural: memcacheds
        singular: memcached
      scope: Namespaced
    
  • Update the pkg/apis/<group>/<version>/<kind>_types.go by adding the marker // +kubebuilder:resource:path=<resource>,scope=Cluster
  • pkg/apis/cache/v1alpha1/memcached_types.go
    // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
    
    // Memcached is the Schema for the memcacheds API
    // +kubebuilder:resource:path=memcacheds,scope=Cluster
    type Memcached struct {
      metav1.TypeMeta   `json:",inline"`
      metav1.ObjectMeta `json:"metadata,omitempty"`
    
      Spec   MemcachedSpec   `json:"spec,omitempty"`
      Status MemcachedStatus `json:"status,omitempty"`
    }
    
  • Execute the command operator-sdk generate crds, then you should be able to check that the CRD was updated with the cluster scope as in the following example:
  • deploy/crds/cache.example.com_memcacheds_crd.yaml
    apiVersion: apiextensions.k8s.io/v1beta1
    kind: CustomResourceDefinition
    metadata:
      name: memcacheds.cache.example.com
    spec:
      group: cache.example.com
      ...
      scope: Cluster