Operators and CRD scope with Operator SDK

Overview

A namespace-scoped operator watches and manages resources in a single namespace, whereas a cluster-scoped operator watches and manages resources cluster-wide. Namespace-scoped operators are preferred because of their flexibility. They enable decoupled upgrades, namespace isolation for failures and monitoring, and differing API definitions.

However, there are use cases where a cluster-scoped operator may make sense. For example, the cert-manager operator is often deployed with cluster-scoped permissions and watches so that it can manage issuing certificates for an entire cluster.

NOTE: CustomResourceDefinition (CRD) scope can also be changed to cluster-scoped. See the CRD scope document for more details.

Namespace-scoped operator usage

This scope is ideal for operator projects which will control resources just in one namespace, which is where the operator is deployed.

NOTE: Projects created by operator-sdk are namespace-scoped by default which means that they will NOT have a ClusterRole defined in deploy/.

Cluster-scoped operator usage

This scope is ideal for operator projects which will control resources in more than one namespace.

Changes required for a cluster-scoped operator

The SDK scaffolds operators to be namespaced by default but with a few modifications to the default manifests the operator can be run as cluster-scoped.

  • deploy/operator.yaml:
    • Set WATCH_NAMESPACE="" to watch all namespaces instead of setting it to the pod’s namespace
    • Set metadata.namespace to define the namespace where the operator will be deployed.
  • deploy/role.yaml:
    • Use ClusterRole instead of Role
  • deploy/role_binding.yaml:
    • Use ClusterRoleBinding instead of RoleBinding
    • Use ClusterRole instead of Role for roleRef
    • Set the subject namespace to the namespace in which the operator is deployed.
  • deploy/service_account.yaml:
    • Set metadata.namespace to the namespace where the operator is deployed.

Example for cluster-scoped operator

With the above changes the specified manifests should look as follows:

  • deploy/operator.yaml:

    1. apiVersion: apps/v1
    2. kind: Deployment
    3. metadata:
    4. name: memcached-operator
    5. namespace: <operator-namespace>
    6. ...
    7. spec:
    8. ...
    9. template:
    10. ...
    11. spec:
    12. ...
    13. serviceAccountName: memcached-operator
    14. containers:
    15. - name: memcached-operator
    16. ...
    17. env:
    18. - name: WATCH_NAMESPACE
    19. value: ""
  • deploy/role.yaml:

    1. apiVersion: rbac.authorization.k8s.io/v1
    2. kind: ClusterRole
    3. metadata:
    4. name: memcached-operator
    5. ...
  • deploy/role_binding.yaml:

    1. kind: ClusterRoleBinding
    2. apiVersion: rbac.authorization.k8s.io/v1
    3. metadata:
    4. name: memcached-operator
    5. subjects:
    6. - kind: ServiceAccount
    7. name: memcached-operator
    8. namespace: <operator-namespace>
    9. roleRef:
    10. kind: ClusterRole
    11. name: memcached-operator
    12. apiGroup: rbac.authorization.k8s.io
  • deploy/service_account.yaml

    1. apiVersion: v1
    2. kind: ServiceAccount
    3. metadata:
    4. name: memcached-operator
    5. namespace: <operator-namespace>

Last modified May 26, 2020: doc: add operator-scope kb layout (#2982) (795c8b58)