<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Operator SDK – Go</title>
    <link>/docs/building-operators/golang/</link>
    <description>Recent content in Go on Operator SDK</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>en-us</language>
    
	  <atom:link href="/docs/building-operators/golang/index.xml" rel="self" type="application/rss+xml" />
    
    
      
        
      
    
    
    <item>
      <title>Docs: Installation Guide</title>
      <link>/docs/building-operators/golang/installation/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      
      <guid>/docs/building-operators/golang/installation/</guid>
      <description>
        
        
        &lt;h2 id=&#34;install-operator-sdk&#34;&gt;Install &lt;code&gt;operator-sdk&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;Follow the steps in the &lt;a href=&#34;/docs/installation/&#34;&gt;installation guide&lt;/a&gt; to learn how to install the &lt;code&gt;operator-sdk&lt;/code&gt; CLI tool.&lt;/p&gt;
&lt;h2 id=&#34;additional-prerequisites&#34;&gt;Additional Prerequisites&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://git-scm.com/downloads&#34;&gt;git&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://golang.org/dl/&#34;&gt;go&lt;/a&gt; version 1.22&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://docs.docker.com/install/&#34;&gt;docker&lt;/a&gt; version 17.03+.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://kubernetes.io/docs/tasks/tools/install-kubectl/&#34;&gt;kubectl&lt;/a&gt; and access to a Kubernetes cluster of a &lt;a href=&#34;/docs/overview#kubernetes-version-compatibility&#34;&gt;compatible version&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

      </description>
    </item>
    
    <item>
      <title>Docs: Quickstart for Go-based Operators</title>
      <link>/docs/building-operators/golang/quickstart/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      
      <guid>/docs/building-operators/golang/quickstart/</guid>
      <description>
        
        
        &lt;p&gt;This guide walks through an example of building a simple memcached-operator using tools and libraries provided by the Operator SDK.&lt;/p&gt;
&lt;h2 id=&#34;prerequisites&#34;&gt;Prerequisites&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Go through the &lt;a href=&#34;/docs/building-operators/golang/installation&#34;&gt;installation guide&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Make sure your user is authorized with &lt;code&gt;cluster-admin&lt;/code&gt; permissions.&lt;/li&gt;
&lt;li&gt;An accessible image registry for various operator images (ex. &lt;a href=&#34;https://hub.docker.com/signup&#34;&gt;hub.docker.com&lt;/a&gt;,
&lt;a href=&#34;https://quay.io/&#34;&gt;quay.io&lt;/a&gt;) and be logged in to your command line environment.
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;example.com&lt;/code&gt; is used as the registry Docker Hub namespace in these examples.
Replace it with another value if using a different registry or namespace.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;/docs/olm-integration/cli-overview#private-bundle-and-catalog-image-registries&#34;&gt;Authentication and certificates&lt;/a&gt; if the registry is private or uses a custom CA.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;steps&#34;&gt;Steps&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Create a project directory for your project and initialize the project:&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;mkdir memcached-operator
&lt;span style=&#34;color:#204a87&#34;&gt;cd&lt;/span&gt; memcached-operator
operator-sdk init --domain example.com --repo github.com/example/memcached-operator
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt; If your local environment is Apple Silicon (&lt;code&gt;darwin/arm64&lt;/code&gt;) use the &lt;code&gt;go/v4&lt;/code&gt;
plugin which provides support for this platform by adding to the init subCommand the flag &lt;code&gt;--plugins=go/v4&lt;/code&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Create a simple Memcached API:&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;operator-sdk create api --group cache --version v1alpha1 --kind Memcached --resource --controller
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ol&gt;
&lt;li&gt;Build and push your operator&amp;rsquo;s image:&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;make docker-build docker-push &lt;span style=&#34;color:#000&#34;&gt;IMG&lt;/span&gt;&lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#4e9a06&#34;&gt;&amp;#34;example.com/memcached-operator:v0.0.1&amp;#34;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;olm-deployment&#34;&gt;OLM deployment&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;Install &lt;a href=&#34;/docs/olm-integration/tutorial-bundle/#enabling-olm&#34;&gt;OLM&lt;/a&gt;:&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;operator-sdk olm install
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ol&gt;
&lt;li&gt;Bundle your operator, then build and push the bundle image (defaults to &lt;code&gt;example.com/memcached-operator-bundle:v0.0.1&lt;/code&gt;):&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;make bundle &lt;span style=&#34;color:#000&#34;&gt;IMG&lt;/span&gt;&lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#4e9a06&#34;&gt;&amp;#34;example.com/memcached-operator:v0.0.1&amp;#34;&lt;/span&gt;
make bundle-build bundle-push &lt;span style=&#34;color:#000&#34;&gt;BUNDLE_IMG&lt;/span&gt;&lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#4e9a06&#34;&gt;&amp;#34;example.com/memcached-operator-bundle:v0.0.1&amp;#34;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ol&gt;
&lt;li&gt;Run your bundle. If your bundle image is hosted in a registry that is private and/or
has a custom CA, these &lt;a href=&#34;/docs/olm-integration/cli-overview#private-bundle-and-catalog-image-registries&#34;&gt;configuration steps&lt;/a&gt; must be complete.&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;operator-sdk run bundle &amp;lt;some-registry&amp;gt;/memcached-operator-bundle:v0.0.1
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ol&gt;
&lt;li&gt;Create a sample Memcached custom resource:&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code class=&#34;language-console&#34; data-lang=&#34;console&#34;&gt;$ kubectl apply -f config/samples/cache_v1alpha1_memcached.yaml
memcached.cache.example.com/memcached-sample created
&lt;/code&gt;&lt;/pre&gt;&lt;ol&gt;
&lt;li&gt;Uninstall the operator:&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;operator-sdk cleanup memcached-operator
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;direct-deployment&#34;&gt;Direct deployment&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;Deploy your operator:&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;make deploy &lt;span style=&#34;color:#000&#34;&gt;IMG&lt;/span&gt;&lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#4e9a06&#34;&gt;&amp;#34;example.com/memcached-operator:v0.0.1&amp;#34;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ol&gt;
&lt;li&gt;Create a sample Memcached custom resource:&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code class=&#34;language-console&#34; data-lang=&#34;console&#34;&gt;$ kubectl apply -f config/samples/cache_v1alpha1_memcached.yaml
memcached.cache.example.com/memcached-sample created
&lt;/code&gt;&lt;/pre&gt;&lt;ol&gt;
&lt;li&gt;Uninstall the operator:&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;make undeploy
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;run-locally-outside-the-cluster&#34;&gt;Run locally (outside the cluster)&lt;/h3&gt;
&lt;p&gt;This is recommended ONLY for development purposes&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Run the operator:&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;make install run
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ol&gt;
&lt;li&gt;In a new terminal tab/window, create a sample Memcached custom resource:&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code class=&#34;language-console&#34; data-lang=&#34;console&#34;&gt;$ kubectl apply -f config/samples/cache_v1alpha1_memcached.yaml
memcached.cache.example.com/memcached-sample created
&lt;/code&gt;&lt;/pre&gt;&lt;ol&gt;
&lt;li&gt;Stop the operator by pressing &lt;code&gt;ctrl+c&lt;/code&gt; in the terminal tab or window the operator is running in&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;next-steps&#34;&gt;Next Steps&lt;/h2&gt;
&lt;p&gt;Read the &lt;a href=&#34;/docs/building-operators/golang/tutorial/&#34;&gt;full tutorial&lt;/a&gt; for an in-depth walkthrough of building a Go operator.&lt;/p&gt;

      </description>
    </item>
    
    <item>
      <title>Docs: Go Operator Tutorial</title>
      <link>/docs/building-operators/golang/tutorial/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      
      <guid>/docs/building-operators/golang/tutorial/</guid>
      <description>
        
        
        &lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; If your project was created with an &lt;code&gt;operator-sdk&lt;/code&gt; version prior to &lt;code&gt;v1.0.0&lt;/code&gt;
please &lt;a href=&#34;/docs/building-operators/golang/migration&#34;&gt;migrate&lt;/a&gt;, or consult the &lt;a href=&#34;https://github.com/operator-framework/operator-sdk/blob/v0.19.x/website/content/en/docs/golang/legacy/quickstart.md&#34;&gt;legacy docs&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&#34;prerequisites&#34;&gt;Prerequisites&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Go through the &lt;a href=&#34;/docs/building-operators/golang/installation&#34;&gt;installation guide&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Make sure your user is authorized with &lt;code&gt;cluster-admin&lt;/code&gt; permissions.&lt;/li&gt;
&lt;li&gt;An accessible image registry for various operator images (ex. &lt;a href=&#34;https://hub.docker.com/signup&#34;&gt;hub.docker.com&lt;/a&gt;,
&lt;a href=&#34;https://quay.io/&#34;&gt;quay.io&lt;/a&gt;) and be logged in to your command line environment.
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;example.com&lt;/code&gt; is used as the registry Docker Hub namespace in these examples.
Replace it with another value if using a different registry or namespace.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;/docs/olm-integration/cli-overview#private-bundle-and-catalog-image-registries&#34;&gt;Authentication and certificates&lt;/a&gt; if the registry is private or uses a custom CA.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;overview&#34;&gt;Overview&lt;/h2&gt;
&lt;p&gt;We will create a sample project to let you know how it works and this sample will:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Create a Memcached Deployment if it doesn&amp;rsquo;t exist&lt;/li&gt;
&lt;li&gt;Ensure that the Deployment size is the same as specified by the Memcached CR spec&lt;/li&gt;
&lt;li&gt;Update the Memcached CR status using the status writer with the names of the CR&amp;rsquo;s pods&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;create-a-new-project&#34;&gt;Create a new project&lt;/h2&gt;
&lt;p&gt;Use the CLI to create a new memcached-operator project:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;mkdir -p &lt;span style=&#34;color:#000&#34;&gt;$HOME&lt;/span&gt;/projects/memcached-operator
&lt;span style=&#34;color:#204a87&#34;&gt;cd&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;$HOME&lt;/span&gt;/projects/memcached-operator
&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;# we&amp;#39;ll use a domain of example.com&lt;/span&gt;
&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;# so all API groups will be &amp;lt;group&amp;gt;.example.com&lt;/span&gt;
operator-sdk init --domain example.com --repo github.com/example/memcached-operator
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;--domain&lt;/code&gt; will be used as the prefix of the API group your custom resources will be created in.
API groups are a mechanism to group portions of the Kubernetes API. You&amp;rsquo;re probably already familiar with
some of the core Kubernetes API groups, such as &lt;code&gt;apps&lt;/code&gt; or &lt;code&gt;rbac.authorization.k8s.io&lt;/code&gt;. API groups are used
internally to version your Kubernetes resources and are thus used for many things. Importantly, you should
name your domain to group your resource types in meaningful group(s) for ease of understanding and because these
groups determine how access can be controlled to your resource types using RBAC. For more information, see &lt;a href=&#34;https://kubernetes.io/docs/reference/using-api/#api-groups&#34;&gt;the core Kubernetes docs&lt;/a&gt; and &lt;a href=&#34;https://book.kubebuilder.io/cronjob-tutorial/gvks.html&#34;&gt;the Kubebuilder docs&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt; If your local environment is Apple Silicon (&lt;code&gt;darwin/arm64&lt;/code&gt;) use the &lt;code&gt;go/v4&lt;/code&gt;
plugin which provides support for this platform by adding to the init subCommand the flag &lt;code&gt;--plugins=go/v4&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;To learn about the project directory structure, see &lt;a href=&#34;https://book.kubebuilder.io/cronjob-tutorial/basic-project.html&#34;&gt;Kubebuilder project layout&lt;/a&gt; doc.&lt;/p&gt;
&lt;h4 id=&#34;a-note-on-dependency-management&#34;&gt;A note on dependency management&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;operator-sdk init&lt;/code&gt; generates a &lt;code&gt;go.mod&lt;/code&gt; file to be used with &lt;a href=&#34;https://github.com/golang/go/wiki/Modules&#34;&gt;Go modules&lt;/a&gt;. The &lt;code&gt;--repo=&amp;lt;path&amp;gt;&lt;/code&gt; flag is required when creating a project outside of &lt;code&gt;$GOPATH/src&lt;/code&gt;, as scaffolded files require a valid module path. Ensure you &lt;a href=&#34;https://github.com/golang/go/wiki/Modules#how-to-install-and-activate-module-support&#34;&gt;activate module support&lt;/a&gt; by running &lt;code&gt;export GO111MODULE=on&lt;/code&gt; before using the SDK.&lt;/p&gt;
&lt;h3 id=&#34;manager&#34;&gt;Manager&lt;/h3&gt;
&lt;p&gt;The main program for the operator &lt;code&gt;main.go&lt;/code&gt; initializes and runs the &lt;a href=&#34;https://pkg.go.dev/sigs.k8s.io/controller-runtime/pkg/manager#Manager&#34;&gt;Manager&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;See the &lt;a href=&#34;https://book.kubebuilder.io/cronjob-tutorial/empty-main.html&#34;&gt;Kubebuilder entrypoint doc&lt;/a&gt; for more details on how the manager registers the Scheme for the custom resource API definitions, and sets up and runs controllers and webhooks.&lt;/p&gt;
&lt;p&gt;The Manager can restrict the namespace that all controllers will watch for resources:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-Go&#34; data-lang=&#34;Go&#34;&gt;&lt;span style=&#34;color:#000&#34;&gt;mgr&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;ctrl&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;NewManager&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;cfg&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;manager&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;Options&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;{&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;Namespace&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;namespace&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;By default this will be empty string which means watch all namespaces:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-Go&#34; data-lang=&#34;Go&#34;&gt;&lt;span style=&#34;color:#000&#34;&gt;mgr&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;ctrl&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;NewManager&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;cfg&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;manager&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;Options&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;{&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;Namespace&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#4e9a06&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Read the &lt;a href=&#34;/docs/building-operators/golang/operator-scope/&#34;&gt;operator scope&lt;/a&gt; documentation on how to run your operator as namespace-scoped vs cluster-scoped.&lt;/p&gt;
&lt;h2 id=&#34;create-a-new-api-and-controller&#34;&gt;Create a new API and Controller&lt;/h2&gt;
&lt;p&gt;Create a new Custom Resource Definition (CRD) API with group &lt;code&gt;cache&lt;/code&gt; version &lt;code&gt;v1alpha1&lt;/code&gt; and Kind Memcached.
When prompted, enter yes &lt;code&gt;y&lt;/code&gt; for creating both the resource and controller.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-console&#34; data-lang=&#34;console&#34;&gt;$ operator-sdk create api --group cache --version v1alpha1 --kind Memcached --resource --controller
Writing scaffold for you to edit...
api/v1alpha1/memcached_types.go
controllers/memcached_controller.go
...
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This will scaffold the Memcached resource API at &lt;code&gt;api/v1alpha1/memcached_types.go&lt;/code&gt; and the controller at &lt;code&gt;controllers/memcached_controller.go&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; In this tutorial we will be providing all the steps to show you how to implement an operator project. However, as a follow up you might want to check the &lt;a href=&#34;https://book.kubebuilder.io/plugins/available/deploy-image-plugin-v1-alpha&#34;&gt;Deploy Image plugin&lt;/a&gt; with which it is possible to have the whole code generated to deploy and manage an Operand(image). To do so, you can use the command &lt;code&gt;$ operator-sdk create api --group cache --version v1alpha1 --kind Memcached --plugins=&amp;quot;deploy-image/v1-alpha&amp;quot; --image=memcached:1.4.36-alpine --image-container-command=&amp;quot;memcached,-m=64,modern,-v&amp;quot; --run-as-user=&amp;quot;1001&amp;quot;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; This guide will cover the default case of a single group API. If you would like to support Multi-Group APIs see the &lt;a href=&#34;https://book.kubebuilder.io/migration/multi-group.html&#34;&gt;Single Group to Multi-Group&lt;/a&gt; doc.&lt;/p&gt;
&lt;h4 id=&#34;understanding-kubernetes-apis&#34;&gt;Understanding Kubernetes APIs&lt;/h4&gt;
&lt;p&gt;For an in-depth explanation of Kubernetes APIs and the group-version-kind model, check out these &lt;a href=&#34;https://book.kubebuilder.io/cronjob-tutorial/gvks.html&#34;&gt;kubebuilder docs&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In general, it&amp;rsquo;s recommended to have one controller responsible for managing each API created for the project to
properly follow the design goals set by &lt;a href=&#34;https://github.com/kubernetes-sigs/controller-runtime&#34;&gt;controller-runtime&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&#34;define-the-api&#34;&gt;Define the API&lt;/h3&gt;
&lt;p&gt;To begin, we will represent our API by defining the &lt;code&gt;Memcached&lt;/code&gt; type, which will have a &lt;code&gt;MemcachedSpec.Size&lt;/code&gt; field to set the quantity of memcached instances (CRs) to be deployed, and a &lt;code&gt;MemcachedStatus.Conditions&lt;/code&gt; field to store a CR&amp;rsquo;s &lt;a href=&#34;https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#typical-status-properties&#34;&gt;Conditions&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Define the API for the Memcached Custom Resource(CR) by modifying the Go type definitions at &lt;code&gt;api/v1alpha1/memcached_types.go&lt;/code&gt; to have the following spec and status:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-Go&#34; data-lang=&#34;Go&#34;&gt;&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;// MemcachedSpec defines the desired state of Memcached
&lt;/span&gt;&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;MemcachedSpec&lt;/span&gt; &lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;struct&lt;/span&gt; &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;{&lt;/span&gt;
	&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;// INSERT ADDITIONAL SPEC FIELDS - desired state of cluster
&lt;/span&gt;&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;&lt;/span&gt;	&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;// Important: Run &amp;#34;make&amp;#34; to regenerate code after modifying this file
&lt;/span&gt;&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;&lt;/span&gt;
	&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;// The following markers will use OpenAPI v3 schema to validate the value
&lt;/span&gt;&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;&lt;/span&gt;	&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;// More info: https://book.kubebuilder.io/reference/markers/crd-validation.html
&lt;/span&gt;&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;&lt;/span&gt;	&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;// +kubebuilder:validation:Minimum=1
&lt;/span&gt;&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;&lt;/span&gt;	&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;// +kubebuilder:validation:Maximum=5
&lt;/span&gt;&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;&lt;/span&gt;	&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;// +kubebuilder:validation:ExclusiveMaximum=false
&lt;/span&gt;&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;&lt;/span&gt;
	&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;// Size defines the number of Memcached instances
&lt;/span&gt;&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;&lt;/span&gt;	&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;// +operator-sdk:csv:customresourcedefinitions:type=spec
&lt;/span&gt;&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;&lt;/span&gt;	&lt;span style=&#34;color:#000&#34;&gt;Size&lt;/span&gt; &lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;int32&lt;/span&gt; &lt;span style=&#34;color:#4e9a06&#34;&gt;`json:&amp;#34;size,omitempty&amp;#34;`&lt;/span&gt;

	&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;// Port defines the port that will be used to init the container with the image
&lt;/span&gt;&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;&lt;/span&gt;	&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;// +operator-sdk:csv:customresourcedefinitions:type=spec
&lt;/span&gt;&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;&lt;/span&gt;	&lt;span style=&#34;color:#000&#34;&gt;ContainerPort&lt;/span&gt; &lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;int32&lt;/span&gt; &lt;span style=&#34;color:#4e9a06&#34;&gt;`json:&amp;#34;containerPort,omitempty&amp;#34;`&lt;/span&gt;
&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;}&lt;/span&gt;

&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;// MemcachedStatus defines the observed state of Memcached
&lt;/span&gt;&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;MemcachedStatus&lt;/span&gt; &lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;struct&lt;/span&gt; &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;{&lt;/span&gt;
	&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;// Represents the observations of a Memcached&amp;#39;s current state.
&lt;/span&gt;&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;&lt;/span&gt;	&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;// Memcached.status.conditions.type are: &amp;#34;Available&amp;#34;, &amp;#34;Progressing&amp;#34;, and &amp;#34;Degraded&amp;#34;
&lt;/span&gt;&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;&lt;/span&gt;	&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;// Memcached.status.conditions.status are one of True, False, Unknown.
&lt;/span&gt;&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;&lt;/span&gt;	&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;// Memcached.status.conditions.reason the value should be a CamelCase string and producers of specific
&lt;/span&gt;&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;&lt;/span&gt;	&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;// condition types may define expected values and meanings for this field, and whether the values
&lt;/span&gt;&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;&lt;/span&gt;	&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;// are considered a guaranteed API.
&lt;/span&gt;&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;&lt;/span&gt;	&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;// Memcached.status.conditions.Message is a human readable message indicating details about the transition.
&lt;/span&gt;&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;&lt;/span&gt;	&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;// For further information see: https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#typical-status-properties
&lt;/span&gt;&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;&lt;/span&gt;
	&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;// Conditions store the status conditions of the Memcached instances
&lt;/span&gt;&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;&lt;/span&gt;	&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;// +operator-sdk:csv:customresourcedefinitions:type=status
&lt;/span&gt;&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;&lt;/span&gt;	&lt;span style=&#34;color:#000&#34;&gt;Conditions&lt;/span&gt; &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;[]&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;metav1&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;Condition&lt;/span&gt; &lt;span style=&#34;color:#4e9a06&#34;&gt;`json:&amp;#34;conditions,omitempty&amp;#34; patchStrategy:&amp;#34;merge&amp;#34; patchMergeKey:&amp;#34;type&amp;#34; protobuf:&amp;#34;bytes,1,rep,name=conditions&amp;#34;`&lt;/span&gt;
&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Add the &lt;code&gt;+kubebuilder:subresource:status&lt;/code&gt; &lt;a href=&#34;https://book.kubebuilder.io/reference/generating-crd.html#status&#34;&gt;marker&lt;/a&gt; to add a &lt;a href=&#34;https://kubernetes.io/docs/tasks/extend-kubernetes/custom-resources/custom-resource-definitions/#status-subresource&#34;&gt;status subresource&lt;/a&gt; to the CRD manifest so that the controller can update the CR status without changing the rest of the CR object:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-Go&#34; data-lang=&#34;Go&#34;&gt;&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;// Memcached is the Schema for the memcacheds API
&lt;/span&gt;&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;//+kubebuilder:subresource:status
&lt;/span&gt;&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;Memcached&lt;/span&gt; &lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;struct&lt;/span&gt; &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;{&lt;/span&gt;
	&lt;span style=&#34;color:#000&#34;&gt;metav1&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;TypeMeta&lt;/span&gt;   &lt;span style=&#34;color:#4e9a06&#34;&gt;`json:&amp;#34;,inline&amp;#34;`&lt;/span&gt;
	&lt;span style=&#34;color:#000&#34;&gt;metav1&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;ObjectMeta&lt;/span&gt; &lt;span style=&#34;color:#4e9a06&#34;&gt;`json:&amp;#34;metadata,omitempty&amp;#34;`&lt;/span&gt;

	&lt;span style=&#34;color:#000&#34;&gt;Spec&lt;/span&gt;   &lt;span style=&#34;color:#000&#34;&gt;MemcachedSpec&lt;/span&gt;   &lt;span style=&#34;color:#4e9a06&#34;&gt;`json:&amp;#34;spec,omitempty&amp;#34;`&lt;/span&gt;
	&lt;span style=&#34;color:#000&#34;&gt;Status&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;MemcachedStatus&lt;/span&gt; &lt;span style=&#34;color:#4e9a06&#34;&gt;`json:&amp;#34;status,omitempty&amp;#34;`&lt;/span&gt;
&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;After modifying the &lt;code&gt;*_types.go&lt;/code&gt; file always run the following command to update the generated code for that resource type:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;make generate
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The above makefile target will invoke the &lt;a href=&#34;https://sigs.k8s.io/controller-tools&#34;&gt;controller-gen&lt;/a&gt; utility to update the &lt;code&gt;api/v1alpha1/zz_generated.deepcopy.go&lt;/code&gt; file to ensure our API&amp;rsquo;s Go type definitions implement the &lt;code&gt;runtime.Object&lt;/code&gt; interface that all Kind types must implement.&lt;/p&gt;
&lt;h3 id=&#34;generating-crd-manifests&#34;&gt;Generating CRD manifests&lt;/h3&gt;
&lt;p&gt;Once the API is defined with spec/status fields and CRD validation markers, the CRD manifests can be generated and updated with the following command:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;make manifests
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This makefile target will invoke &lt;a href=&#34;https://sigs.k8s.io/controller-tools&#34;&gt;controller-gen&lt;/a&gt; to generate the CRD manifests at &lt;code&gt;config/crd/bases/cache.example.com_memcacheds.yaml&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&#34;openapi-validation&#34;&gt;OpenAPI validation&lt;/h3&gt;
&lt;p&gt;OpenAPI validation defined in a CRD ensures CRs are validated based on a set of declarative rules. All CRDs should have validation.
See the &lt;a href=&#34;/docs/building-operators/golang/references/openapi-validation&#34;&gt;OpenAPI validation&lt;/a&gt; doc for details.&lt;/p&gt;
&lt;h2 id=&#34;implement-the-controller&#34;&gt;Implement the Controller&lt;/h2&gt;
&lt;p&gt;For this example replace the generated controller file &lt;code&gt;controllers/memcached_controller.go&lt;/code&gt; with the example &lt;a href=&#34;https://github.com/operator-framework/operator-sdk/blob/latest/testdata/go/v4/memcached-operator/internal/controller/memcached_controller.go&#34;&gt;&lt;code&gt;memcached_controller.go&lt;/code&gt;&lt;/a&gt; implementation.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: If you used a value other than &lt;code&gt;github.com/example/memcached-operator&lt;/code&gt; for repository (&lt;code&gt;--repo&lt;/code&gt; flag) when running the &lt;code&gt;operator-sdk init&lt;/code&gt; command, modify accordingly in the &lt;code&gt;import&lt;/code&gt; block of the file.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: The next two subsections explain how the controller watches resources and how the reconcile loop is triggered.
If you&amp;rsquo;d like to skip this section, head to the &lt;a href=&#34;#run-the-operator&#34;&gt;deploy&lt;/a&gt; section to see how to run the operator.&lt;/p&gt;
&lt;h3 id=&#34;setup-a-recorder&#34;&gt;Setup a Recorder&lt;/h3&gt;
&lt;p&gt;First, add a recorder when you initialize the Memcached reconciler in &lt;code&gt;main.go&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-Go&#34; data-lang=&#34;Go&#34;&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;controllers&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;MemcachedReconciler&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;{&lt;/span&gt;
	&lt;span style=&#34;color:#000&#34;&gt;Client&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;   &lt;span style=&#34;color:#000&#34;&gt;mgr&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;GetClient&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(),&lt;/span&gt;
	&lt;span style=&#34;color:#000&#34;&gt;Scheme&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;   &lt;span style=&#34;color:#000&#34;&gt;mgr&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;GetScheme&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(),&lt;/span&gt;
	&lt;span style=&#34;color:#000&#34;&gt;Recorder&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;mgr&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;GetEventRecorderFor&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#4e9a06&#34;&gt;&amp;#34;memcached-controller&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;),&lt;/span&gt;
&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;}).&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;SetupWithManager&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;mgr&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;);&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;nil&lt;/span&gt; &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;{&lt;/span&gt;
	&lt;span style=&#34;color:#000&#34;&gt;setupLog&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;Error&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;err&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#4e9a06&#34;&gt;&amp;#34;unable to create controller&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#4e9a06&#34;&gt;&amp;#34;controller&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#4e9a06&#34;&gt;&amp;#34;Memcached&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;)&lt;/span&gt;
	&lt;span style=&#34;color:#000&#34;&gt;os&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;Exit&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#0000cf;font-weight:bold&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;)&lt;/span&gt;
&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This recorder will be used within the reconcile method of the controller to emit events.&lt;/p&gt;
&lt;h3 id=&#34;resources-watched-by-the-controller&#34;&gt;Resources watched by the Controller&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;SetupWithManager()&lt;/code&gt; function in &lt;code&gt;controllers/memcached_controller.go&lt;/code&gt; specifies how the controller is built to watch a CR and other resources that are owned and managed by that controller.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-Go&#34; data-lang=&#34;Go&#34;&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;import&lt;/span&gt; &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(&lt;/span&gt;
	&lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;...&lt;/span&gt;
	&lt;span style=&#34;color:#000&#34;&gt;appsv1&lt;/span&gt; &lt;span style=&#34;color:#4e9a06&#34;&gt;&amp;#34;k8s.io/api/apps/v1&amp;#34;&lt;/span&gt;
	&lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;...&lt;/span&gt;
&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;)&lt;/span&gt;

&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;r&lt;/span&gt; &lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;MemcachedReconciler&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;SetupWithManager&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;mgr&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;ctrl&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;Manager&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;error&lt;/span&gt; &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;{&lt;/span&gt;
	&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;ctrl&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;NewControllerManagedBy&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;mgr&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;).&lt;/span&gt;
		&lt;span style=&#34;color:#000&#34;&gt;For&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;cachev1alpha1&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;Memcached&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;{}).&lt;/span&gt;
		&lt;span style=&#34;color:#000&#34;&gt;Owns&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;appsv1&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;Deployment&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;{}).&lt;/span&gt;
		&lt;span style=&#34;color:#000&#34;&gt;Complete&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;r&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;)&lt;/span&gt;
&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;NewControllerManagedBy()&lt;/code&gt; provides a controller builder that allows various controller configurations.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;For(&amp;amp;cachev1alpha1.Memcached{})&lt;/code&gt; specifies the Memcached type as the primary resource to watch. For each Memcached type Add/Update/Delete event the reconcile loop will be sent a reconcile &lt;code&gt;Request&lt;/code&gt; (a namespace/name key) for that Memcached object.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Owns(&amp;amp;appsv1.Deployment{})&lt;/code&gt; specifies the Deployments type as the secondary resource to watch. For each Deployment type Add/Update/Delete event, the event handler will map each event to a reconcile &lt;code&gt;Request&lt;/code&gt; for the owner of the Deployment. Which in this case is the Memcached object for which the Deployment was created.&lt;/p&gt;
&lt;p&gt;The dependent objects, in this case the Deployments, need to have an &lt;a href=&#34;https://kubernetes.io/docs/concepts/overview/working-with-objects/owners-dependents/#owner-references-in-object-specifications&#34;&gt;Owner References&lt;/a&gt; field that references their owner object. This will be added by using the method &lt;code&gt;ctrl.SetControllerReference&lt;/code&gt;. &lt;a href=&#34;https://kubernetes.io/docs/concepts/overview/working-with-objects/owners-dependents/&#34;&gt;More info&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Note: The K8s api will manage the resources according to the&lt;code&gt;ownerRef&lt;/code&gt; which will be properly set by using this method. Therefore, the K8s API will know that these resources, such as the Deployment to run the Memcached Operand image, depend on the custom resource for the Memcached Kind.  This allows the K8s API to delete all dependent resources when/if the custom resource is deleted. &lt;a href=&#34;https://kubernetes.io/docs/concepts/architecture/garbage-collection/#cascading-deletion&#34;&gt;More info&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&#34;controller-configurations&#34;&gt;Controller Configurations&lt;/h3&gt;
&lt;p&gt;There are a number of other useful configurations that can be made when initializing a controller. For more details on these configurations consult the upstream &lt;a href=&#34;https://pkg.go.dev/sigs.k8s.io/controller-runtime/pkg/builder#example-Builder&#34;&gt;builder&lt;/a&gt; and &lt;a href=&#34;https://pkg.go.dev/sigs.k8s.io/controller-runtime/pkg/controller&#34;&gt;controller&lt;/a&gt; godocs.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Set the max number of concurrent Reconciles for the controller via the &lt;a href=&#34;https://pkg.go.dev/sigs.k8s.io/controller-runtime/pkg/controller#Options&#34;&gt;&lt;code&gt;MaxConcurrentReconciles&lt;/code&gt;&lt;/a&gt;  option. Defaults to 1.
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-Go&#34; data-lang=&#34;Go&#34;&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;r&lt;/span&gt; &lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;MemcachedReconciler&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;SetupWithManager&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;mgr&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;ctrl&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;Manager&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;error&lt;/span&gt; &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;{&lt;/span&gt;
  &lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;ctrl&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;NewControllerManagedBy&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;mgr&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;).&lt;/span&gt;
    &lt;span style=&#34;color:#000&#34;&gt;For&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;cachev1alpha1&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;Memcached&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;{}).&lt;/span&gt;
    &lt;span style=&#34;color:#000&#34;&gt;Owns&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;appsv1&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;Deployment&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;{}).&lt;/span&gt;
    &lt;span style=&#34;color:#000&#34;&gt;WithOptions&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;controller&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;Options&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;{&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;MaxConcurrentReconciles&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#0000cf;font-weight:bold&#34;&gt;2&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;}).&lt;/span&gt;
    &lt;span style=&#34;color:#000&#34;&gt;Complete&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;r&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;)&lt;/span&gt;
&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;Filter watch events using &lt;a href=&#34;/docs/building-operators/golang/references/event-filtering/&#34;&gt;predicates&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Choose the type of &lt;a href=&#34;https://pkg.go.dev/sigs.k8s.io/controller-runtime/pkg/handler#hdr-EventHandlers&#34;&gt;EventHandler&lt;/a&gt; to change how a watch event will translate to reconcile requests for the reconcile loop. For operator relationships that are more complex than primary and secondary resources, the &lt;a href=&#34;https://pkg.go.dev/sigs.k8s.io/controller-runtime/pkg/handler#EnqueueRequestsFromMapFunc&#34;&gt;&lt;code&gt;EnqueueRequestsFromMapFunc&lt;/code&gt;&lt;/a&gt; handler can be used to transform a watch event into an arbitrary set of reconcile requests.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;reconcile-loop&#34;&gt;Reconcile loop&lt;/h3&gt;
&lt;p&gt;The reconcile function is responsible for enforcing the desired CR state on the actual state of the system. It runs each time an event occurs on a watched CR or resource, and will return some value depending on whether those states match or not.&lt;/p&gt;
&lt;p&gt;In this way, every Controller has a Reconciler object with a &lt;code&gt;Reconcile()&lt;/code&gt; method that implements the reconcile loop. The reconcile loop is passed the &lt;a href=&#34;https://pkg.go.dev/sigs.k8s.io/controller-runtime/pkg/reconcile#Request&#34;&gt;&lt;code&gt;Request&lt;/code&gt;&lt;/a&gt; argument which is a Namespace/Name key used to lookup the primary resource object, Memcached, from the cache:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-Go&#34; data-lang=&#34;Go&#34;&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;import&lt;/span&gt; &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(&lt;/span&gt;
	&lt;span style=&#34;color:#000&#34;&gt;ctrl&lt;/span&gt; &lt;span style=&#34;color:#4e9a06&#34;&gt;&amp;#34;sigs.k8s.io/controller-runtime&amp;#34;&lt;/span&gt;

	&lt;span style=&#34;color:#000&#34;&gt;cachev1alpha1&lt;/span&gt; &lt;span style=&#34;color:#4e9a06&#34;&gt;&amp;#34;github.com/example/memcached-operator/api/v1alpha1&amp;#34;&lt;/span&gt;
	&lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;...&lt;/span&gt;
&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;)&lt;/span&gt;

&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;r&lt;/span&gt; &lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;MemcachedReconciler&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;Reconcile&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;ctx&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;context&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;Context&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;req&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;ctrl&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;Request&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;ctrl&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;Result&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;error&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;{&lt;/span&gt;
  &lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;// Lookup the Memcached instance for this reconcile request
&lt;/span&gt;&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;&lt;/span&gt;  &lt;span style=&#34;color:#000&#34;&gt;memcached&lt;/span&gt; &lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;cachev1alpha1&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;Memcached&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;{}&lt;/span&gt;
  &lt;span style=&#34;color:#000&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;r&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;Get&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;ctx&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;req&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;NamespacedName&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;memcached&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;)&lt;/span&gt;
  &lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;...&lt;/span&gt;
&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;For a guide on Reconcilers, Clients, and interacting with resource Events, see the &lt;a href=&#34;/docs/building-operators/golang/references/client/&#34;&gt;Client API doc&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The following are a few possible return options for a Reconciler:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;With the error:
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;ctrl&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;Result&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;{},&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;err&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;Without an error:
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;ctrl&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;Result&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;{&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;Requeue&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;true&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;},&lt;/span&gt; &lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;nil&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;Therefore, to stop the Reconcile, use:
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;ctrl&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;Result&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;{},&lt;/span&gt; &lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;nil&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;Reconcile again after X time:
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt; &lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;ctrl&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;Result&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;{&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;RequeueAfter&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#0000cf;font-weight:bold&#34;&gt;5&lt;/span&gt; &lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;*&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;time&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;Minute&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;},&lt;/span&gt; &lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;nil&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For more details, check the Reconcile and its &lt;a href=&#34;https://pkg.go.dev/sigs.k8s.io/controller-runtime/pkg/reconcile&#34;&gt;Reconcile godoc&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&#34;specify-permissions-and-generate-rbac-manifests&#34;&gt;Specify permissions and generate RBAC manifests&lt;/h3&gt;
&lt;p&gt;The controller needs certain &lt;a href=&#34;https://kubernetes.io/docs/reference/access-authn-authz/rbac/&#34;&gt;RBAC&lt;/a&gt; permissions to interact with the resources it manages. These are specified via &lt;a href=&#34;https://book.kubebuilder.io/reference/markers/rbac.html&#34;&gt;RBAC markers&lt;/a&gt; like the following:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-Go&#34; data-lang=&#34;Go&#34;&gt;&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;//+kubebuilder:rbac:groups=cache.example.com,resources=memcacheds,verbs=get;list;watch;create;update;patch;delete
&lt;/span&gt;&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;//+kubebuilder:rbac:groups=cache.example.com,resources=memcacheds/status,verbs=get;update;patch
&lt;/span&gt;&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;//+kubebuilder:rbac:groups=cache.example.com,resources=memcacheds/finalizers,verbs=update
&lt;/span&gt;&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;//+kubebuilder:rbac:groups=core,resources=events,verbs=create;patch
&lt;/span&gt;&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;//+kubebuilder:rbac:groups=apps,resources=deployments,verbs=get;list;watch;create;update;patch;delete
&lt;/span&gt;&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;//+kubebuilder:rbac:groups=core,resources=pods,verbs=get;list;watch
&lt;/span&gt;&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;&lt;/span&gt;
&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;r&lt;/span&gt; &lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;MemcachedReconciler&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;Reconcile&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;ctx&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;context&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;Context&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;req&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;ctrl&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;Request&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;ctrl&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;Result&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;error&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;{&lt;/span&gt;
  &lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;...&lt;/span&gt;
&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;ClusterRole&lt;/code&gt; manifest at &lt;code&gt;config/rbac/role.yaml&lt;/code&gt; is generated from the above markers via controller-gen with the following command:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;make manifests
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;NOTE: If you receive an error, please run the specified command in the error and re-run &lt;code&gt;make manifests&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&#34;configure-the-operators-image-registry&#34;&gt;Configure the operator&amp;rsquo;s image registry&lt;/h2&gt;
&lt;p&gt;All that remains is to build and push the operator image to the desired image registry.&lt;/p&gt;
&lt;p&gt;Before building the operator image, ensure the generated Dockerfile references
the base image you want. You can change the default &amp;ldquo;runner&amp;rdquo; image &lt;code&gt;gcr.io/distroless/static:nonroot&lt;/code&gt;
by replacing its tag with another, for example &lt;code&gt;alpine:latest&lt;/code&gt;, and removing
the &lt;code&gt;USER 65532:65532&lt;/code&gt; directive.&lt;/p&gt;
&lt;p&gt;Your Makefile composes image tags either from values written at project initialization or from the CLI.
In particular, &lt;code&gt;IMAGE_TAG_BASE&lt;/code&gt; lets you define a common image registry, namespace, and partial name
for all your image tags. Update this to another registry and/or namespace if the current value is incorrect.
Afterwards you can update the &lt;code&gt;IMG&lt;/code&gt; variable definition like so:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-diff&#34; data-lang=&#34;diff&#34;&gt;&lt;span style=&#34;color:#a40000&#34;&gt;-IMG ?= controller:latest
&lt;/span&gt;&lt;span style=&#34;color:#a40000&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#00a000&#34;&gt;+IMG ?= $(IMAGE_TAG_BASE):$(VERSION)
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Once done, you do not have to set &lt;code&gt;IMG&lt;/code&gt; or any other image variable in the CLI. The following command will
build and push an operator image tagged as &lt;code&gt;example.com/memcached-operator:v0.0.1&lt;/code&gt; to Docker Hub:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-console&#34; data-lang=&#34;console&#34;&gt;make docker-build docker-push
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&#34;run-the-operator&#34;&gt;Run the Operator&lt;/h2&gt;
&lt;p&gt;There are three ways to run the operator:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;As a Go program outside a cluster&lt;/li&gt;
&lt;li&gt;As a Deployment inside a Kubernetes cluster&lt;/li&gt;
&lt;li&gt;Managed by the &lt;a href=&#34;/docs/olm-integration/tutorial-bundle/#enabling-olm&#34;&gt;Operator Lifecycle Manager (OLM)&lt;/a&gt; in &lt;a href=&#34;/docs/olm-integration/quickstart-bundle&#34;&gt;bundle&lt;/a&gt; format&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;1-run-locally-outside-the-cluster&#34;&gt;1. Run locally outside the cluster&lt;/h3&gt;
&lt;p&gt;The following steps will show how to deploy the operator on the cluster. However, to run locally for development purposes and outside of a cluster use the target &lt;code&gt;make install run&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Note that by using this plugin the Operand image informed will be stored via an environment variable in the &lt;code&gt;config/manager/manager.yaml&lt;/code&gt; manifest.&lt;/p&gt;
&lt;p&gt;Therefore, before running &lt;code&gt;make install run&lt;/code&gt; you need to export any environment variable that you might have. Example:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;color:#204a87&#34;&gt;export&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;MEMCACHED_IMAGE&lt;/span&gt;&lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#4e9a06&#34;&gt;&amp;#34;memcached:1.4.36-alpine&amp;#34;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;2-run-as-a-deployment-inside-the-cluster&#34;&gt;2. Run as a Deployment inside the cluster&lt;/h3&gt;
&lt;p&gt;By default, a new namespace is created with name &lt;code&gt;&amp;lt;project-name&amp;gt;-system&lt;/code&gt;, ex. &lt;code&gt;memcached-operator-system&lt;/code&gt;, and will be used for the deployment.&lt;/p&gt;
&lt;p&gt;Run the following to deploy the operator. This will also install the RBAC manifests from &lt;code&gt;config/rbac&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;make deploy
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Verify that the memcached-operator is up and running:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-console&#34; data-lang=&#34;console&#34;&gt;$ kubectl get deployment -n memcached-operator-system
NAME                                    READY   UP-TO-DATE   AVAILABLE   AGE
memcached-operator-controller-manager   1/1     1            1           8m
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&#34;3-deploy-your-operator-with-olm&#34;&gt;3. Deploy your Operator with OLM&lt;/h3&gt;
&lt;p&gt;First, install &lt;a href=&#34;/docs/olm-integration/tutorial-bundle/#enabling-olm&#34;&gt;OLM&lt;/a&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;operator-sdk olm install
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Bundle your operator, then build and push the bundle image. The &lt;code&gt;bundle&lt;/code&gt; target generates a &lt;a href=&#34;https://github.com/operator-framework/operator-registry/blob/v1.16.1/docs/design/operator-bundle.md#operator-bundle&#34;&gt;bundle&lt;/a&gt;
in the &lt;code&gt;bundle&lt;/code&gt; directory containing manifests and metadata defining your operator.
&lt;code&gt;bundle-build&lt;/code&gt; and &lt;code&gt;bundle-push&lt;/code&gt; build and push a bundle image defined by &lt;code&gt;bundle.Dockerfile&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;make bundle bundle-build bundle-push
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Finally, run your bundle. If your bundle image is hosted in a registry that is private and/or
has a custom CA, these &lt;a href=&#34;/docs/olm-integration/cli-overview#private-bundle-and-catalog-image-registries&#34;&gt;configuration steps&lt;/a&gt; must be complete.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;operator-sdk run bundle &amp;lt;some-registry&amp;gt;/memcached-operator-bundle:v0.0.1
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Check out the &lt;a href=&#34;/docs/olm-integration/tutorial-bundle&#34;&gt;docs&lt;/a&gt; for a deep dive into &lt;code&gt;operator-sdk&lt;/code&gt;&#39;s OLM integration.&lt;/p&gt;
&lt;h2 id=&#34;create-a-memcached-cr&#34;&gt;Create a Memcached CR&lt;/h2&gt;
&lt;p&gt;Update the sample Memcached CR manifest at &lt;code&gt;config/samples/cache_v1alpha1_memcached.yaml&lt;/code&gt; and define the &lt;code&gt;spec&lt;/code&gt; as the following:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-YAML&#34; data-lang=&#34;YAML&#34;&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;apiVersion&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;cache.example.com/v1alpha1&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;kind&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;Memcached&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;metadata&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;  &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;name&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;memcached-sample&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;spec&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;  &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;size&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#0000cf;font-weight:bold&#34;&gt;3&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;  &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;containerPort&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#0000cf;font-weight:bold&#34;&gt;11211&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Create the CR:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;kubectl apply -f config/samples/cache_v1alpha1_memcached.yaml
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Ensure that the memcached operator creates the deployment for the sample CR with the correct size:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-console&#34; data-lang=&#34;console&#34;&gt;$ kubectl get deployment
NAME                                    READY   UP-TO-DATE   AVAILABLE   AGE
memcached-sample                        3/3     3            3           1m
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Check the pods and CR status to confirm the status is updated with the memcached pod names:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-console&#34; data-lang=&#34;console&#34;&gt;$ kubectl get pods
NAME                                  READY     STATUS    RESTARTS   AGE
memcached-sample-6fd7c98d8-7dqdr      1/1       Running   0          1m
memcached-sample-6fd7c98d8-g5k7v      1/1       Running   0          1m
memcached-sample-6fd7c98d8-m7vn7      1/1       Running   0          1m
&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code class=&#34;language-console&#34; data-lang=&#34;console&#34;&gt;$ kubectl get memcached/memcached-sample -o yaml
apiVersion: cache.example.com/v1alpha1
kind: Memcached
metadata:
  clusterName: &amp;quot;&amp;quot;
  creationTimestamp: 2018-03-31T22:51:08Z
  generation: 0
  name: memcached-sample
  namespace: default
  resourceVersion: &amp;quot;245453&amp;quot;
  selfLink: /apis/cache.example.com/v1alpha1/namespaces/default/memcacheds/memcached-sample
  uid: 0026cc97-3536-11e8-bd83-0800274106a1
spec:
  size: 3
status:
  nodes:
  - memcached-sample-6fd7c98d8-7dqdr
  - memcached-sample-6fd7c98d8-g5k7v
  - memcached-sample-6fd7c98d8-m7vn7
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&#34;update-the-size&#34;&gt;Update the size&lt;/h3&gt;
&lt;p&gt;Update &lt;code&gt;config/samples/cache_v1alpha1_memcached.yaml&lt;/code&gt; to change the &lt;code&gt;spec.size&lt;/code&gt; field in the Memcached CR from 3 to 5:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;kubectl patch memcached memcached-sample -p &lt;span style=&#34;color:#4e9a06&#34;&gt;&amp;#39;{&amp;#34;spec&amp;#34;:{&amp;#34;size&amp;#34;: 5}}&amp;#39;&lt;/span&gt; --type&lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;=&lt;/span&gt;merge
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Confirm that the operator changes the deployment size:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-console&#34; data-lang=&#34;console&#34;&gt;$ kubectl get deployment
NAME                                    READY   UP-TO-DATE   AVAILABLE   AGE
memcached-sample                        5/5     5            5           3m
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&#34;cleanup&#34;&gt;Cleanup&lt;/h3&gt;
&lt;p&gt;Run the following to delete all deployed resources:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;kubectl delete -f config/samples/cache_v1alpha1_memcached.yaml
make undeploy
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;next-steps&#34;&gt;Next steps&lt;/h2&gt;
&lt;p&gt;Next, check out the following:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Validating and mutating &lt;a href=&#34;/docs/building-operators/golang/webhook&#34;&gt;admission webhooks&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Operator packaging and distribution with &lt;a href=&#34;/docs/olm-integration&#34;&gt;OLM&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;The &lt;a href=&#34;/docs/building-operators/golang/advanced-topics/&#34;&gt;advanced topics&lt;/a&gt; doc for more use cases and under-the-hood details.&lt;/li&gt;
&lt;/ol&gt;

      </description>
    </item>
    
    <item>
      <title>Docs: Admission Webhooks</title>
      <link>/docs/building-operators/golang/webhook/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      
      <guid>/docs/building-operators/golang/webhook/</guid>
      <description>
        
        
        &lt;h2 id=&#34;create-a-validating-or-mutating-admission-webhook&#34;&gt;Create a validating or mutating Admission Webhook&lt;/h2&gt;
&lt;p&gt;Admission webhooks are HTTP callbacks that receive admission requests and do something with them. It is registered with Kubernetes, and
will be called by Kubernetes to validate or mutate a resource before being stored. There are two types of admission webhooks.&lt;/p&gt;
&lt;h4 id=&#34;1-validating-admission-webhook&#34;&gt;1. Validating admission webhook&lt;/h4&gt;
&lt;p&gt;Validating webhooks can be used to perform validations that go beyond the capabilities of OpenAPI schema validation,
such as ensuring a field is immutable after creation or higher level permissions checks based on the user that is making
the request to the API server. It can reject the request, but it cannot modify the object that they are receiving in the request.&lt;/p&gt;
&lt;h4 id=&#34;2-mutating-admission-webhook&#34;&gt;2. Mutating admission webhook&lt;/h4&gt;
&lt;p&gt;Mutating webhooks are most frequently used for defaulting, by adding default values for unset fields in the resource on creation.
They can modify objects by creating a patch that will be sent back in the admission response.&lt;/p&gt;
&lt;p&gt;For more background on Admission webhooks, refer to the &lt;a href=&#34;https://book.kubebuilder.io/reference/admission-webhook.html&#34;&gt;Kubebuilder documentation&lt;/a&gt; or the &lt;a href=&#34;https://kubernetes.io/docs/reference/access-authn-authz/extensible-admission-controllers/&#34;&gt;official Kubernetes documentation&lt;/a&gt;.
You can also refer to the &lt;a href=&#34;https://book.kubebuilder.io/cronjob-tutorial/webhook-implementation.html&#34;&gt;Kubebuilder webhook walkthrough&lt;/a&gt;, which is similar in content to this guide.&lt;/p&gt;
&lt;h3 id=&#34;create-validation-webhook&#34;&gt;Create Validation Webhook&lt;/h3&gt;
&lt;p&gt;As an example, let&amp;rsquo;s walk through the scaffolding of a validation webhook for the sample memcached operator.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;$ operator-sdk create webhook --group cache --version v1alpha1 --kind Memcached --defaulting --programmatic-validation
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;After, &lt;code&gt;create webhook&lt;/code&gt; command, the following message will appear on the terminal. It scaffolds out &lt;code&gt;api/&amp;lt;version&amp;gt;/&amp;lt;kind&amp;gt;_webhook.go&lt;/code&gt; file. In this example, it would be &lt;code&gt;api/v1alpha1/memcached_webhook.go&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;Writing kustomize manifests &lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;for&lt;/span&gt; you to edit...
Writing scaffold &lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;for&lt;/span&gt; you to edit...
api/v1alpha1/memcached_webhook.go
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;--defaulting&lt;/code&gt; flag will scaffold the resources required for a mutating webhook, and the &lt;code&gt;--programmatic-validation&lt;/code&gt; flag will scaffold the resources required for a validating webhook.
In this case we have scaffolded both.&lt;/p&gt;
&lt;p&gt;After running the &lt;code&gt;create webhook&lt;/code&gt; command the file structure would be:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;├── Dockerfile
├── Makefile
├── PROJECT
├── api
│   └── v1alpha1
│       ├── memcached_webhook.go
│       ├── webhook_suite_test.go
├── config
│   ├── certmanager
│   │   ├── certificate.yaml
│   │   ├── kustomization.yaml
│   │   └── kustomizeconfig.yaml
│   ├── default
│   │   ├── manager_webhook_patch.yaml
│   │   └── webhookcainjection_patch.yaml
│   └── webhook
│       ├── kustomization.yaml
│       ├── kustomizeconfig.yaml
│       └── service.yaml
├── go.mod
├── go.sum
└── main.go
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The scaffolded file &lt;code&gt;api/v1alpha1/memcached_webhook.go&lt;/code&gt; has method signatures which need to be implemented for the validation webhook.&lt;/p&gt;
&lt;p&gt;Following this, there are a few steps which need to be done in your operator project to enable webhooks. This will involve:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Implementing the required methods for Validating or Mutating webhook in &lt;code&gt;&amp;lt;kind&amp;gt;_webhook.go&lt;/code&gt;. An example of such implementation is provided &lt;a href=&#34;https://book.kubebuilder.io/cronjob-tutorial/webhook-implementation.html&#34;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Uncommenting sections in &lt;code&gt;config/default/kustomization.yaml&lt;/code&gt; to enable webhook and cert-manager configuration through kustomize. Cert-manager (or any third party solution) can be used to provision certificates for webhook server. This is explained in detail &lt;a href=&#34;https://book.kubebuilder.io/cronjob-tutorial/running-webhook.html#deploy-webhooks&#34;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;
If OLM is being used to deploy the operator, then the section prefixed with &lt;code&gt;[CERT-MANAGER]&lt;/code&gt; need not be uncommented. This is because, OLM currently handles the cert generation and rotation for webhook deployment using self-signed certs. It also does not allow users to specify the name or mount location for the certs. More documentation on this issue can be found &lt;a href=&#34;https://olm.operatorframework.io/docs/advanced-tasks/adding-admission-and-conversion-webhooks/#deploying-an-operator-with-webhooks-using-olm&#34;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&#34;generate-webhook-manifests-and-enable-webhook-deployment&#34;&gt;Generate webhook manifests and enable webhook deployment&lt;/h3&gt;
&lt;p&gt;Once your webhooks are implemented, all that’s left is to create the &lt;code&gt;WebhookConfiguration&lt;/code&gt; manifests required to register your webhooks with Kubernetes:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;$ make manifests
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;run-your-operator-and-webhooks&#34;&gt;Run your operator and webhooks&lt;/h2&gt;
&lt;p&gt;There are two ways to test your operator project with webhooks.&lt;/p&gt;
&lt;h4 id=&#34;run-locally&#34;&gt;Run locally&lt;/h4&gt;
&lt;p&gt;Technically, the webhooks can be run locally, but for it to work you need to generate certificates for the webhook server and store them at &lt;code&gt;/tmp/k8s-webhook-server/serving-certs/tls.{crt,key}&lt;/code&gt;. For more details about running webhook locally, refer &lt;a href=&#34;https://book.kubebuilder.io/cronjob-tutorial/running.html#running-webhooks-locally&#34;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h4 id=&#34;run-as-a-deployment-inside-the-cluster&#34;&gt;Run as a Deployment inside the cluster&lt;/h4&gt;
&lt;p&gt;Adding webhooks does not alter deploying your operator. For instructions on deploying your operator into a cluster, refer to the &lt;a href=&#34;https://sdk.operatorframework.io/docs/building-operators/golang/tutorial/#2-run-as-a-deployment-inside-the-cluster&#34;&gt;tutorial&lt;/a&gt;.&lt;/p&gt;

      </description>
    </item>
    
    <item>
      <title>Docs: Operators Scope</title>
      <link>/docs/building-operators/golang/operator-scope/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      
      <guid>/docs/building-operators/golang/operator-scope/</guid>
      <description>
        
        
        &lt;h2 id=&#34;overview&#34;&gt;Overview&lt;/h2&gt;
&lt;p&gt;A namespace-scoped operator watches and manages resources in a single Namespace, whereas a cluster-scoped operator
watches and manages resources cluster-wide.&lt;/p&gt;
&lt;p&gt;An operator should be cluster-scoped if it watches resources that can be created in any Namespace. An operator should
be namespace-scoped if it is intended to be flexibly deployed. This scope permits
decoupled upgrades, namespace isolation for failures and monitoring, and differing API definitions.&lt;/p&gt;
&lt;p&gt;By default, &lt;code&gt;operator-sdk init&lt;/code&gt; scaffolds a cluster-scoped operator. This document details conversion of default
operator projects to namespaced-scoped operators. Before proceeding, be aware that your operator may be better suited
as cluster-scoped. For example, the &lt;a href=&#34;https://github.com/jetstack/cert-manager&#34;&gt;cert-manager&lt;/a&gt; operator is often deployed with cluster-scoped
permissions and watches so that it can manage and issue certificates for an entire cluster.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;IMPORTANT&lt;/strong&gt;: When a &lt;a href=&#34;https://pkg.go.dev/sigs.k8s.io/controller-runtime/pkg/manager#Manager&#34;&gt;Manager&lt;/a&gt; instance is created in the &lt;code&gt;main.go&lt;/code&gt; file, the
Namespaces are set via &lt;a href=&#34;https://pkg.go.dev/sigs.k8s.io/controller-runtime/pkg/cache#Config&#34;&gt;Cache Config&lt;/a&gt; as described below. These Namespaces should be watched and
cached for the Client which is provided by the Manager. Only clients provided by cluster-scoped Managers are able
to manage cluster-scoped CRD&amp;rsquo;s. For further information see: &lt;a href=&#34;/docs/building-operators/golang/crds-scope/&#34;&gt;CRD scope doc&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&#34;manager-watching-options&#34;&gt;Manager watching options&lt;/h2&gt;
&lt;h3 id=&#34;watching-resources-in-all-namespaces-default&#34;&gt;Watching resources in all Namespaces (default)&lt;/h3&gt;
&lt;p&gt;A &lt;a href=&#34;https://pkg.go.dev/sigs.k8s.io/controller-runtime/pkg/manager#Manager&#34;&gt;Manager&lt;/a&gt; is initialized with no Cache option specified, or with a Cache.DefaultNamespaces of &lt;code&gt;Namespace: &amp;quot;&amp;quot;&lt;/code&gt; will
watch all Namespaces:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;...&lt;/span&gt;
&lt;span style=&#34;color:#000&#34;&gt;mgr&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;ctrl&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;NewManager&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;ctrl&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;GetConfigOrDie&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(),&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;ctrl&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;Options&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;{&lt;/span&gt;
    &lt;span style=&#34;color:#000&#34;&gt;Scheme&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;             &lt;span style=&#34;color:#000&#34;&gt;scheme&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;,&lt;/span&gt;
    &lt;span style=&#34;color:#000&#34;&gt;MetricsBindAddress&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;metricsAddr&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;,&lt;/span&gt;
    &lt;span style=&#34;color:#000&#34;&gt;Port&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;               &lt;span style=&#34;color:#0000cf;font-weight:bold&#34;&gt;9443&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;,&lt;/span&gt;
    &lt;span style=&#34;color:#000&#34;&gt;LeaderElection&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;     &lt;span style=&#34;color:#000&#34;&gt;enableLeaderElection&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;,&lt;/span&gt;
    &lt;span style=&#34;color:#000&#34;&gt;LeaderElectionID&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;   &lt;span style=&#34;color:#4e9a06&#34;&gt;&amp;#34;f1c5ece8.example.com&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;,&lt;/span&gt;
&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;})&lt;/span&gt;
&lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;watching-resources-in-specific-namespaces&#34;&gt;Watching resources in specific Namespaces&lt;/h3&gt;
&lt;p&gt;To restrict the scope of the &lt;a href=&#34;https://pkg.go.dev/sigs.k8s.io/controller-runtime/pkg/manager#Manager&#34;&gt;Manager&amp;rsquo;s&lt;/a&gt; cache to a specific Namespace, set &lt;code&gt;Cache.DefaultNamespaces&lt;/code&gt;
field in &lt;a href=&#34;https://pkg.go.dev/sigs.k8s.io/controller-runtime/pkg/manager#Options&#34;&gt;Options&lt;/a&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;...&lt;/span&gt;
&lt;span style=&#34;color:#000&#34;&gt;mgr&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;ctrl&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;NewManager&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;ctrl&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;GetConfigOrDie&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(),&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;ctrl&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;Options&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;{&lt;/span&gt;
    &lt;span style=&#34;color:#000&#34;&gt;Scheme&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;             &lt;span style=&#34;color:#000&#34;&gt;scheme&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;,&lt;/span&gt;
    &lt;span style=&#34;color:#000&#34;&gt;MetricsBindAddress&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;metricsAddr&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;,&lt;/span&gt;
    &lt;span style=&#34;color:#000&#34;&gt;Port&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;               &lt;span style=&#34;color:#0000cf;font-weight:bold&#34;&gt;9443&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;,&lt;/span&gt;
    &lt;span style=&#34;color:#000&#34;&gt;LeaderElection&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;     &lt;span style=&#34;color:#000&#34;&gt;enableLeaderElection&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;,&lt;/span&gt;
    &lt;span style=&#34;color:#000&#34;&gt;LeaderElectionID&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;   &lt;span style=&#34;color:#4e9a06&#34;&gt;&amp;#34;f1c5ece8.example.com&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;,&lt;/span&gt;
    &lt;span style=&#34;color:#000&#34;&gt;Cache&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;cache&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;Options&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;{&lt;/span&gt;
      &lt;span style=&#34;color:#000&#34;&gt;DefaultNamespaces&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;map&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;[&lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;string&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;]&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;cache&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;Config&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;{&lt;/span&gt;&lt;span style=&#34;color:#4e9a06&#34;&gt;&amp;#34;operator-namespace&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;cache&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;Config&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;{}},&lt;/span&gt;
    &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;},&lt;/span&gt;
&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;})&lt;/span&gt;
&lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;watching-resources-in-a-set-of-namespaces&#34;&gt;Watching resources in a set of Namespaces&lt;/h3&gt;
&lt;p&gt;It is also possible to use &lt;code&gt;DefaultNamespaces&lt;/code&gt; to watch and manage resources in a set of Namespaces:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;...&lt;/span&gt;
&lt;span style=&#34;color:#000&#34;&gt;mgr&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;ctrl&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;NewManager&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;ctrl&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;GetConfigOrDie&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(),&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;ctrl&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;Options&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;{&lt;/span&gt;
    &lt;span style=&#34;color:#000&#34;&gt;Scheme&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;             &lt;span style=&#34;color:#000&#34;&gt;scheme&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;,&lt;/span&gt;
    &lt;span style=&#34;color:#000&#34;&gt;MetricsBindAddress&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;metricsAddr&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;,&lt;/span&gt;
    &lt;span style=&#34;color:#000&#34;&gt;Port&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;               &lt;span style=&#34;color:#0000cf;font-weight:bold&#34;&gt;9443&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;,&lt;/span&gt;
    &lt;span style=&#34;color:#000&#34;&gt;LeaderElection&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;     &lt;span style=&#34;color:#000&#34;&gt;enableLeaderElection&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;,&lt;/span&gt;
    &lt;span style=&#34;color:#000&#34;&gt;LeaderElectionID&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;   &lt;span style=&#34;color:#4e9a06&#34;&gt;&amp;#34;f1c5ece8.example.com&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;,&lt;/span&gt;
    &lt;span style=&#34;color:#000&#34;&gt;Cache&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;cache&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;Options&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;{&lt;/span&gt;
      &lt;span style=&#34;color:#000&#34;&gt;DefaultNamespaces&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;map&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;[&lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;string&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;]&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;cache&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;Config&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;{&lt;/span&gt;
        &lt;span style=&#34;color:#4e9a06&#34;&gt;&amp;#34;operator-namespace1&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;cache&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;Config&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;{},&lt;/span&gt;
        &lt;span style=&#34;color:#4e9a06&#34;&gt;&amp;#34;operator-namespace2&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;cache&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;Config&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;{},&lt;/span&gt;
      &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;},&lt;/span&gt;
    &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;},&lt;/span&gt;
&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;})&lt;/span&gt;
&lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In the above example, a CR created in a Namespace not in the set passed to &lt;code&gt;Cache.DefaultNamespaces&lt;/code&gt; will not be reconciled by
its controller because the &lt;a href=&#34;https://pkg.go.dev/sigs.k8s.io/controller-runtime/pkg/manager#Manager&#34;&gt;Manager&lt;/a&gt; does not manage that Namespace. Further restrictions and qualifications
can created on a per-namespace basis by setting fields in the cache.Config object, for further information see the
&lt;a href=&#34;https://pkg.go.dev/sigs.k8s.io/controller-runtime/pkg/cache#Config&#34;&gt;controller runtime docs&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;IMPORTANT:&lt;/strong&gt; Note that this is not intended to be used for excluding Namespaces, this is better done via a Predicate.&lt;/p&gt;
&lt;h2 id=&#34;restricting-roles-and-permissions&#34;&gt;Restricting Roles and permissions&lt;/h2&gt;
&lt;p&gt;An operator&amp;rsquo;s scope defines its &lt;a href=&#34;https://pkg.go.dev/sigs.k8s.io/controller-runtime/pkg/manager#Manager&#34;&gt;Manager&amp;rsquo;s&lt;/a&gt; cache&amp;rsquo;s scope but not the permissions to access the resources.
After updating the Manager&amp;rsquo;s scope to be Namespaced, &lt;a href=&#34;https://kubernetes.io/docs/reference/access-authn-authz/rbac/&#34;&gt;Role-Based Access Control (RBAC)&lt;/a&gt; permissions
applied to the operator&amp;rsquo;s service account should be restricted accordingly.&lt;/p&gt;
&lt;p&gt;These permissions are found in the directory &lt;code&gt;config/rbac/&lt;/code&gt;. The &lt;code&gt;ClusterRole&lt;/code&gt; in &lt;code&gt;role.yaml&lt;/code&gt; and &lt;code&gt;ClusterRoleBinding&lt;/code&gt;
in &lt;code&gt;role_binding.yaml&lt;/code&gt; are used to grant the operator permissions to access and manage its resources.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;NOTE&lt;/strong&gt; For changing the operator&amp;rsquo;s scope only the &lt;code&gt;role.yaml&lt;/code&gt; and &lt;code&gt;role_binding.yaml&lt;/code&gt; manifests need to be updated.
For the purposes of this doc, the other RBAC manifests &lt;code&gt;&amp;lt;kind&amp;gt;_editor_role.yaml&lt;/code&gt;, &lt;code&gt;&amp;lt;kind&amp;gt;_viewer_role.yaml&lt;/code&gt;,
and &lt;code&gt;auth_proxy_*.yaml&lt;/code&gt; are not relevant to changing the operator&amp;rsquo;s resource permissions.&lt;/p&gt;
&lt;h3 id=&#34;changing-the-permissions-to-namespaced&#34;&gt;Changing the permissions to Namespaced&lt;/h3&gt;
&lt;p&gt;To change the scope of the RBAC permissions from cluster-wide to a specific namespace, you will need to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Use &lt;code&gt;Role&lt;/code&gt;s instead of &lt;code&gt;ClusterRole&lt;/code&gt;s.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href=&#34;https://book.kubebuilder.io/reference/markers/rbac.html&#34;&gt;&lt;code&gt;RBAC markers&lt;/code&gt;&lt;/a&gt; defined in the controller (e.g &lt;code&gt;controllers/memcached_controller.go&lt;/code&gt;)
are used to generate the operator&amp;rsquo;s &lt;a href=&#34;https://kubernetes.io/docs/reference/access-authn-authz/rbac/#role-and-clusterrole&#34;&gt;RBAC ClusterRole&lt;/a&gt; (e.g &lt;code&gt;config/rbac/role.yaml&lt;/code&gt;). The default
markers don&amp;rsquo;t specify a &lt;code&gt;namespace&lt;/code&gt; property and will result in a &lt;code&gt;ClusterRole&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Update the &lt;a href=&#34;https://book.kubebuilder.io/reference/markers/rbac.html&#34;&gt;&lt;code&gt;RBAC markers&lt;/code&gt;&lt;/a&gt; in &lt;code&gt;&amp;lt;kind&amp;gt;_controller.go&lt;/code&gt; with &lt;code&gt;namespace=&amp;lt;namespace&amp;gt;&lt;/code&gt; where the &lt;code&gt;Role&lt;/code&gt; is to be applied, such as:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;//+kubebuilder:rbac:groups=cache.example.com,namespace=memcached-operator-system,resources=memcacheds,verbs=get;list;watch;create;update;patch;delete
&lt;/span&gt;&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;//+kubebuilder:rbac:groups=cache.example.com,namespace=memcached-operator-system,resources=memcacheds/status,verbs=get;update;patch
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Then run &lt;code&gt;make manifests&lt;/code&gt; to update &lt;code&gt;config/rbac/role.yaml&lt;/code&gt;. In our example it would look like:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;apiVersion&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;rbac.authorization.k8s.io/v1&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;kind&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;Role&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;metadata&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;  &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;creationTimestamp&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;null&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;  &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;name&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;manager-role&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;  &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;namespace&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;memcached-operator-system&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;Use &lt;code&gt;RoleBinding&lt;/code&gt;s instead of &lt;code&gt;ClusterRoleBinding&lt;/code&gt;s. The &lt;code&gt;config/rbac/role_binding.yaml&lt;/code&gt; needs to be manually updated:&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;apiVersion&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;rbac.authorization.k8s.io/v1&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;kind&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;RoleBinding&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;metadata&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;  &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;name&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;manager-rolebinding&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;roleRef&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;  &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;apiGroup&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;rbac.authorization.k8s.io&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;  &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;kind&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;Role&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;  &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;name&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;manager-role&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;subjects&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;&lt;/span&gt;- &lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;kind&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;ServiceAccount&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;  &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;name&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;controller-manager&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;  &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;namespace&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;system&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;!-- todo(camilamacedo86): The need for the RoleBinding show an issue tracked
in https://github.com/kubernetes-sigs/kubebuilder/issues/1496. --&gt;
&lt;h2 id=&#34;configuring-watch-namespaces-dynamically&#34;&gt;Configuring watch namespaces dynamically&lt;/h2&gt;
&lt;p&gt;Instead of having any Namespaces hard-coded in the &lt;code&gt;main.go&lt;/code&gt; file a good practice is to use an environment
variable to allow the restrictive configurations. The one suggested here is &lt;code&gt;WATCH_NAMESPACE&lt;/code&gt;, a
comma-separated list of namespaces passed to the manager at deploy time.&lt;/p&gt;
&lt;h3 id=&#34;configuring-namespace-scoped-operators&#34;&gt;Configuring Namespace scoped operators&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Add a helper function in the &lt;code&gt;main.go&lt;/code&gt; file:&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;// getWatchNamespace returns the Namespace the operator should be watching for changes
&lt;/span&gt;&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;getWatchNamespace&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;string&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;error&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;{&lt;/span&gt;
    &lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;// WatchNamespaceEnvVar is the constant for env variable WATCH_NAMESPACE
&lt;/span&gt;&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;// which specifies the Namespace to watch.
&lt;/span&gt;&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;// An empty value means the operator is running with cluster scope.
&lt;/span&gt;&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;watchNamespaceEnvVar&lt;/span&gt; &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#4e9a06&#34;&gt;&amp;#34;WATCH_NAMESPACE&amp;#34;&lt;/span&gt;

    &lt;span style=&#34;color:#000&#34;&gt;ns&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;found&lt;/span&gt; &lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;os&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;LookupEnv&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;watchNamespaceEnvVar&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;)&lt;/span&gt;
    &lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;!&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;found&lt;/span&gt; &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;{&lt;/span&gt;
        &lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#4e9a06&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;fmt&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;Errorf&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#4e9a06&#34;&gt;&amp;#34;%s must be set&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;watchNamespaceEnvVar&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;)&lt;/span&gt;
    &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;}&lt;/span&gt;
    &lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;ns&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;nil&lt;/span&gt;
&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;Use the environment variable value:&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;...&lt;/span&gt;
&lt;span style=&#34;color:#000&#34;&gt;watchNamespace&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;getWatchNamespace&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;()&lt;/span&gt;
&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;nil&lt;/span&gt; &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;{&lt;/span&gt;
    &lt;span style=&#34;color:#000&#34;&gt;setupLog&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;Error&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;err&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#4e9a06&#34;&gt;&amp;#34;unable to get WatchNamespace, &amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;+&lt;/span&gt;
       &lt;span style=&#34;color:#4e9a06&#34;&gt;&amp;#34;the manager will watch and manage resources in all namespaces&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;)&lt;/span&gt;
&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;}&lt;/span&gt;

&lt;span style=&#34;color:#000&#34;&gt;mgr&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;ctrl&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;NewManager&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;ctrl&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;GetConfigOrDie&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(),&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;ctrl&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;Options&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;{&lt;/span&gt;
    &lt;span style=&#34;color:#000&#34;&gt;Scheme&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;             &lt;span style=&#34;color:#000&#34;&gt;scheme&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;,&lt;/span&gt;
    &lt;span style=&#34;color:#000&#34;&gt;MetricsBindAddress&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;metricsAddr&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;,&lt;/span&gt;
    &lt;span style=&#34;color:#000&#34;&gt;Port&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;               &lt;span style=&#34;color:#0000cf;font-weight:bold&#34;&gt;9443&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;,&lt;/span&gt;
    &lt;span style=&#34;color:#000&#34;&gt;LeaderElection&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;     &lt;span style=&#34;color:#000&#34;&gt;enableLeaderElection&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;,&lt;/span&gt;
    &lt;span style=&#34;color:#000&#34;&gt;LeaderElectionID&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;   &lt;span style=&#34;color:#4e9a06&#34;&gt;&amp;#34;f1c5ece8.example.com&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;,&lt;/span&gt;
    &lt;span style=&#34;color:#000&#34;&gt;Cache&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;cache&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;Options&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;{&lt;/span&gt;
      &lt;span style=&#34;color:#000&#34;&gt;DefaultNamespaces&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;map&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;[&lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;string&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;]&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;cache&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;Config&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;{&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;watchNamespace&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;cache&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;Config&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;{}},&lt;/span&gt;
    &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;},&lt;/span&gt;
&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;})&lt;/span&gt;
&lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;Define the environment variable in the &lt;code&gt;config/manager/manager.yaml&lt;/code&gt;:&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;spec&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;  &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;containers&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;  &lt;/span&gt;- &lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;command&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;    &lt;/span&gt;- /manager&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;args&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;    &lt;/span&gt;- --leader-elect&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;image&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;controller&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;latest&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;name&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;manager&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;resources&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;      &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;limits&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;        &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;cpu&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;100m&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;        &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;memory&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;30Mi&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;      &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;requests&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;        &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;cpu&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;100m&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;        &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;memory&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;20Mi&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;env&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;      &lt;/span&gt;- &lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;name&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;WATCH_NAMESPACE&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;        &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;valueFrom&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;          &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;fieldRef&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;            &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;fieldPath&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;metadata.namespace&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;  &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;terminationGracePeriodSeconds&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#0000cf;font-weight:bold&#34;&gt;10&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;NOTE&lt;/strong&gt; &lt;code&gt;WATCH_NAMESPACE&lt;/code&gt; here will always be set as the namespace where the operator is deployed.&lt;/p&gt;
&lt;h3 id=&#34;configuring-cluster-scoped-operators-with-multinamespacedcachebuilder&#34;&gt;Configuring cluster-scoped operators with MultiNamespacedCacheBuilder&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Add a helper function to get the environment variable value in the &lt;code&gt;main.go&lt;/code&gt; file as done in the previous example (e.g &lt;code&gt;getWatchNamespace()&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Use the environment variable value and check if it is a multi-namespace scenario:&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;    &lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;...&lt;/span&gt;
&lt;span style=&#34;color:#000&#34;&gt;watchNamespace&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;getWatchNamespace&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;()&lt;/span&gt;
&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;nil&lt;/span&gt; &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;{&lt;/span&gt;
    &lt;span style=&#34;color:#000&#34;&gt;setupLog&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;Error&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;err&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#4e9a06&#34;&gt;&amp;#34;unable to get WatchNamespace, &amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;+&lt;/span&gt;
        &lt;span style=&#34;color:#4e9a06&#34;&gt;&amp;#34;the manager will watch and manage resources in all Namespaces&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;)&lt;/span&gt;
&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;}&lt;/span&gt;

&lt;span style=&#34;color:#000&#34;&gt;options&lt;/span&gt; &lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;ctrl&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;Options&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;{&lt;/span&gt;
    &lt;span style=&#34;color:#000&#34;&gt;Scheme&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;             &lt;span style=&#34;color:#000&#34;&gt;scheme&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;,&lt;/span&gt;
    &lt;span style=&#34;color:#000&#34;&gt;MetricsBindAddress&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;metricsAddr&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;,&lt;/span&gt;
    &lt;span style=&#34;color:#000&#34;&gt;Port&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;               &lt;span style=&#34;color:#0000cf;font-weight:bold&#34;&gt;9443&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;,&lt;/span&gt;
    &lt;span style=&#34;color:#000&#34;&gt;LeaderElection&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;     &lt;span style=&#34;color:#000&#34;&gt;enableLeaderElection&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;,&lt;/span&gt;
    &lt;span style=&#34;color:#000&#34;&gt;LeaderElectionID&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;   &lt;span style=&#34;color:#4e9a06&#34;&gt;&amp;#34;f1c5ece8.example.com&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;,&lt;/span&gt;
    &lt;span style=&#34;color:#000&#34;&gt;Cache&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;cache&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;Options&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;{&lt;/span&gt;
      &lt;span style=&#34;color:#000&#34;&gt;DefaultNamespaces&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;map&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;[&lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;string&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;]&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;cache&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;Config&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;{&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;watchNamespace&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;cache&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;Config&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;{}},&lt;/span&gt;
    &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;},&lt;/span&gt;
&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;}&lt;/span&gt;

&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;// Add support for MultiNamespace set in WATCH_NAMESPACE (e.g ns1,ns2)
&lt;/span&gt;&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;strings&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;Contains&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;watchNamespace&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#4e9a06&#34;&gt;&amp;#34;,&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;{&lt;/span&gt;
    &lt;span style=&#34;color:#000&#34;&gt;setupLog&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;Info&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#4e9a06&#34;&gt;&amp;#34;manager set up with multiple namespaces&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#4e9a06&#34;&gt;&amp;#34;namespaces&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;watchNamespace&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;)&lt;/span&gt;
    &lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;// configure cluster-scoped with MultiNamespacedCacheBuilder
&lt;/span&gt;&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#000&#34;&gt;options&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;Namespace&lt;/span&gt; &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#4e9a06&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;
    &lt;span style=&#34;color:#000&#34;&gt;options&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;NewCache&lt;/span&gt; &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;cache&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;MultiNamespacedCacheBuilder&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;strings&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;Split&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;watchNamespace&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#4e9a06&#34;&gt;&amp;#34;,&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;))&lt;/span&gt;
&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;Define the environment variable in the &lt;code&gt;config/manager/manager.yaml&lt;/code&gt;:&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;...&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;env&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;      &lt;/span&gt;- &lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;name&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;WATCH_NAMESPACE&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;        &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;value&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#4e9a06&#34;&gt;&amp;#34;ns1,ns2&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;  &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;terminationGracePeriodSeconds&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#0000cf;font-weight:bold&#34;&gt;10&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;&lt;/span&gt;...&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;updating-your-csvs-installmodes&#34;&gt;Updating your CSV&amp;rsquo;s installModes&lt;/h2&gt;
&lt;p&gt;If your operator is &lt;a href=&#34;/docs/olm-integration&#34;&gt;integrated with OLM&lt;/a&gt;, you will want to update your &lt;a href=&#34;/docs/olm-integration/generation/#kustomize-files&#34;&gt;CSV base&amp;rsquo;s&lt;/a&gt;
&lt;code&gt;spec.installModes&lt;/code&gt; list to support the desired namespacing requirements. Support for multiple types of namespacing
is allowed, so supporting multiple install modes in a CSV is permitted. After doing so, update your
&lt;a href=&#34;/docs/olm-integration/quickstart-bundle&#34;&gt;bundle&lt;/a&gt; or &lt;a href=&#34;/docs/olm-integration/tutorial-package-manifests&#34;&gt;package manifests&lt;/a&gt; by following the linked guides.&lt;/p&gt;
&lt;h3 id=&#34;watching-resources-in-all-namespaces-default-1&#34;&gt;Watching resources in all Namespaces (default)&lt;/h3&gt;
&lt;p&gt;Only the &lt;code&gt;AllNamespaces&lt;/code&gt; install mode is &lt;code&gt;supported: true&lt;/code&gt; by default, so no changes are required.&lt;/p&gt;
&lt;h3 id=&#34;watching-resources-in-a-single-namespace&#34;&gt;Watching resources in a single Namespace&lt;/h3&gt;
&lt;p&gt;If the operator can watch its own namespace, set the following in your &lt;code&gt;spec.installModes&lt;/code&gt; list:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;  &lt;/span&gt;- &lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;type&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;OwnNamespace&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;supported&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;true&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If the operator can watch a single namespace that is not its own, set the following in your &lt;code&gt;spec.installModes&lt;/code&gt; list:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;  &lt;/span&gt;- &lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;type&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;SingleNamespace&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;supported&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;true&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;watching-resources-in-multiple-namespaces&#34;&gt;Watching resources in multiple Namespaces&lt;/h3&gt;
&lt;p&gt;If the operator can watch multiple namespaces, set the following in your &lt;code&gt;spec.installModes&lt;/code&gt; list:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;  &lt;/span&gt;- &lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;type&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;MultiNamespace&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;supported&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;true&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
      </description>
    </item>
    
    <item>
      <title>Docs: CRD Scope</title>
      <link>/docs/building-operators/golang/crds-scope/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      
      <guid>/docs/building-operators/golang/crds-scope/</guid>
      <description>
        
        
        &lt;h2 id=&#34;overview&#34;&gt;Overview&lt;/h2&gt;
&lt;p&gt;This page details the various methods to control the scope of a CRD. See the &lt;a href=&#34;/docs/building-operators/golang/operator-scope/&#34;&gt;operator scope doc&lt;/a&gt; for information on configuring operator scope, such as which namespaces to watch.&lt;/p&gt;
&lt;p&gt;Custom Resource Definitions (CRDs) contain a scope field that determines whether the resulting Custom Resource (CR)
is cluster or namespace scoped. An operator author might use a namespaced-scoped CRD
to restrict access to a CR to certain namespaces, or to have different versions of CRs accessible in different namespaces.
Alternatively, an operator author might want a cluster-scoped CRD so all namespaces have visibility and access to CRs.&lt;/p&gt;
&lt;p&gt;The CRD manifests are generated by the &lt;code&gt;operator-sdk create api&lt;/code&gt; command in &lt;code&gt;config/crd/bases&lt;/code&gt;. A CRD&amp;rsquo;s &lt;code&gt;spec.scope&lt;/code&gt; field controls API scope; valid values are &lt;a href=&#34;https://kubernetes.io/docs/tasks/extend-kubernetes/custom-resources/custom-resource-definitions/#create-a-customresourcedefinition&#34;&gt;&lt;code&gt;Cluster&lt;/code&gt; and &lt;code&gt;Namespaced&lt;/code&gt;&lt;/a&gt;.
For an Operator-sdk Go project, this value is determined by the &lt;code&gt;operator-sdk create api --namespaced&lt;/code&gt; boolean flag, which edits the
&lt;code&gt;types.go&lt;/code&gt; file for the resource. For other operator types, the command edits &lt;code&gt;spec.scope&lt;/code&gt; in the CRD&amp;rsquo;s YAML manifest directly.&lt;/p&gt;
&lt;h2 id=&#34;set-create-api---namespaced-flag&#34;&gt;Set &lt;code&gt;create api&lt;/code&gt; &amp;ndash;namespaced flag&lt;/h2&gt;
&lt;p&gt;When creating a new API, the &lt;code&gt;--namespaced&lt;/code&gt; flag controls whether the resulting CRD will be cluster or namespace scoped.
By default, &lt;code&gt;--namespaced&lt;/code&gt; is set to &lt;code&gt;true&lt;/code&gt; which sets the scope to &lt;code&gt;Namespaced&lt;/code&gt;. An example command to create a cluster-scoped API would be:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-console&#34; data-lang=&#34;console&#34;&gt;$ operator-sdk create api --group cache --version v1alpha1 --kind Memcached --resource=true --controller=true --namespaced=false
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&#34;set-scope-marker-in-typesgo&#34;&gt;Set Scope Marker in types.go&lt;/h2&gt;
&lt;p&gt;You can also manually set the scope in the Go &lt;code&gt;types.go&lt;/code&gt; file by adding or changing the &lt;a href=&#34;https://book.kubebuilder.io/reference/markers/crd.html&#34;&gt;kubebuilder scope marker&lt;/a&gt;
to your resource. This file is usually located in &lt;code&gt;api/&amp;lt;version&amp;gt;/&amp;lt;kind&amp;gt;_types.go&lt;/code&gt; or &lt;code&gt;apis/&amp;lt;group&amp;gt;/&amp;lt;version&amp;gt;/&amp;lt;kind&amp;gt;_types.go&lt;/code&gt; if
you are using the &lt;a href=&#34;https://book.kubebuilder.io/migration/multi-group.html&#34;&gt;multigroup&lt;/a&gt; layout. Once this marker is set, the CRD files will be generated with the approriate scope.
Here is an example API type with the marker set to cluster scope:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-golang&#34; data-lang=&#34;golang&#34;&gt;&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;//+kubebuilder:object:root=true
&lt;/span&gt;&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;//+kubebuilder:subresource:status
&lt;/span&gt;&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;//+kubebuilder:resource:scope=Cluster
&lt;/span&gt;&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;&lt;/span&gt;
&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;// Memcached is the Schema for the memcacheds API
&lt;/span&gt;&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;Memcached&lt;/span&gt; &lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;struct&lt;/span&gt; &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;{&lt;/span&gt;
	&lt;span style=&#34;color:#000&#34;&gt;metav1&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;TypeMeta&lt;/span&gt;   &lt;span style=&#34;color:#4e9a06&#34;&gt;`json:&amp;#34;,inline&amp;#34;`&lt;/span&gt;
	&lt;span style=&#34;color:#000&#34;&gt;metav1&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;ObjectMeta&lt;/span&gt; &lt;span style=&#34;color:#4e9a06&#34;&gt;`json:&amp;#34;metadata,omitempty&amp;#34;`&lt;/span&gt;

	&lt;span style=&#34;color:#000&#34;&gt;Spec&lt;/span&gt;   &lt;span style=&#34;color:#000&#34;&gt;MemcachedSpec&lt;/span&gt;   &lt;span style=&#34;color:#4e9a06&#34;&gt;`json:&amp;#34;spec,omitempty&amp;#34;`&lt;/span&gt;
	&lt;span style=&#34;color:#000&#34;&gt;Status&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;MemcachedStatus&lt;/span&gt; &lt;span style=&#34;color:#4e9a06&#34;&gt;`json:&amp;#34;status,omitempty&amp;#34;`&lt;/span&gt;
&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;To set the scope to namespaced, the marker would be set to &lt;code&gt;//+kubebuilder:resource:scope=Namespaced&lt;/code&gt; instead.&lt;/p&gt;
&lt;h2 id=&#34;set-scope-in-crd-yaml-file&#34;&gt;Set scope in CRD YAML file&lt;/h2&gt;
&lt;p&gt;The scope can be manually set directly in the CRD&amp;rsquo;s Kind YAML file, normally located in  &lt;code&gt;config/crd/bases/&amp;lt;group&amp;gt;.&amp;lt;domain&amp;gt;_&amp;lt;kind&amp;gt;.yaml&lt;/code&gt;.
An example YAML file for a namespace-scoped CRD is shown below:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-YAML&#34; data-lang=&#34;YAML&#34;&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;apiVersion&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;apiextensions.k8s.io/v1beta1&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;kind&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;CustomResourceDefinition&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;metadata&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;  &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;annotations&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;controller-gen.kubebuilder.io/version&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;v0&lt;span style=&#34;color:#0000cf;font-weight:bold&#34;&gt;.2.5&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;  &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;creationTimestamp&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;null&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;  &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;name&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;memcacheds.cache.example.com&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;spec&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;  &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;group&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;cache.example.com&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;  &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;names&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;kind&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;Memcached&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;listKind&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;MemcachedList&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;plural&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;memcacheds&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;singular&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;memcached&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;  &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;scope&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;Namespaced&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;  &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;subresources&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;status&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;{}&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;&lt;/span&gt;...&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;   
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
      </description>
    </item>
    
    <item>
      <title>Docs: Testing your Operator project</title>
      <link>/docs/building-operators/golang/testing/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      
      <guid>/docs/building-operators/golang/testing/</guid>
      <description>
        
        
        &lt;h2 id=&#34;overview&#34;&gt;Overview&lt;/h2&gt;
&lt;p&gt;The Operator SDK project recommends using controller-runtime&amp;rsquo;s &lt;a href=&#34;https://pkg.go.dev/sigs.k8s.io/controller-runtime/pkg/envtest&#34;&gt;envtest&lt;/a&gt; to write tests for your Operators projects. Envtest has a more active contributor community, it is more mature than Operator SDK&amp;rsquo;s test framework, and it does not require an actual cluster to run tests which can be a huge benefit in CI scenarios.&lt;/p&gt;
&lt;h2 id=&#34;using-envtest&#34;&gt;Using EnvTest&lt;/h2&gt;
&lt;p&gt;You will see that &lt;code&gt;controllers/suite_test.go&lt;/code&gt; is created when a controller is scaffolded by the tool. This file contains boilerplate for executing integration tests using &lt;a href=&#34;https://pkg.go.dev/sigs.k8s.io/controller-runtime/pkg/envtest&#34;&gt;envtest&lt;/a&gt; with &lt;a href=&#34;https://onsi.github.io/ginkgo/&#34;&gt;ginkgo&lt;/a&gt; and &lt;a href=&#34;https://onsi.github.io/gomega/&#34;&gt;gomega&lt;/a&gt;.
Setup instructions, including those for disconnected environments, are found &lt;a href=&#34;https://book.kubebuilder.io/reference/envtest.html&#34;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;These tests are runnable as native Go tests:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;go &lt;span style=&#34;color:#204a87&#34;&gt;test&lt;/span&gt; controllers/ -v -ginkgo.v
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The projects generated by using the SDK tool have a Makefile which contains the target tests which executes when you run &lt;code&gt;make test&lt;/code&gt;. Note that this target will also execute when you run &lt;code&gt;make docker-build IMG=&amp;lt;some-registry&amp;gt;/&amp;lt;project-name&amp;gt;:&amp;lt;tag&amp;gt;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Operator SDK adopted this stack to write tests for its operators. It might be useful to check &lt;a href=&#34;https://book.kubebuilder.io/cronjob-tutorial/writing-tests.html&#34;&gt;writing controller tests&lt;/a&gt; documentation and examples to learn how to better write tests for your operator. See, for example, that &lt;a href=&#34;https://github.com/kubernetes-sigs/controller-runtime&#34;&gt;controller-runtime&lt;/a&gt; is covered by tests using the same stack as well.&lt;/p&gt;
&lt;h2 id=&#34;e2e-integration-tests&#34;&gt;e2e Integration tests&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;For Golang-based operators&lt;/strong&gt;: you can create the e2e tests using Go. See the &lt;code&gt;test&lt;/code&gt; directory for the Memcached sample
under the &lt;a href=&#34;https://github.com/operator-framework/operator-sdk/tree/master/testdata/go/v4/memcached-operator&#34;&gt;testdata/go/v3/memcached-operator&lt;/a&gt; to see an example of e2e tests.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;For Ansible-based operators&lt;/strong&gt;: you can use &lt;a href=&#34;https://molecule.readthedocs.io/&#34;&gt;Molecule&lt;/a&gt;, an Ansible testing framework. For further information see &lt;a href=&#34;/docs/building-operators/ansible/testing-guide&#34;&gt;Testing with Molecule&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;For Helm-based operators&lt;/strong&gt;: you can also use &lt;a href=&#34;https://helm.sh/docs/topics/chart_tests/&#34;&gt;Chart tests&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Alternatively, you can achieve the same goal using shell scripts. The following are a few examples of shell scripts
used for testing projects built with SDK &lt;code&gt;1.0.0&lt;/code&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/operator-framework/operator-sdk/blob/v1.0.0/hack/tests/e2e-go.sh&#34;&gt;Legacy test to check Golang-based Operators&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/operator-framework/operator-sdk/blob/v1.0.0/hack/tests/e2e-helm.sh&#34;&gt;Legacy test to check Helm-based Operators&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/operator-framework/operator-sdk/blob/v1.0.0/hack/tests/e2e-ansible.sh&#34;&gt;Legacy test to check Ansible-based Operators&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;other-options&#34;&gt;Other Options&lt;/h2&gt;
&lt;p&gt;Also, you can write tests for your operator in a declarative format using &lt;a href=&#34;https://github.com/kudobuilder/kuttl/&#34;&gt;kuttl&lt;/a&gt;. Via kuttl, you can define YAML manifests that specify the expected before and after states of a cluster when your operator is used. For more info see &lt;a href=&#34;/docs/testing-operators/scorecard/kuttl-tests&#34;&gt;Writing Kuttl Scorecard Tests&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;An alternative and more modern solution to kuttl is &lt;a href=&#34;https://kyverno.github.io/chainsaw/latest/&#34;&gt;chainsaw&lt;/a&gt;. Chainsaw offers more flexibility, a rich assertion model, and is actively maintained. Tests from kuttl can be automatically converted to chainsaw, see &lt;a href=&#34;https://kyverno.github.io/chainsaw/latest/guides/kuttl-migration&#34;&gt;Migration from KUTTL&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;To implement application-specific tests, the SDK&amp;rsquo;s test harness, &lt;a href=&#34;/docs/testing-operators/scorecard/&#34;&gt;scorecard&lt;/a&gt;, provides the ability to ship custom code in container images as well, which can be referenced in the test suite. Because this test suite definition metadata travels with the Operator Bundle, it allows for functional testing of the Operator without the source code or the project layout being available. See &lt;a href=&#34;/docs/testing-operators/scorecard/custom-tests&#34;&gt;Writing Custom Scorecard Tests&lt;/a&gt;.&lt;/p&gt;

      </description>
    </item>
    
    <item>
      <title>Docs: Advanced Topics</title>
      <link>/docs/building-operators/golang/advanced-topics/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      
      <guid>/docs/building-operators/golang/advanced-topics/</guid>
      <description>
        
        
        &lt;h3 id=&#34;manage-cr-status-conditions&#34;&gt;Manage CR status conditions&lt;/h3&gt;
&lt;p&gt;An often-used pattern is to include &lt;code&gt;Conditions&lt;/code&gt; in the status of custom resources. A &lt;a href=&#34;https://github.com/kubernetes/apimachinery/blob/d4f471b82f0a17cda946aeba446770563f92114d/pkg/apis/meta/v1/types.go#L1368&#34;&gt;&lt;code&gt;Condition&lt;/code&gt;&lt;/a&gt; represents the latest available observations of an object&amp;rsquo;s state (see the &lt;a href=&#34;https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#typical-status-properties&#34;&gt;Kubernetes API conventions documentation&lt;/a&gt; for more information).&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;Conditions&lt;/code&gt; field added to the &lt;code&gt;MemcachedStatus&lt;/code&gt; struct simplifies the management of your CR&amp;rsquo;s conditions. It:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Enables callers to add and remove conditions.&lt;/li&gt;
&lt;li&gt;Ensures that there are no duplicates.&lt;/li&gt;
&lt;li&gt;Sorts the conditions deterministically to avoid unnecessary repeated reconciliations.&lt;/li&gt;
&lt;li&gt;Automatically handles the each condition&amp;rsquo;s &lt;code&gt;LastTransitionTime&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Provides helper methods to make it easy to determine the state of a condition.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To use conditions in your custom resource, add a Conditions field to the Status struct in &lt;code&gt;_types.go&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-Go&#34; data-lang=&#34;Go&#34;&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;import&lt;/span&gt; &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(&lt;/span&gt;
    &lt;span style=&#34;color:#000&#34;&gt;metav1&lt;/span&gt; &lt;span style=&#34;color:#4e9a06&#34;&gt;&amp;#34;k8s.io/apimachinery/pkg/apis/meta/v1&amp;#34;&lt;/span&gt;
&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;)&lt;/span&gt;

&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;MyAppStatus&lt;/span&gt; &lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;struct&lt;/span&gt; &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;{&lt;/span&gt;
    &lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;// Conditions represent the latest available observations of an object&amp;#39;s state
&lt;/span&gt;&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#000&#34;&gt;Conditions&lt;/span&gt; &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;[]&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;metav1&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;Condition&lt;/span&gt; &lt;span style=&#34;color:#4e9a06&#34;&gt;`json:&amp;#34;conditions&amp;#34;`&lt;/span&gt;
&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Then, in your controller, you can use &lt;a href=&#34;https://github.com/kubernetes/apimachinery/blob/master/pkg/api/meta/conditions.go&#34;&gt;&lt;code&gt;Conditions&lt;/code&gt;&lt;/a&gt; methods to make it easier to set and remove conditions or check their current values.&lt;/p&gt;
&lt;h3 id=&#34;adding-3rd-party-resources-to-your-operator&#34;&gt;Adding 3rd Party Resources To Your Operator&lt;/h3&gt;
&lt;p&gt;The operator&amp;rsquo;s Manager supports the core Kubernetes resource types as found in the client-go &lt;a href=&#34;https://github.com/kubernetes/client-go/blob/master/kubernetes/scheme/register.go&#34;&gt;scheme&lt;/a&gt; package and will also register the schemes of all custom resource types defined in your project.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-Go&#34; data-lang=&#34;Go&#34;&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;import&lt;/span&gt; &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(&lt;/span&gt;
    &lt;span style=&#34;color:#000&#34;&gt;cachev1alpha1&lt;/span&gt; &lt;span style=&#34;color:#a40000&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;github&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;com&lt;/span&gt;&lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;example&lt;/span&gt;&lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;memcached&lt;/span&gt;&lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;operator&lt;/span&gt;&lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;api&lt;/span&gt;&lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;v1alpha1&lt;/span&gt;
    &lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;...&lt;/span&gt;
&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;)&lt;/span&gt;

&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;init&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;{&lt;/span&gt;

    &lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;// Setup Scheme for all resources
&lt;/span&gt;&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#000&#34;&gt;utilruntime&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;Must&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;cachev1alpha1&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;AddToScheme&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;scheme&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;))&lt;/span&gt;
    &lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;//+kubebuilder:scaffold:scheme
&lt;/span&gt;&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;To add a 3rd party resource to an operator, you must add it to the Manager&amp;rsquo;s scheme. By creating an &lt;code&gt;AddToScheme()&lt;/code&gt; method or reusing one you can easily add a resource to your scheme. An &lt;a href=&#34;https://github.com/kubernetes/api/blob/master/apps/v1/register.go#L41&#34;&gt;example&lt;/a&gt; shows that you define a function and then use the &lt;a href=&#34;https://pkg.go.dev/k8s.io/apimachinery/pkg/runtime&#34;&gt;runtime&lt;/a&gt; package to create a &lt;code&gt;SchemeBuilder&lt;/code&gt;.&lt;/p&gt;
&lt;h4 id=&#34;register-with-the-managers-scheme&#34;&gt;Register with the Manager&amp;rsquo;s scheme&lt;/h4&gt;
&lt;p&gt;Call the &lt;code&gt;AddToScheme()&lt;/code&gt; function for your 3rd party resource and pass it the Manager&amp;rsquo;s scheme via &lt;code&gt;mgr.GetScheme()&lt;/code&gt; or &lt;code&gt;scheme&lt;/code&gt; in &lt;code&gt;main.go&lt;/code&gt;.
Example:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;import&lt;/span&gt; &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(&lt;/span&gt;
    &lt;span style=&#34;color:#000&#34;&gt;routev1&lt;/span&gt; &lt;span style=&#34;color:#4e9a06&#34;&gt;&amp;#34;github.com/openshift/api/route/v1&amp;#34;&lt;/span&gt;
&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;)&lt;/span&gt;

&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;init&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;{&lt;/span&gt;
    &lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;...&lt;/span&gt;

    &lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;// Adding the routev1
&lt;/span&gt;&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#000&#34;&gt;utilruntime&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;Must&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;clientgoscheme&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;AddToScheme&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;scheme&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;))&lt;/span&gt;

    &lt;span style=&#34;color:#000&#34;&gt;utilruntime&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;Must&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;routev1&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;AddToScheme&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;scheme&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;))&lt;/span&gt;
    &lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;//+kubebuilder:scaffold:scheme
&lt;/span&gt;&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;&lt;/span&gt;
    &lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;...&lt;/span&gt;
&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h5 id=&#34;if-3rd-party-resource-does-not-have-addtoscheme-function&#34;&gt;If 3rd party resource does not have &lt;code&gt;AddToScheme()&lt;/code&gt; function&lt;/h5&gt;
&lt;p&gt;Use the &lt;a href=&#34;https://pkg.go.dev/sigs.k8s.io/controller-runtime/pkg/scheme#Builder&#34;&gt;SchemeBuilder&lt;/a&gt; package from controller-runtime to initialize a new scheme builder that can be used to register the 3rd party resource with the manager&amp;rsquo;s scheme.&lt;/p&gt;
&lt;p&gt;Example of registering &lt;code&gt;DNSEndpoints&lt;/code&gt; 3rd party resource from &lt;code&gt;external-dns&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;import&lt;/span&gt; &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(&lt;/span&gt;
    &lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;...&lt;/span&gt;
    &lt;span style=&#34;color:#4e9a06&#34;&gt;&amp;#34;k8s.io/apimachinery/pkg/runtime/schema&amp;#34;&lt;/span&gt;
    &lt;span style=&#34;color:#4e9a06&#34;&gt;&amp;#34;sigs.k8s.io/controller-runtime/pkg/scheme&amp;#34;&lt;/span&gt;
    &lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;...&lt;/span&gt;
    &lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;// DNSEndpoints
&lt;/span&gt;&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#000&#34;&gt;externaldns&lt;/span&gt; &lt;span style=&#34;color:#4e9a06&#34;&gt;&amp;#34;github.com/kubernetes-incubator/external-dns/endpoint&amp;#34;&lt;/span&gt;
    &lt;span style=&#34;color:#000&#34;&gt;metav1&lt;/span&gt; &lt;span style=&#34;color:#4e9a06&#34;&gt;&amp;#34;k8s.io/apimachinery/pkg/apis/meta/v1&amp;#34;&lt;/span&gt;
 &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;)&lt;/span&gt;

&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;init&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;{&lt;/span&gt;
    &lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;...&lt;/span&gt;

    &lt;span style=&#34;color:#000&#34;&gt;log&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;Info&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#4e9a06&#34;&gt;&amp;#34;Registering Components.&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;)&lt;/span&gt;

    &lt;span style=&#34;color:#000&#34;&gt;schemeBuilder&lt;/span&gt; &lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;scheme&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;Builder&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;{&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;GroupVersion&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;schema&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;GroupVersion&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;{&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;Group&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#4e9a06&#34;&gt;&amp;#34;externaldns.k8s.io&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;Version&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#4e9a06&#34;&gt;&amp;#34;v1alpha1&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;}}&lt;/span&gt;
    &lt;span style=&#34;color:#000&#34;&gt;schemeBuilder&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;Register&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;externaldns&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;DNSEndpoint&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;{},&lt;/span&gt; &lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;externaldns&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;DNSEndpointList&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;{})&lt;/span&gt;
    &lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;schemeBuilder&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;AddToScheme&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;mgr&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;GetScheme&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;());&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;nil&lt;/span&gt; &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;{&lt;/span&gt;
        &lt;span style=&#34;color:#000&#34;&gt;log&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;Error&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;err&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#4e9a06&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;)&lt;/span&gt;
        &lt;span style=&#34;color:#000&#34;&gt;os&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;Exit&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#0000cf;font-weight:bold&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;)&lt;/span&gt;
    &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;}&lt;/span&gt;

    &lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;...&lt;/span&gt;
&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;NOTES:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;After adding new import paths to your operator project, run &lt;code&gt;go mod vendor&lt;/code&gt; if a &lt;code&gt;vendor/&lt;/code&gt; directory is present in the root of your project directory to fulfill these dependencies.&lt;/li&gt;
&lt;li&gt;Your 3rd party resource needs to be added before add the controller in &lt;code&gt;&amp;quot;Setup all Controllers&amp;quot;&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;monitoring-and-observability&#34;&gt;Monitoring and Observability&lt;/h3&gt;
&lt;p&gt;This section covers how to create custom metrics, &lt;a href=&#34;https://prometheus.io/docs/prometheus/latest/configuration/alerting_rules/&#34;&gt;alerts&lt;/a&gt; and &lt;a href=&#34;https://prometheus.io/docs/prometheus/latest/configuration/recording_rules/&#34;&gt;recording rules&lt;/a&gt; for your operator. It focuses on the technical aspects, and demonstrates the implementation by updating the sample &lt;a href=&#34;https://github.com/operator-framework/operator-sdk/tree/master/testdata/go/v4/monitoring/memcached-operator&#34;&gt;memcached-operator&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;For more information regarding monitoring best practices, take a look at our docs on &lt;a href=&#34;https://sdk.operatorframework.io/docs/best-practices/observability-best-practices/&#34;&gt;observability-best-practices&lt;/a&gt;.&lt;/p&gt;
&lt;h4 id=&#34;prerequisites&#34;&gt;Prerequisites&lt;/h4&gt;
&lt;p&gt;The following steps are required in order to inspect the operator&amp;rsquo;s custom metrics, alerts and recording rules:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Install Prometheus and Prometheus Operator. We recommend using &lt;a href=&#34;https://github.com/prometheus-operator/kube-prometheus&#34;&gt;kube-prometheus&lt;/a&gt; in production if you don’t have your own monitoring system. If you are just experimenting, you can only install Prometheus and Prometheus Operator.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Make sure Prometheus has access to the operator&amp;rsquo;s namespace, by setting the corresponding RBAC rules.&lt;/p&gt;
&lt;p&gt;Example: &lt;a href=&#34;https://github.com/operator-framework/operator-sdk/blob/master/testdata/go/v4/monitoring/memcached-operator/config/rbac/prometheus_role.yaml&#34;&gt;prometheus_role.yaml&lt;/a&gt; and &lt;a href=&#34;https://github.com/operator-framework/operator-sdk/blob/master/testdata/go/v4/monitoring/memcached-operator/config/rbac/prometheus_role_binding.yaml&#34;&gt;prometheus_role_binding.yaml&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&#34;publishing-custom-metrics&#34;&gt;Publishing Custom Metrics&lt;/h4&gt;
&lt;p&gt;If you wish to publish custom metrics for your operator, this can be easily achieved by using the global registry from &lt;code&gt;controller-runtime/pkg/metrics&lt;/code&gt;.
One way to achieve this is to declare your collectors as global variables, register them using &lt;code&gt;RegisterMetrics()&lt;/code&gt; and call it in the controller&amp;rsquo;s &lt;code&gt;init()&lt;/code&gt; function.&lt;/p&gt;
&lt;p&gt;Example custom metric: &lt;a href=&#34;https://github.com/operator-framework/operator-sdk/blob/master/testdata/go/v4/monitoring/memcached-operator/monitoring/metrics.go&#34;&gt;MemcachedDeploymentSizeUndesiredCountTotal&lt;/a&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;package&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;monitoring&lt;/span&gt;

&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;import&lt;/span&gt; &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(&lt;/span&gt;
	&lt;span style=&#34;color:#4e9a06&#34;&gt;&amp;#34;github.com/prometheus/client_golang/prometheus&amp;#34;&lt;/span&gt;
	&lt;span style=&#34;color:#4e9a06&#34;&gt;&amp;#34;sigs.k8s.io/controller-runtime/pkg/metrics&amp;#34;&lt;/span&gt;
&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;)&lt;/span&gt;

&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(&lt;/span&gt;
	&lt;span style=&#34;color:#000&#34;&gt;MemcachedDeploymentSizeUndesiredCountTotal&lt;/span&gt; &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;prometheus&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;NewCounter&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(&lt;/span&gt;
		&lt;span style=&#34;color:#000&#34;&gt;prometheus&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;CounterOpts&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;{&lt;/span&gt;
			&lt;span style=&#34;color:#000&#34;&gt;Name&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#4e9a06&#34;&gt;&amp;#34;memcached_deployment_size_undesired_count_total&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;,&lt;/span&gt;
			&lt;span style=&#34;color:#000&#34;&gt;Help&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#4e9a06&#34;&gt;&amp;#34;Total number of times the deployment size was not as desired.&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;,&lt;/span&gt;
		&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;},&lt;/span&gt;
	&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;)&lt;/span&gt;
&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;)&lt;/span&gt;

&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;// RegisterMetrics will register metrics with the global prometheus registry
&lt;/span&gt;&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;RegisterMetrics&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;{&lt;/span&gt;
	&lt;span style=&#34;color:#000&#34;&gt;metrics&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;Registry&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;MustRegister&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;MemcachedDeploymentSizeUndesiredCountTotal&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;)&lt;/span&gt;
&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;The above example creates a new &lt;code&gt;Counter&lt;/code&gt; metric. For other metrics&amp;rsquo; types, see &lt;a href=&#34;https://prometheus.io/docs/concepts/metric_types/&#34;&gt;Prometheus Documentation&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;For more information regarding operators metrics best-practices, please follow &lt;a href=&#34;https://sdk.operatorframework.io/docs/best-practices/observability-best-practices/&#34;&gt;observability-best-practices&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href=&#34;https://github.com/operator-framework/operator-sdk/blob/master/testdata/go/v4/monitoring/memcached-operator/cmd/main.go&#34;&gt;init() function example&lt;/a&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;package&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;main&lt;/span&gt;


&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;import&lt;/span&gt; &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(&lt;/span&gt;
   &lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;...&lt;/span&gt;
   &lt;span style=&#34;color:#4e9a06&#34;&gt;&amp;#34;github.com/example/memcached-operator/monitoring&amp;#34;&lt;/span&gt;
&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;)&lt;/span&gt;

&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;init&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;{&lt;/span&gt;
   &lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;...&lt;/span&gt;
   &lt;span style=&#34;color:#000&#34;&gt;monitoring&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;RegisterMetrics&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;()&lt;/span&gt;
   &lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;...&lt;/span&gt;
&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The next step would be to set the controller&amp;rsquo;s logic according to which we update the metric&amp;rsquo;s value. In this case, the new metric type is &lt;code&gt;Counter&lt;/code&gt;, thus a valid update operation would be to increment its value.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://github.com/operator-framework/operator-sdk/blob/master/testdata/go/v4/monitoring/memcached-operator/internal/controller/memcached_controller.go&#34;&gt;Metric update example&lt;/a&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;...&lt;/span&gt;
&lt;span style=&#34;color:#000&#34;&gt;size&lt;/span&gt; &lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;memcached&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;Spec&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;Size&lt;/span&gt;
&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;found&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;Spec&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;Replicas&lt;/span&gt; &lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;size&lt;/span&gt; &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;{&lt;/span&gt;
    &lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;// Increment MemcachedDeploymentSizeUndesiredCountTotal metric by 1
&lt;/span&gt;&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#000&#34;&gt;monitoring&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;MemcachedDeploymentSizeUndesiredCountTotal&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;Inc&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;()&lt;/span&gt;
&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Different metrics types have different valid operations. For more information, please follow &lt;a href=&#34;https://pkg.go.dev/github.com/prometheus/client_golang/prometheus&#34;&gt;Prometheus Golang client&lt;/a&gt;.&lt;/p&gt;
&lt;h4 id=&#34;publishing-alerts-and-recording-rules&#34;&gt;Publishing Alerts and Recording Rules&lt;/h4&gt;
&lt;p&gt;In order to add alerts and recording rules, which are unique to the operator&amp;rsquo;s needs, we&amp;rsquo;ll create a dedicated PrometheusRule object, by using &lt;a href=&#34;https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api-reference/api.md&#34;&gt;prometheus-operator API&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://github.com/operator-framework/operator-sdk/blob/master/testdata/go/v4/monitoring/memcached-operator/monitoring/alerts.go&#34;&gt;PrometheusRule example&lt;/a&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;package&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;monitoring&lt;/span&gt;

&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;import&lt;/span&gt; &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(&lt;/span&gt;
	&lt;span style=&#34;color:#000&#34;&gt;monitoringv1&lt;/span&gt; &lt;span style=&#34;color:#4e9a06&#34;&gt;&amp;#34;github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1&amp;#34;&lt;/span&gt;
	&lt;span style=&#34;color:#000&#34;&gt;metav1&lt;/span&gt; &lt;span style=&#34;color:#4e9a06&#34;&gt;&amp;#34;k8s.io/apimachinery/pkg/apis/meta/v1&amp;#34;&lt;/span&gt;
	&lt;span style=&#34;color:#4e9a06&#34;&gt;&amp;#34;k8s.io/apimachinery/pkg/util/intstr&amp;#34;&lt;/span&gt;
&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;)&lt;/span&gt;

&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;// NewPrometheusRule creates new PrometheusRule(CR) for the operator to have alerts and recording rules
&lt;/span&gt;&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;NewPrometheusRule&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;namespace&lt;/span&gt; &lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;string&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;monitoringv1&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;PrometheusRule&lt;/span&gt; &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;{&lt;/span&gt;
	&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;monitoringv1&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;PrometheusRule&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;{&lt;/span&gt;
		&lt;span style=&#34;color:#000&#34;&gt;TypeMeta&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;metav1&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;TypeMeta&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;{&lt;/span&gt;
			&lt;span style=&#34;color:#000&#34;&gt;APIVersion&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;monitoringv1&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;SchemeGroupVersion&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;String&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(),&lt;/span&gt;
			&lt;span style=&#34;color:#000&#34;&gt;Kind&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;       &lt;span style=&#34;color:#4e9a06&#34;&gt;&amp;#34;PrometheusRule&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;,&lt;/span&gt;
		&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;},&lt;/span&gt;
		&lt;span style=&#34;color:#000&#34;&gt;ObjectMeta&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;metav1&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;ObjectMeta&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;{&lt;/span&gt;
			&lt;span style=&#34;color:#000&#34;&gt;Name&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;      &lt;span style=&#34;color:#4e9a06&#34;&gt;&amp;#34;memcached-operator-rules&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;,&lt;/span&gt;
			&lt;span style=&#34;color:#000&#34;&gt;Namespace&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#4e9a06&#34;&gt;&amp;#34;memcached-operator-system&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;,&lt;/span&gt;
		&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;},&lt;/span&gt;
		&lt;span style=&#34;color:#000&#34;&gt;Spec&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;NewPrometheusRuleSpec&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(),&lt;/span&gt;
	&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;}&lt;/span&gt;

&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;// NewPrometheusRuleSpec creates PrometheusRuleSpec for alerts and recording rules
&lt;/span&gt;&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;NewPrometheusRuleSpec&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;monitoringv1&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;PrometheusRuleSpec&lt;/span&gt; &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;{&lt;/span&gt;
	&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;monitoringv1&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;PrometheusRuleSpec&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;{&lt;/span&gt;
		&lt;span style=&#34;color:#000&#34;&gt;Groups&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;[]&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;monitoringv1&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;RuleGroup&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;{{&lt;/span&gt;
			&lt;span style=&#34;color:#000&#34;&gt;Name&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#4e9a06&#34;&gt;&amp;#34;memcached.rules&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;,&lt;/span&gt;
			&lt;span style=&#34;color:#000&#34;&gt;Rules&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;[]&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;monitoringv1&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;Rule&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;{&lt;/span&gt;
				&lt;span style=&#34;color:#000&#34;&gt;createOperatorUpTotalRecordingRule&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(),&lt;/span&gt; 
				&lt;span style=&#34;color:#000&#34;&gt;createOperatorDownAlertRule&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;()&lt;/span&gt;
			&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;},&lt;/span&gt;
		&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;}},&lt;/span&gt;
	&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;}&lt;/span&gt;

&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;// createOperatorUpTotalRecordingRule creates memcached_operator_up_total recording rule
&lt;/span&gt;&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;createOperatorUpTotalRecordingRule&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;monitoringv1&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;Rule&lt;/span&gt; &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;{&lt;/span&gt;
   &lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;monitoringv1&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;Rule&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;{&lt;/span&gt;
      &lt;span style=&#34;color:#000&#34;&gt;Record&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#4e9a06&#34;&gt;&amp;#34;memcached_operator_up_total&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;,&lt;/span&gt;
      &lt;span style=&#34;color:#000&#34;&gt;Expr&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;   &lt;span style=&#34;color:#000&#34;&gt;intstr&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;FromString&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#4e9a06&#34;&gt;&amp;#34;sum(up{pod=~&amp;#39;memcached-operator-controller-manager-.*&amp;#39;} or vector(0))&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;),&lt;/span&gt;
   &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;}&lt;/span&gt;

&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;// createOperatorDownAlertRule creates MemcachedOperatorDown alert rule
&lt;/span&gt;&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;createOperatorDownAlertRule&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;monitoringv1&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;Rule&lt;/span&gt; &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;{&lt;/span&gt;
	&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;monitoringv1&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;Rule&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;{&lt;/span&gt;
		&lt;span style=&#34;color:#000&#34;&gt;Alert&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#4e9a06&#34;&gt;&amp;#34;MemcachedOperatorDown&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;,&lt;/span&gt;
		&lt;span style=&#34;color:#000&#34;&gt;Expr&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;  &lt;span style=&#34;color:#000&#34;&gt;intstr&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;FromString&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#4e9a06&#34;&gt;&amp;#34;memcached_operator_up_total == 0&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;),&lt;/span&gt;
		&lt;span style=&#34;color:#000&#34;&gt;Annotations&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;map&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;[&lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;string&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;]&lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;string&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;{&lt;/span&gt;
			&lt;span style=&#34;color:#4e9a06&#34;&gt;&amp;#34;description&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#4e9a06&#34;&gt;&amp;#34;No running memcached-operator pods were detected in the last 5 min.&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;,&lt;/span&gt;
		&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;},&lt;/span&gt;
		&lt;span style=&#34;color:#000&#34;&gt;For&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#4e9a06&#34;&gt;&amp;#34;5m&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;,&lt;/span&gt;
		&lt;span style=&#34;color:#000&#34;&gt;Labels&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;map&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;[&lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;string&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;]&lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;string&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;{&lt;/span&gt;
			&lt;span style=&#34;color:#4e9a06&#34;&gt;&amp;#34;severity&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;    &lt;span style=&#34;color:#4e9a06&#34;&gt;&amp;#34;critical&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;,&lt;/span&gt;
		&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;},&lt;/span&gt;
	&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Then, we may want to ensure that the new PrometheusRule is being created and reconciled. One way to achieve this is by expanding the existing &lt;code&gt;Reconcile()&lt;/code&gt; function logic.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://github.com/operator-framework/operator-sdk/blob/master/testdata/go/v4/monitoring/memcached-operator/internal/controller/memcached_controller.go&#34;&gt;PrometheusRule reconciliation example&lt;/a&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;r&lt;/span&gt; &lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;MemcachedReconciler&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;Reconcile&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;ctx&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;context&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;Context&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;req&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;ctrl&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;Request&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;ctrl&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;Result&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;error&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;{&lt;/span&gt;
    &lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;...&lt;/span&gt;
    &lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;...&lt;/span&gt;
    &lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;// Check if prometheus rule already exists, if not create a new one
&lt;/span&gt;&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#000&#34;&gt;foundRule&lt;/span&gt; &lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;monitoringv1&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;PrometheusRule&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;{}&lt;/span&gt;
    &lt;span style=&#34;color:#000&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;r&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;Get&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;ctx&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;types&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;NamespacedName&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;{&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;Name&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;ruleName&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;Namespace&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;namespace&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;},&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;foundRule&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;)&lt;/span&gt;
    &lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;nil&lt;/span&gt; &lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;apierrors&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;IsNotFound&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;err&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;{&lt;/span&gt;
        &lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;// Define a new prometheus rule
&lt;/span&gt;&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;&lt;/span&gt;        &lt;span style=&#34;color:#000&#34;&gt;prometheusRule&lt;/span&gt; &lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;monitoring&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;NewPrometheusRule&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;namespace&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;)&lt;/span&gt;
        &lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;r&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;Create&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;ctx&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;prometheusRule&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;);&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;nil&lt;/span&gt; &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;{&lt;/span&gt;
            &lt;span style=&#34;color:#000&#34;&gt;log&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;Error&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;err&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#4e9a06&#34;&gt;&amp;#34;Failed to create prometheus rule&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;)&lt;/span&gt;
            &lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;ctrl&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;Result&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;{},&lt;/span&gt; &lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;nil&lt;/span&gt;
        &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;}&lt;/span&gt;
    &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;}&lt;/span&gt;
    
    &lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;nil&lt;/span&gt; &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;{&lt;/span&gt;
    &lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;// Check if prometheus rule spec was changed, if so set as desired
&lt;/span&gt;&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#000&#34;&gt;desiredRuleSpec&lt;/span&gt; &lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;monitoring&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;NewPrometheusRuleSpec&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;()&lt;/span&gt;
    &lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;!&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;reflect&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;DeepEqual&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;foundRule&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;Spec&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;DeepCopy&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(),&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;desiredRuleSpec&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;{&lt;/span&gt;
        &lt;span style=&#34;color:#000&#34;&gt;desiredRuleSpec&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;DeepCopyInto&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;foundRule&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;Spec&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;)&lt;/span&gt;
        &lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;r&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;Update&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;ctx&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;foundRule&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;);&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;nil&lt;/span&gt; &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;{&lt;/span&gt;
            &lt;span style=&#34;color:#000&#34;&gt;log&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;Error&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;err&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#4e9a06&#34;&gt;&amp;#34;Failed to update prometheus rule&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;)&lt;/span&gt;
            &lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;ctrl&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;Result&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;{},&lt;/span&gt; &lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;nil&lt;/span&gt;
        &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;}&lt;/span&gt;
    &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;}&lt;/span&gt;
    &lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;...&lt;/span&gt;
    &lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;...&lt;/span&gt;
&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;Please review the &lt;a href=&#34;https://sdk.operatorframework.io/docs/best-practices/observability-best-practices/&#34;&gt;observability-best-practices&lt;/a&gt; for additional important information regarding alerts and recording rules.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&#34;alerts-unit-testing&#34;&gt;Alerts Unit Testing&lt;/h4&gt;
&lt;p&gt;It is highly recommended implementing unit tests for prometheus rules. For more information, please follow the Prometheus &lt;a href=&#34;https://prometheus.io/docs/prometheus/latest/configuration/unit_testing_rules/&#34;&gt;unit testing documentation&lt;/a&gt;. For examples of unit testing in a Golang operator, see the sample memcached-operator &lt;a href=&#34;https://github.com/operator-framework/operator-sdk/tree/master/testdata/go/v4/monitoring/memcached-operator/monitoring/prom-rule-ci&#34;&gt;alerts unit tests&lt;/a&gt;.&lt;/p&gt;
&lt;h4 id=&#34;inspecting-the-metrics-alerts-and-recording-rules-with-prometheus-ui&#34;&gt;Inspecting the metrics, alerts and recording rules with Prometheus UI&lt;/h4&gt;
&lt;p&gt;Finally, in order to inspect the exposed metrics and alerts, we need to forward the corresponding port where metrics are published by Prometheus (usually &lt;code&gt;9090&lt;/code&gt;, which is the default value). This can be done with the following command:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;$ kubectl -n monitoring port-forward svc/prometheus-k8s &lt;span style=&#34;color:#0000cf;font-weight:bold&#34;&gt;9090&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;where we assume that the prometheus service is available in the &lt;code&gt;monitoring&lt;/code&gt; namespace.&lt;/p&gt;
&lt;p&gt;Now you can access Prometheus UI using &lt;code&gt;http://localhost:9090&lt;/code&gt;. For more details on exposing prometheus metrics, please refer &lt;a href=&#34;https://github.com/prometheus-operator/kube-prometheus/blob/main/docs/access-ui.md#prometheus&#34;&gt;kube-prometheus docs&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&#34;handle-cleanup-on-deletion&#34;&gt;Handle Cleanup on Deletion&lt;/h3&gt;
&lt;p&gt;Operators may create objects as part of their operational duty. Object accumulation can consume unnecessary resources, slow down the API and clutter the user interface. As such it is important for operators to keep good hygiene and to clean up resources when they are not needed. Here are a few common scenarios.&lt;/p&gt;
&lt;h4 id=&#34;internal-resources&#34;&gt;Internal Resources&lt;/h4&gt;
&lt;p&gt;A typical example of correct resource cleanup is the &lt;a href=&#34;https://kubernetes.io/docs/concepts/workloads/controllers/job/&#34;&gt;Jobs&lt;/a&gt; implementation. When a Job is created, one or multiple Pods are created as child resources. When a Job is deleted, the associated Pods are deleted as well. This is a very common pattern easily achieved by setting an owner reference from the parent (Job) to the child (Pod) object. Here is a code snippet for doing so, where &amp;ldquo;r&amp;rdquo; is the reconcilier and &amp;ldquo;ctrl&amp;rdquo; the controller-runtime library:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;color:#000&#34;&gt;ctrl&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;SetControllerReference&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;job&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;pod&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;r&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;Scheme&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Note that the default behavior for cascading deletion is background propagation, meaning deletion requests for child objects occur after the request to delete the parent object. &lt;a href=&#34;https://kubernetes.io/docs/concepts/workloads/controllers/garbage-collection/&#34;&gt;This Kubernetes doc&lt;/a&gt; provides alternative deletion types.&lt;/p&gt;
&lt;h4 id=&#34;external-resources&#34;&gt;External Resources&lt;/h4&gt;
&lt;p&gt;Sometimes external resources or resources that are not owned by a custom resource, those across namespaces for example, need to be cleaned up when the parent resource is deleted. In that case &lt;a href=&#34;https://kubernetes.io/docs/tasks/extend-kubernetes/custom-resources/custom-resource-definitions/#finalizers&#34;&gt;Finalizers&lt;/a&gt; can be leveraged. A deletion request for an object with a finalizer becomes an update during which a deletion timestamp is set; the object is not deleted while the finalizer is present. The reconciliation loop of the custom resource&amp;rsquo;s controller will then need to check whether a the deletion timestamp is set, perform the external cleanup operation(s), then remove the finalizer to allow garbage collection of the object. Multiple finalizers may be present on an object, each with a key that should indicate what external resources require deletion by the controller.&lt;/p&gt;
&lt;p&gt;The following is a snippet from a theoretical controller file &lt;code&gt;controllers/memcached_controller.go&lt;/code&gt; that implements a finalizer handler:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;import&lt;/span&gt; &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(&lt;/span&gt;
    &lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;...&lt;/span&gt;
    &lt;span style=&#34;color:#4e9a06&#34;&gt;&amp;#34;sigs.k8s.io/controller-runtime/pkg/controller/controllerutil&amp;#34;&lt;/span&gt;
&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;)&lt;/span&gt;

&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;const&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;memcachedFinalizer&lt;/span&gt; &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#4e9a06&#34;&gt;&amp;#34;cache.example.com/finalizer&amp;#34;&lt;/span&gt;

&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;r&lt;/span&gt; &lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;MemcachedReconciler&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;Reconcile&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;ctx&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;context&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;Context&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;req&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;ctrl&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;Request&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;ctrl&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;Result&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;error&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;{&lt;/span&gt;
    &lt;span style=&#34;color:#000&#34;&gt;reqLogger&lt;/span&gt; &lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;r&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;log&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;WithValues&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#4e9a06&#34;&gt;&amp;#34;memcached&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;req&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;NamespacedName&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;)&lt;/span&gt;
    &lt;span style=&#34;color:#000&#34;&gt;reqLogger&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;Info&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#4e9a06&#34;&gt;&amp;#34;Reconciling Memcached&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;)&lt;/span&gt;

    &lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;// Fetch the Memcached instance
&lt;/span&gt;&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#000&#34;&gt;memcached&lt;/span&gt; &lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;cachev1alpha1&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;Memcached&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;{}&lt;/span&gt;
    &lt;span style=&#34;color:#000&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;r&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;Get&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;ctx&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;req&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;NamespacedName&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;memcached&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;)&lt;/span&gt;
    &lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;nil&lt;/span&gt; &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;{&lt;/span&gt;
        &lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;errors&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;IsNotFound&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;err&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;{&lt;/span&gt;
            &lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;// Request object not found, could have been deleted after reconcile request.
&lt;/span&gt;&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;&lt;/span&gt;            &lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;// Owned objects are automatically garbage collected. For additional cleanup logic use finalizers.
&lt;/span&gt;&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;&lt;/span&gt;            &lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;// Return and don&amp;#39;t requeue
&lt;/span&gt;&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;&lt;/span&gt;            &lt;span style=&#34;color:#000&#34;&gt;reqLogger&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;Info&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#4e9a06&#34;&gt;&amp;#34;Memcached resource not found. Ignoring since object must be deleted.&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;)&lt;/span&gt;
            &lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;ctrl&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;Result&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;{},&lt;/span&gt; &lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;nil&lt;/span&gt;
        &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;}&lt;/span&gt;
        &lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;// Error reading the object - requeue the request.
&lt;/span&gt;&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;&lt;/span&gt;        &lt;span style=&#34;color:#000&#34;&gt;reqLogger&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;Error&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;err&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#4e9a06&#34;&gt;&amp;#34;Failed to get Memcached.&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;)&lt;/span&gt;
        &lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;ctrl&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;Result&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;{},&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;err&lt;/span&gt;
    &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;}&lt;/span&gt;

    &lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;...&lt;/span&gt;

    &lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;// Check if the Memcached instance is marked to be deleted, which is
&lt;/span&gt;&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;// indicated by the deletion timestamp being set.
&lt;/span&gt;&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#000&#34;&gt;isMemcachedMarkedToBeDeleted&lt;/span&gt; &lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;memcached&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;GetDeletionTimestamp&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;nil&lt;/span&gt;
    &lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;isMemcachedMarkedToBeDeleted&lt;/span&gt; &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;{&lt;/span&gt;
        &lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;controllerutil&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;ContainsFinalizer&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;memcached&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;memcachedFinalizer&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;{&lt;/span&gt;
            &lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;// Run finalization logic for memcachedFinalizer. If the
&lt;/span&gt;&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;&lt;/span&gt;            &lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;// finalization logic fails, don&amp;#39;t remove the finalizer so
&lt;/span&gt;&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;&lt;/span&gt;            &lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;// that we can retry during the next reconciliation.
&lt;/span&gt;&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;&lt;/span&gt;            &lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;r&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;finalizeMemcached&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;reqLogger&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;memcached&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;);&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;nil&lt;/span&gt; &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;{&lt;/span&gt;
                &lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;ctrl&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;Result&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;{},&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;err&lt;/span&gt;
            &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;}&lt;/span&gt;

            &lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;// Remove memcachedFinalizer. Once all finalizers have been
&lt;/span&gt;&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;&lt;/span&gt;            &lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;// removed, the object will be deleted.
&lt;/span&gt;&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;&lt;/span&gt;            &lt;span style=&#34;color:#000&#34;&gt;controllerutil&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;RemoveFinalizer&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;memcached&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;memcachedFinalizer&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;)&lt;/span&gt;
            &lt;span style=&#34;color:#000&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;r&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;Update&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;ctx&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;memcached&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;)&lt;/span&gt;
            &lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;nil&lt;/span&gt; &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;{&lt;/span&gt;
                &lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;ctrl&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;Result&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;{},&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;err&lt;/span&gt;
            &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;}&lt;/span&gt;
        &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;}&lt;/span&gt;
        &lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;ctrl&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;Result&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;{},&lt;/span&gt; &lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;nil&lt;/span&gt;
    &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;}&lt;/span&gt;

    &lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;// Add finalizer for this CR
&lt;/span&gt;&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;!&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;controllerutil&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;ContainsFinalizer&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;memcached&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;memcachedFinalizer&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;{&lt;/span&gt;
        &lt;span style=&#34;color:#000&#34;&gt;controllerutil&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;AddFinalizer&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;memcached&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;memcachedFinalizer&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;)&lt;/span&gt;
        &lt;span style=&#34;color:#000&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;r&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;Update&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;ctx&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;memcached&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;)&lt;/span&gt;
        &lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;nil&lt;/span&gt; &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;{&lt;/span&gt;
            &lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;ctrl&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;Result&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;{},&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;err&lt;/span&gt;
        &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;}&lt;/span&gt;
    &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;}&lt;/span&gt;

    &lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;...&lt;/span&gt;

    &lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;ctrl&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;Result&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;{},&lt;/span&gt; &lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;nil&lt;/span&gt;
&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;}&lt;/span&gt;

&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;r&lt;/span&gt; &lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;MemcachedReconciler&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;finalizeMemcached&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;reqLogger&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;logr&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;Logger&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;m&lt;/span&gt; &lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;cachev1alpha1&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;Memcached&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;error&lt;/span&gt; &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;{&lt;/span&gt;
    &lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;// TODO(user): Add the cleanup steps that the operator
&lt;/span&gt;&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;// needs to do before the CR can be deleted. Examples
&lt;/span&gt;&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;// of finalizers include performing backups and deleting
&lt;/span&gt;&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;// resources that are not owned by this CR, like a PVC.
&lt;/span&gt;&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#000&#34;&gt;reqLogger&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;Info&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#4e9a06&#34;&gt;&amp;#34;Successfully finalized memcached&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;)&lt;/span&gt;
    &lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;nil&lt;/span&gt;
&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id=&#34;complex-cleanup-logic&#34;&gt;Complex cleanup logic&lt;/h4&gt;
&lt;p&gt;Similar to the previous scenario, finalizers can be used for implementing complex cleanup logic. Take &lt;a href=&#34;https://kubernetes.io/docs/concepts/workloads/controllers/cron-jobs/&#34;&gt;CronJobs&lt;/a&gt; as an example: the controller maintains limited-size lists of jobs that have been created by the CronJob controller to check for deletion. These list sizes are configured by the CronJob fields &lt;a href=&#34;https://kubernetes.io/docs/tasks/job/automated-tasks-with-cron-jobs/#jobs-history-limits&#34;&gt;&lt;code&gt;.spec.successfulJobsHistoryLimit&lt;/code&gt; and &lt;code&gt;.spec.failedJobsHistoryLimit&lt;/code&gt;&lt;/a&gt;, which specify how many completed and failed jobs should be kept. Check out the &lt;a href=&#34;https://book.kubebuilder.io/cronjob-tutorial/controller-implementation.html#3-clean-up-old-jobs-according-to-the-history-limit&#34;&gt;Kubebuilder CronJob tutorial&lt;/a&gt; for full implementation details.&lt;/p&gt;
&lt;h4 id=&#34;sensitive-resources&#34;&gt;Sensitive resources&lt;/h4&gt;
&lt;p&gt;Sensitive resources need to be protected against unintended deletion. An intuitive example of protecting resources is the &lt;a href=&#34;https://kubernetes.io/docs/concepts/storage/persistent-volumes/&#34;&gt;PersistentVolume (PV) / PersistentVolumeClaim (PVC)&lt;/a&gt; relationship. A PV is first created, after which users can request access to that PV&amp;rsquo;s storage by creating a PVC, which gets bound to the PV. If a user tries to delete a PV currently bound by a PVC, the PV is not removed immediately. Instead, PV removal is postponed until the PV is not bound to any PVC. Finalizers again can be leveraged to achieve a similar behaviour for your own PV-like custom resources: by setting a finalizer on an object, your controller can make sure there are no remaining objects bound to it before removing the finalizer and deleting the object.
Additionally, the user who created the PVC can specify what happens to the underlying storage allocated in a PV when the PVC is deleted through the &lt;a href=&#34;https://kubernetes.io/docs/concepts/storage/persistent-volumes/#reclaiming&#34;&gt;reclaim policy&lt;/a&gt;. There are several options available, each of which defines a behavior that is achieved again through the use of finalizers. The key concept to take away is that your operator can give a user the power to decide how their resources are cleaned up via finalizers, which may be dangerous yet useful depending on your workloads.&lt;/p&gt;
&lt;h3 id=&#34;leader-election&#34;&gt;Leader election&lt;/h3&gt;
&lt;p&gt;During the lifecycle of an operator it&amp;rsquo;s possible that there may be more than 1 instance running at any given time e.g when rolling out an upgrade for the operator.
In such a scenario it is necessary to avoid contention between multiple operator instances via leader election so that only one leader instance handles the reconciliation while the other instances are inactive but ready to take over when the leader steps down.&lt;/p&gt;
&lt;p&gt;There are two different leader election implementations to choose from, each with its own tradeoff.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://pkg.go.dev/sigs.k8s.io/controller-runtime/pkg/leaderelection&#34;&gt;Leader-with-lease&lt;/a&gt;: The leader pod periodically renews the leader lease and gives up leadership when it can&amp;rsquo;t renew the lease. This implementation allows for a faster transition to a new leader when the existing leader is isolated, but there is a possibility of split brain in &lt;a href=&#34;https://github.com/kubernetes/client-go/blob/30b06a83d67458700a5378239df6b96948cb9160/tools/leaderelection/leaderelection.go#L21-L24&#34;&gt;certain situations&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://pkg.go.dev/github.com/operator-framework/operator-lib/leader&#34;&gt;Leader-for-life&lt;/a&gt;: The leader pod only gives up leadership (via garbage collection) when it is deleted. This implementation precludes the possibility of 2 instances mistakenly running as leaders (split brain). However, this method can be subject to a delay in electing a new leader. For instance when the leader pod is on an unresponsive or partitioned node, the &lt;a href=&#34;https://kubernetes.io/docs/reference/command-line-tools-reference/kube-controller-manager/#options&#34;&gt;&lt;code&gt;pod-eviction-timeout&lt;/code&gt;&lt;/a&gt; dictates how long it takes for the leader pod to be deleted from the node and step down (default 5m).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;By default the SDK enables the leader-with-lease implementation. However you should consult the docs above for both approaches to consider the tradeoffs that make sense for your use case.&lt;/p&gt;
&lt;p&gt;The following examples illustrate how to use the two options:&lt;/p&gt;
&lt;h4 id=&#34;leader-for-life&#34;&gt;Leader for life&lt;/h4&gt;
&lt;p&gt;A call to &lt;code&gt;leader.Become()&lt;/code&gt; will block the operator as it retries until it can become the leader by creating the configmap named &lt;code&gt;memcached-operator-lock&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-Go&#34; data-lang=&#34;Go&#34;&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;import&lt;/span&gt; &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(&lt;/span&gt;
    &lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;...&lt;/span&gt;
    &lt;span style=&#34;color:#4e9a06&#34;&gt;&amp;#34;github.com/operator-framework/operator-lib/leader&amp;#34;&lt;/span&gt;
&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;)&lt;/span&gt;

&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;main&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;{&lt;/span&gt;
    &lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;...&lt;/span&gt;
    &lt;span style=&#34;color:#000&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;leader&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;Become&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;context&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;TODO&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(),&lt;/span&gt; &lt;span style=&#34;color:#4e9a06&#34;&gt;&amp;#34;memcached-operator-lock&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;)&lt;/span&gt;
    &lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;nil&lt;/span&gt; &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;{&lt;/span&gt;
        &lt;span style=&#34;color:#000&#34;&gt;log&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;Error&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;err&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#4e9a06&#34;&gt;&amp;#34;Failed to retry for leader lock&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;)&lt;/span&gt;
        &lt;span style=&#34;color:#000&#34;&gt;os&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;Exit&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#0000cf;font-weight:bold&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;)&lt;/span&gt;
    &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;}&lt;/span&gt;
    &lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;...&lt;/span&gt;
&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If the operator is not running inside a cluster &lt;code&gt;leader.Become()&lt;/code&gt; will simply return without error to skip the leader election since it can&amp;rsquo;t detect the operator&amp;rsquo;s namespace.&lt;/p&gt;
&lt;h4 id=&#34;leader-with-lease&#34;&gt;Leader with lease&lt;/h4&gt;
&lt;p&gt;The leader-with-lease approach can be enabled via the &lt;a href=&#34;https://pkg.go.dev/sigs.k8s.io/controller-runtime/pkg/manager#Options&#34;&gt;Manager Options&lt;/a&gt; for leader election.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-Go&#34; data-lang=&#34;Go&#34;&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;import&lt;/span&gt; &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(&lt;/span&gt;
    &lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;...&lt;/span&gt;
    &lt;span style=&#34;color:#4e9a06&#34;&gt;&amp;#34;sigs.k8s.io/controller-runtime/pkg/manager&amp;#34;&lt;/span&gt;
&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;)&lt;/span&gt;

&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;main&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;{&lt;/span&gt;
    &lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;...&lt;/span&gt;
    &lt;span style=&#34;color:#000&#34;&gt;opts&lt;/span&gt; &lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;manager&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;Options&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;{&lt;/span&gt;
        &lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;...&lt;/span&gt;
        &lt;span style=&#34;color:#000&#34;&gt;LeaderElection&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;true&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;,&lt;/span&gt;
        &lt;span style=&#34;color:#000&#34;&gt;LeaderElectionID&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#4e9a06&#34;&gt;&amp;#34;memcached-operator-lock&amp;#34;&lt;/span&gt;
    &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;}&lt;/span&gt;
    &lt;span style=&#34;color:#000&#34;&gt;mgr&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;manager&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;New&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;cfg&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;opts&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;)&lt;/span&gt;
    &lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;...&lt;/span&gt;
&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;When the operator is not running in a cluster, the Manager will return an error on starting since it can&amp;rsquo;t detect the operator&amp;rsquo;s namespace in order to create the configmap for leader election. You can override this namespace by setting the Manager&amp;rsquo;s &lt;code&gt;LeaderElectionNamespace&lt;/code&gt; option.&lt;/p&gt;
&lt;h3 id=&#34;multiple-architectures&#34;&gt;Multiple architectures&lt;/h3&gt;
&lt;p&gt;Authors may decide to distribute their bundles for various architectures: x86_64, aarch64, ppc64le, s390x, etc, to accommodate the diversity of Kubernetes clusters and reach a larger number of potential users. Each architecture requires however compatible binaries. Considerations on the topic are available in the &lt;a href=&#34;/docs/advanced-topics/multi-arch&#34;&gt;Multiple Architectures page&lt;/a&gt;.&lt;/p&gt;

      </description>
    </item>
    
    <item>
      <title>Docs: Go-based Operator Reference</title>
      <link>/docs/building-operators/golang/references/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      
      <guid>/docs/building-operators/golang/references/</guid>
      <description>
        
        
        
      </description>
    </item>
    
    <item>
      <title>Docs: </title>
      <link>/docs/building-operators/golang/migration/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      
      <guid>/docs/building-operators/golang/migration/</guid>
      <description>
        
        
        &lt;h2 id=&#34;overview&#34;&gt;Overview&lt;/h2&gt;
&lt;p&gt;The motivations for the new layout are related to bringing more flexibility to users and part of the process to Integrating Kubebuilder and Operator SDK. Because of this integration you may be referred to the Kubebuilder documentation &lt;a href=&#34;https://book.kubebuilder.io/&#34;&gt;https://book.kubebuilder.io/&lt;/a&gt; for more information about certain topics. When using this document just remember to replace &lt;code&gt;$ kubebuilder &amp;lt;command&amp;gt;&lt;/code&gt; with &lt;code&gt;$ operator-sdk &amp;lt;command&amp;gt;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; It is recommended that you have your project upgraded to the latest SDK v1.y release version before following the steps in this guide to migrate to the new layout. However, the steps might work from previous versions as well. In this case, if you find an issue which is not covered here then check the previous &lt;a href=&#34;/docs/upgrading-sdk-version/&#34;&gt;Migration Guides&lt;/a&gt; which might help out.&lt;/p&gt;
&lt;h3 id=&#34;what-was-changed&#34;&gt;What was changed&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;The &lt;code&gt;deploy&lt;/code&gt; directory was replaced with the &lt;code&gt;config&lt;/code&gt; directory including a new layout of Kubernetes manifests files:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;CRD manifests in &lt;code&gt;deploy/crds/&lt;/code&gt; are now in &lt;code&gt;config/crd/bases&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;CR manifests in &lt;code&gt;deploy/crds/&lt;/code&gt; are now in &lt;code&gt;config/samples&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Controller manifest &lt;code&gt;deploy/operator.yaml&lt;/code&gt; is now in &lt;code&gt;config/manager/manager.yaml&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;RBAC manifests in &lt;code&gt;deploy&lt;/code&gt; are now in &lt;code&gt;config/rbac/&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;build/Dockerfile&lt;/code&gt; is moved to &lt;code&gt;Dockerfile&lt;/code&gt; in the project root directory&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;pkg/apis&lt;/code&gt; and &lt;code&gt;pkg/controllers&lt;/code&gt; are now in the root directory.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;cmd/manager/main.go&lt;/code&gt; is now in the root directory.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;what-is-new&#34;&gt;What is new&lt;/h3&gt;
&lt;p&gt;Scaffolded projects now use:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/kubernetes-sigs/kustomize&#34;&gt;kustomize&lt;/a&gt; to manage Kubernetes resources needed to deploy your operator&lt;/li&gt;
&lt;li&gt;A &lt;code&gt;Makefile&lt;/code&gt; with helpful targets to build, test, deploy and tailor things based on your project needs&lt;/li&gt;
&lt;li&gt;Helpers and options to work with webhooks. For further information see &lt;a href=&#34;https://book.kubebuilder.io/reference/webhook-overview.html&#34;&gt;What is a Webhook?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Updated metrics configuration using &lt;a href=&#34;https://github.com/brancz/kube-rbac-proxy&#34;&gt;kube-auth-proxy&lt;/a&gt;, a &lt;code&gt;--metrics-addr&lt;/code&gt; flag, and &lt;a href=&#34;https://github.com/kubernetes-sigs/kustomize&#34;&gt;kustomize&lt;/a&gt;-based deployment of a Kubernetes &lt;code&gt;Service&lt;/code&gt; and prometheus operator &lt;code&gt;ServiceMonitor&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Scaffolded tests that use the &lt;a href=&#34;https://pkg.go.dev/sigs.k8s.io/controller-runtime/pkg/envtest&#34;&gt;&lt;code&gt;envtest&lt;/code&gt;&lt;/a&gt; test framework&lt;/li&gt;
&lt;li&gt;Preliminary support for CLI plugins. For more info see the &lt;a href=&#34;https://github.com/kubernetes-sigs/kubebuilder/blob/master/designs/extensible-cli-and-scaffolding-plugins-phase-1.md&#34;&gt;plugins design document&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;A &lt;code&gt;PROJECT&lt;/code&gt; configuration file to store information about GVKs, plugins, and help the CLI make decisions&lt;/li&gt;
&lt;li&gt;A new option to create projects using ComponentConfig. For more info, see the &lt;a href=&#34;https://github.com/kubernetes-sigs/controller-runtime/blob/master/designs/component-config.md&#34;&gt;enhancement proposal&lt;/a&gt; and the [Component config tutorial][component-config-tutorial]&lt;/li&gt;
&lt;li&gt;Go version &lt;code&gt;1.15&lt;/code&gt; (previously it was &lt;code&gt;1.13&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Generated files with the default API versions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;apiextensions/v1&lt;/code&gt; for generated CRDs (&lt;code&gt;apiextensions/v1beta1&lt;/code&gt; was deprecated in Kubernetes &lt;code&gt;1.16&lt;/code&gt; and will be removed in &lt;code&gt;1.22&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;admissionregistration.k8s.io/v1&lt;/code&gt; for webhooks (&lt;code&gt;admissionregistration.k8s.io/v1beta1&lt;/code&gt; was deprecated in Kubernetes &lt;code&gt;1.16&lt;/code&gt; and will be removed in &lt;code&gt;1.22&lt;/code&gt; )&lt;/li&gt;
&lt;li&gt;&lt;code&gt;cert-manager.io/v1&lt;/code&gt; for the certificate manager when webhooks are used (&lt;code&gt;cert-manager.io/v1alpha2&lt;/code&gt; was deprecated in &lt;code&gt;Cert-Manager 0.14&lt;/code&gt;. More info: &lt;a href=&#34;https://cert-manager.io/docs/installation/upgrade/&#34;&gt;CertManager v1.0 docs&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; You can still use the deprecated APIs which are only needed to support Kubernetes &lt;code&gt;1.15&lt;/code&gt; and earlier.&lt;/p&gt;
&lt;h2 id=&#34;how-to-migrate&#34;&gt;How to migrate&lt;/h2&gt;
&lt;p&gt;The easy migration path is to initialize a new project, re-recreate APIs, then copy pre-v1.0.0 configuration files into the new project.&lt;/p&gt;
&lt;h3 id=&#34;prerequisites&#34;&gt;Prerequisites&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Go through the &lt;a href=&#34;/docs/building-operators/ansible/installation&#34;&gt;installation guide&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Make sure your user is authorized with &lt;code&gt;cluster-admin&lt;/code&gt; permissions.&lt;/li&gt;
&lt;li&gt;An accessible image registry for various operator images (ex. &lt;a href=&#34;https://hub.docker.com/signup&#34;&gt;hub.docker.com&lt;/a&gt;,
&lt;a href=&#34;https://quay.io/&#34;&gt;quay.io&lt;/a&gt;) and be logged in to your command line environment.
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;example.com&lt;/code&gt; is used as the registry Docker Hub namespace in these examples.
Replace it with another value if using a different registry or namespace.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;/docs/olm-integration/cli-overview#private-bundle-and-catalog-image-registries&#34;&gt;Authentication and certificates&lt;/a&gt; if the registry is private or uses a custom CA.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;create-a-new-project&#34;&gt;Create a new project&lt;/h3&gt;
&lt;p&gt;In Kubebuilder-style projects, CRD groups are defined using two different flags
(&lt;code&gt;--group&lt;/code&gt; and &lt;code&gt;--domain&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;When we initialize a new project, we need to specify the domain that &lt;em&gt;all&lt;/em&gt; APIs in
our project will share, so before creating the new project, we need to determine which
domain we&amp;rsquo;re using for the APIs in our existing project.&lt;/p&gt;
&lt;p&gt;To determine the domain, look at the &lt;code&gt;spec.group&lt;/code&gt; field in your CRDs in the
&lt;code&gt;deploy/crds&lt;/code&gt; directory.&lt;/p&gt;
&lt;p&gt;The domain is everything after the first DNS segment. Using &lt;code&gt;cache.example.com&lt;/code&gt; as an
example, the &lt;code&gt;--domain&lt;/code&gt; would be &lt;code&gt;example.com&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;So let&amp;rsquo;s create a new project with the same domain (&lt;code&gt;example.com&lt;/code&gt;):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;mkdir memcached-operator
&lt;span style=&#34;color:#204a87&#34;&gt;cd&lt;/span&gt; memcached-operator
operator-sdk init --domain example.com --repo github.com/example/memcached-operator
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt;: &lt;code&gt;operator-sdk&lt;/code&gt; attempts to automatically discover the Go module path of your project by looking for a &lt;code&gt;go.mod&lt;/code&gt; file, or if in &lt;code&gt;$GOPATH&lt;/code&gt;, by using the directory path. Use the &lt;code&gt;--repo&lt;/code&gt; flag to explicitly set the module path.&lt;/p&gt;
&lt;h3 id=&#34;check-if-your-project-is-multi-group&#34;&gt;Check if your project is multi-group&lt;/h3&gt;
&lt;p&gt;Before we start creating the APIs, check if your project has more than one group such as: &lt;code&gt;foo.example.com/v1&lt;/code&gt; and &lt;code&gt;crew.example.com/v1&lt;/code&gt;. If you intend to work with multiple groups in your project, then run the command &lt;code&gt;operator-sdk edit --multigroup=true&lt;/code&gt; to change the project&amp;rsquo;s layout to support multi-group.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; In multi-group projects, APIs are defined in &lt;code&gt;apis/&amp;lt;group&amp;gt;/&amp;lt;version&amp;gt;&lt;/code&gt; and controllers are defined in &lt;code&gt;controllers/&amp;lt;group&amp;gt;&lt;/code&gt;.
For further information see &lt;a href=&#34;https://book.kubebuilder.io/migration/multi-group.html&#34;&gt;Single Group to Multi-Group&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&#34;migrate-apis-and-controllers&#34;&gt;Migrate APIs and Controllers&lt;/h3&gt;
&lt;p&gt;Now that we have our new project initialized, we need to re-create each of our APIs.
Using our API example from earlier (&lt;code&gt;cache.example.com&lt;/code&gt;), we&amp;rsquo;ll use &lt;code&gt;cache&lt;/code&gt; for the
&lt;code&gt;--group&lt;/code&gt;, &lt;code&gt;v1alpha1&lt;/code&gt; for the &lt;code&gt;--version&lt;/code&gt; and &lt;code&gt;Memcached&lt;/code&gt; for &lt;code&gt;--kind&lt;/code&gt; flag.&lt;/p&gt;
&lt;p&gt;For each API in the existing project, run:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;operator-sdk create api &lt;span style=&#34;color:#4e9a06&#34;&gt;\
&lt;/span&gt;&lt;span style=&#34;color:#4e9a06&#34;&gt;&lt;/span&gt;    --group&lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;=&lt;/span&gt;cache &lt;span style=&#34;color:#4e9a06&#34;&gt;\
&lt;/span&gt;&lt;span style=&#34;color:#4e9a06&#34;&gt;&lt;/span&gt;    --version&lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;=&lt;/span&gt;&amp;lt;version&amp;gt; &lt;span style=&#34;color:#4e9a06&#34;&gt;\
&lt;/span&gt;&lt;span style=&#34;color:#4e9a06&#34;&gt;&lt;/span&gt;    --kind&lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;=&lt;/span&gt;&amp;lt;Kind&amp;gt; &lt;span style=&#34;color:#4e9a06&#34;&gt;\
&lt;/span&gt;&lt;span style=&#34;color:#4e9a06&#34;&gt;&lt;/span&gt;    --resource &lt;span style=&#34;color:#4e9a06&#34;&gt;\
&lt;/span&gt;&lt;span style=&#34;color:#4e9a06&#34;&gt;&lt;/span&gt;    --controller
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id=&#34;how-to-keep-apiextensionsk8siov1beta1-for-crds&#34;&gt;How to keep &lt;code&gt;apiextensions.k8s.io/v1beta1&lt;/code&gt; for CRDs?&lt;/h4&gt;
&lt;p&gt;From now on, the CRDs that will be created by controller-gen will be using Kubernetes API version &lt;code&gt;apiextensions.k8s.io/v1&lt;/code&gt; by default, instead of &lt;code&gt;apiextensions.k8s.io/v1beta1&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;apiextensions.k8s.io/v1beta1&lt;/code&gt; was deprecated in Kubernetes &lt;code&gt;1.16&lt;/code&gt; and will be removed in Kubernetes &lt;code&gt;1.22&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;If you would like to keep using the previous version, use the flag &lt;code&gt;--crd-version=v1beta1&lt;/code&gt; in the above command. This is only needed if you want your operator to support Kubernetes &lt;code&gt;1.15&lt;/code&gt; and earlier.&lt;/p&gt;
&lt;h3 id=&#34;apis&#34;&gt;APIs&lt;/h3&gt;
&lt;p&gt;Now let’s copy the API definition from &lt;code&gt;pkg/apis/&amp;lt;group&amp;gt;/&amp;lt;version&amp;gt;/&amp;lt;kind&amp;gt;_types.go&lt;/code&gt; to &lt;code&gt;api/&amp;lt;version&amp;gt;/&amp;lt;kind&amp;gt;_types.go&lt;/code&gt;. For our example, it is only required to copy the code from the &lt;code&gt;Spec&lt;/code&gt; and &lt;code&gt;Status&lt;/code&gt; fields.&lt;/p&gt;
&lt;p&gt;This file is quite similar to the old one. Once you copy over your API definitions and generate manifests, you should end up with an identical API for your custom resource type. However, pay close attention to these kubebuilder &lt;a href=&#34;https://book.kubebuilder.io/reference/markers.html?highlight=markers#marker-syntax&#34;&gt;Markers&lt;/a&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;+k8s:deepcopy-gen:interfaces=...&lt;/code&gt; marker was replaced with &lt;code&gt;+kubebuilder:object:root=true&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;If you are not using &lt;a href=&#34;https://github.com/kubernetes/kube-openapi/tree/master/cmd/openapi-gen&#34;&gt;openapi-gen&lt;/a&gt; to generate OpenAPI Go code, then &lt;code&gt;// +k8s:openapi-gen=true&lt;/code&gt; and other related openapi markers can be removed.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Note::&lt;/strong&gt; The &lt;code&gt;operator-sdk generate openapi&lt;/code&gt; command was deprecated in &lt;code&gt;0.13.0&lt;/code&gt; and was removed in &lt;code&gt;0.17&lt;/code&gt; SDK release. Hence, it is recommended to use &lt;a href=&#34;https://github.com/kubernetes/kube-openapi/tree/master/cmd/openapi-gen&#34;&gt;openapi-gen&lt;/a&gt; directly for OpenAPI code generation.&lt;/p&gt;
&lt;p&gt;Our Memcached API types will look like:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;// MemcachedSpec defines the desired state of Memcached
&lt;/span&gt;&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;MemcachedSpec&lt;/span&gt; &lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;struct&lt;/span&gt; &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;{&lt;/span&gt;
	&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;// Size is the size of the memcached deployment
&lt;/span&gt;&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;&lt;/span&gt;	&lt;span style=&#34;color:#000&#34;&gt;Size&lt;/span&gt; &lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;int32&lt;/span&gt; &lt;span style=&#34;color:#4e9a06&#34;&gt;`json:&amp;#34;size&amp;#34;`&lt;/span&gt;
&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;}&lt;/span&gt;

&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;// MemcachedStatus defines the observed state of Memcached
&lt;/span&gt;&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;MemcachedStatus&lt;/span&gt; &lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;struct&lt;/span&gt; &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;{&lt;/span&gt;
	&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;// Nodes are the names of the memcached pods
&lt;/span&gt;&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;&lt;/span&gt;	&lt;span style=&#34;color:#000&#34;&gt;Nodes&lt;/span&gt; &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;[]&lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;string&lt;/span&gt; &lt;span style=&#34;color:#4e9a06&#34;&gt;`json:&amp;#34;nodes&amp;#34;`&lt;/span&gt;
&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;}&lt;/span&gt;

&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;//+kubebuilder:object:root=true
&lt;/span&gt;&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;//+kubebuilder:subresource:status
&lt;/span&gt;&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;&lt;/span&gt;
&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;// Memcached is the Schema for the memcacheds API
&lt;/span&gt;&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;Memcached&lt;/span&gt; &lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;struct&lt;/span&gt; &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;{&lt;/span&gt;&lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;...&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;}&lt;/span&gt;

&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;//+kubebuilder:object:root=true
&lt;/span&gt;&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;&lt;/span&gt;
&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;// MemcachedList contains a list of Memcached
&lt;/span&gt;&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;MemcachedList&lt;/span&gt; &lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;struct&lt;/span&gt; &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;{&lt;/span&gt;&lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;...&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;webhooks&#34;&gt;Webhooks&lt;/h3&gt;
&lt;p&gt;SDK version &lt;code&gt;1.0.0&lt;/code&gt; and later has support for webhooks by the CLI. If your project doesn&amp;rsquo;t require any webhooks, you can skip this section. However, if you have been using it via customizations in your project, you should use the tool to re-scaffold the webhooks.&lt;/p&gt;
&lt;p&gt;A webhook can only be scaffolded for a pre-existent API in your project. Then, for each case you will run the command &lt;code&gt;operator-sdk create webhook&lt;/code&gt; providing the &lt;code&gt;--group&lt;/code&gt;, &lt;code&gt;--kind&lt;/code&gt; and &lt;code&gt;version&lt;/code&gt; of the API based on the flags that need to be used.&lt;/p&gt;
&lt;p&gt;The valid flags for its types are: &lt;code&gt;--defaulting&lt;/code&gt;, &lt;code&gt;--programmatic-validation&lt;/code&gt; and &lt;code&gt;--conversion&lt;/code&gt;. Use the same type that was used for scaffolding. To create &lt;code&gt;defaulting&lt;/code&gt; and &lt;code&gt;validating&lt;/code&gt; webhook:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;operator-sdk create webhook &lt;span style=&#34;color:#4e9a06&#34;&gt;\
&lt;/span&gt;&lt;span style=&#34;color:#4e9a06&#34;&gt;&lt;/span&gt;    --group&lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;=&lt;/span&gt;cache &lt;span style=&#34;color:#4e9a06&#34;&gt;\
&lt;/span&gt;&lt;span style=&#34;color:#4e9a06&#34;&gt;&lt;/span&gt;    --version&lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;=&lt;/span&gt;&amp;lt;version&amp;gt; &lt;span style=&#34;color:#4e9a06&#34;&gt;\
&lt;/span&gt;&lt;span style=&#34;color:#4e9a06&#34;&gt;&lt;/span&gt;    --kind&lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;=&lt;/span&gt;&amp;lt;Kind&amp;gt; &lt;span style=&#34;color:#4e9a06&#34;&gt;\
&lt;/span&gt;&lt;span style=&#34;color:#4e9a06&#34;&gt;&lt;/span&gt;    --defaulting &lt;span style=&#34;color:#4e9a06&#34;&gt;\
&lt;/span&gt;&lt;span style=&#34;color:#4e9a06&#34;&gt;&lt;/span&gt;    --programmatic-validation
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;To create &lt;code&gt;conversion&lt;/code&gt; webhook:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;operator-sdk create webhook &lt;span style=&#34;color:#4e9a06&#34;&gt;\
&lt;/span&gt;&lt;span style=&#34;color:#4e9a06&#34;&gt;&lt;/span&gt;    --group&lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;=&lt;/span&gt;cache &lt;span style=&#34;color:#4e9a06&#34;&gt;\
&lt;/span&gt;&lt;span style=&#34;color:#4e9a06&#34;&gt;&lt;/span&gt;    --version&lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;=&lt;/span&gt;&amp;lt;version&amp;gt; &lt;span style=&#34;color:#4e9a06&#34;&gt;\
&lt;/span&gt;&lt;span style=&#34;color:#4e9a06&#34;&gt;&lt;/span&gt;    --kind&lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;=&lt;/span&gt;&amp;lt;Kind&amp;gt; &lt;span style=&#34;color:#4e9a06&#34;&gt;\
&lt;/span&gt;&lt;span style=&#34;color:#4e9a06&#34;&gt;&lt;/span&gt;    --conversion
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;After the webhook is generated, you will need to copy the webhook definition and content from your old project to the new one. You can find the respective file in &lt;code&gt;api/v1/&amp;lt;kind&amp;gt;_webhook.go&lt;/code&gt;.&lt;/p&gt;
&lt;h4 id=&#34;how-to-keep-using-apiextensionsk8siov1beta1-for-webhooks&#34;&gt;How to keep using &lt;code&gt;apiextensions.k8s.io/v1beta1&lt;/code&gt; for Webhooks?&lt;/h4&gt;
&lt;p&gt;Hereafter, the webhooks that are created by SDK will use Kubernetes API version &lt;code&gt;admissionregistration.k8s.io/v1&lt;/code&gt; by default instead of &lt;code&gt;admissionregistration.k8s.io/v1beta1&lt;/code&gt; and &lt;code&gt;cert-manager.io/v1&lt;/code&gt; instead of &lt;code&gt;cert-manager.io/v1alpha2&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Note that &lt;code&gt;apiextensions/v1beta1&lt;/code&gt; and &lt;code&gt;admissionregistration.k8s.io/v1beta1&lt;/code&gt; were deprecated in Kubernetes &lt;code&gt;1.16&lt;/code&gt; and will be removed in Kubernetes &lt;code&gt;1.22&lt;/code&gt;. If you use &lt;code&gt;apiextensions/v1&lt;/code&gt; and &lt;code&gt;admissionregistration.k8s.io/v1&lt;/code&gt;, then you need to use &lt;code&gt;cert-manager.io/v1&lt;/code&gt; which will be the default API adopted by the SDK CLI.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; If you are using the API &lt;code&gt;cert-manager.io/v1alpha2&lt;/code&gt;, it is not compatible with the latest Kubernetes API version. (&lt;code&gt;cert-manager.io/v1alpha2&lt;/code&gt; was deprecated in &lt;code&gt;Cert-Manager 0.14&lt;/code&gt;. For more info, refer to &lt;a href=&#34;https://cert-manager.io/docs/installation/upgrade/&#34;&gt;CertManager v1.0 docs&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;If you would like to use the previous version, use the flag &lt;code&gt;--webhook-version=v1beta1&lt;/code&gt; in the above command which is only required if you want your operator to support Kubernetes &lt;code&gt;1.15&lt;/code&gt; and earlier.&lt;/p&gt;
&lt;h3 id=&#34;controllers&#34;&gt;Controllers&lt;/h3&gt;
&lt;p&gt;Now let’s migrate the controller code from &lt;code&gt;pkg/controller/&amp;lt;kind&amp;gt;/&amp;lt;kind&amp;gt;_controller.go&lt;/code&gt; to &lt;code&gt;controllers/&amp;lt;kind&amp;gt;_controller.go&lt;/code&gt; following these steps:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Copy over any struct fields from the existing project into the new &lt;code&gt;&amp;lt;Kind&amp;gt;Reconciler&lt;/code&gt; struct.
&lt;strong&gt;Note:&lt;/strong&gt; The &lt;code&gt;Reconciler&lt;/code&gt; struct has been renamed from &lt;code&gt;Reconcile&amp;lt;Kind&amp;gt;&lt;/code&gt; to &lt;code&gt;&amp;lt;Kind&amp;gt;Reconciler&lt;/code&gt;. In our example, we would see &lt;code&gt;ReconcileMemcached&lt;/code&gt; instead of &lt;code&gt;MemcachedReconciler&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Replace the &lt;code&gt;// your logic here&lt;/code&gt; in the new layout with your reconcile logic.&lt;/li&gt;
&lt;li&gt;Copy the code under &lt;code&gt;func add(mgr manager.Manager, r reconcile.Reconciler)&lt;/code&gt; to &lt;code&gt;func SetupWithManager&lt;/code&gt;:&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;r&lt;/span&gt; &lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;MemcachedReconciler&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;SetupWithManager&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;mgr&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;ctrl&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;Manager&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;error&lt;/span&gt; &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;{&lt;/span&gt;
	&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;ctrl&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;NewControllerManagedBy&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;mgr&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;).&lt;/span&gt;
		&lt;span style=&#34;color:#000&#34;&gt;For&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;cachev1alpha1&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;Memcached&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;{}).&lt;/span&gt;
		&lt;span style=&#34;color:#000&#34;&gt;Owns&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;appsv1&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;Deployment&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;{}).&lt;/span&gt;
		&lt;span style=&#34;color:#000&#34;&gt;Complete&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;r&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;)&lt;/span&gt;
&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In our example, the &lt;code&gt;Watch&lt;/code&gt; implemented for the Deployment will be replaced with &lt;code&gt;Owns(&amp;amp;appsv1.Deployment{})&lt;/code&gt;. Setting up controller &lt;code&gt;Watches&lt;/code&gt; is simplified in more recent versions of controller-runtime, which has controller &lt;a href=&#34;https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.6.1/pkg/builder?tab=doc&#34;&gt;Builder&lt;/a&gt; helpers to handle more of the details.&lt;/p&gt;
&lt;h4 id=&#34;set-rbac-permissions&#34;&gt;Set RBAC permissions&lt;/h4&gt;
&lt;p&gt;The RBAC permissions are now configured via &lt;a href=&#34;https://book.kubebuilder.io/reference/markers/rbac.html&#34;&gt;RBAC markers&lt;/a&gt;, which are used to generate and update the manifest files present in &lt;code&gt;config/rbac/&lt;/code&gt;. These markers can be found (and should be defined) on the &lt;code&gt;Reconcile()&lt;/code&gt; method of each controller.&lt;/p&gt;
&lt;p&gt;In the Memcached example, they look like the following:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;//+kubebuilder:rbac:groups=cache.example.com,resources=memcacheds,verbs=get;list;watch;create;update;patch;delete
&lt;/span&gt;&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;//+kubebuilder:rbac:groups=cache.example.com,resources=memcacheds/status,verbs=get;update;patch
&lt;/span&gt;&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;//+kubebuilder:rbac:groups=apps,resources=deployments,verbs=get;list;watch;create;update;patch;delete
&lt;/span&gt;&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;//+kubebuilder:rbac:groups=core,resources=pods,verbs=get;list
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;To update &lt;code&gt;config/rbac/role.yaml&lt;/code&gt; after changing the markers, run &lt;code&gt;make manifests&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;By default, new projects are cluster-scoped (i.e. they have cluster-scoped permissions and watch all namespaces). Read the &lt;a href=&#34;/docs/building-operators/golang/operator-scope&#34;&gt;operator scope documentation&lt;/a&gt; for more information about changing the scope of your operator.&lt;/p&gt;
&lt;p&gt;See the complete migrated &lt;code&gt;memcached_controller.go&lt;/code&gt; code &lt;a href=&#34;https://github.com/operator-framework/operator-sdk/tree/master/testdata/go/v4/memcached-operator&#34;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; The version of &lt;a href=&#34;https://github.com/kubernetes-sigs/controller-runtime/releases&#34;&gt;controller-runtime&lt;/a&gt; used in the projects scaffolded by SDK &lt;code&gt;0.19.x+&lt;/code&gt; was &lt;code&gt;v0.6.0&lt;/code&gt;. Please check &lt;a href=&#34;https://github.com/kubernetes-sigs/controller-runtime/releases&#34;&gt;sigs.k8s.io/controller-runtime release docs from 0.7.0+ version&lt;/a&gt; for breaking changes.&lt;/p&gt;
&lt;h5 id=&#34;updating-your-serviceaccount&#34;&gt;Updating your ServiceAccount&lt;/h5&gt;
&lt;p&gt;New Go projects come with a ServiceAccount &lt;code&gt;controller-manager&lt;/code&gt; in &lt;code&gt;config/rbac/service_account.yaml&lt;/code&gt;.
Your project&amp;rsquo;s RoleBinding and ClusterRoleBinding subjects, and Deployments &lt;code&gt;spec.template.spec.serviceAccountName&lt;/code&gt;
that reference a ServiceAccount already refer to this new name. When you run &lt;code&gt;make deploy&lt;/code&gt;,
your project&amp;rsquo;s name will be prepended to &lt;code&gt;controller-manager&lt;/code&gt;, making it unique within a namespace,
much like your old &lt;code&gt;deploy/service_account.yaml&lt;/code&gt;. If you wish to use the old ServiceAccount,
make sure to update all RBAC bindings and your manager Deployment.&lt;/p&gt;
&lt;h3 id=&#34;migrate-maingo&#34;&gt;Migrate &lt;code&gt;main.go&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;By checking our new &lt;code&gt;main.go&lt;/code&gt; we will find that:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The SDK &lt;a href=&#34;https://pkg.go.dev/github.com/operator-framework/operator-lib@v0.1.0/leader?tab=doc&#34;&gt;leader.Become&lt;/a&gt; was replaced by the &lt;a href=&#34;https://pkg.go.dev/sigs.k8s.io/controller-runtime/pkg/manager#LeaderElectionRunnable&#34;&gt;controller-runtime&amp;rsquo;s leader&lt;/a&gt; with lease mechanism. However, you can still use &lt;a href=&#34;https://pkg.go.dev/github.com/operator-framework/operator-lib@v0.1.0/leader?tab=doc&#34;&gt;leader.Become&lt;/a&gt; if you wish:&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;main&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;...&lt;/span&gt;
	&lt;span style=&#34;color:#000&#34;&gt;ctx&lt;/span&gt; &lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;context&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;TODO&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;()&lt;/span&gt;
	&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;// Become the leader before proceeding
&lt;/span&gt;&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;&lt;/span&gt;	&lt;span style=&#34;color:#000&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;leader&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;Become&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;ctx&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#4e9a06&#34;&gt;&amp;#34;memcached-operator-lock&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;)&lt;/span&gt;
	&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;nil&lt;/span&gt; &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;{&lt;/span&gt;
    	&lt;span style=&#34;color:#000&#34;&gt;log&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;Error&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;err&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#4e9a06&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;)&lt;/span&gt;
    	&lt;span style=&#34;color:#000&#34;&gt;os&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;Exit&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#0000cf;font-weight:bold&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;)&lt;/span&gt;
	&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;...&lt;/span&gt;
&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In order to use the previous one ensure that you have the &lt;a href=&#34;https://github.com/operator-framework/operator-lib/&#34;&gt;operator-lib&lt;/a&gt; as a dependency of your project.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;The default port used by the metric endpoint binds to &lt;code&gt;:8080&lt;/code&gt; from the previous &lt;code&gt;:8383&lt;/code&gt;. To continue using port &lt;code&gt;8383&lt;/code&gt;, specify &lt;code&gt;--metrics-bind-address=:8383&lt;/code&gt; when you start the operator.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;OPERATOR_NAME&lt;/code&gt; and &lt;code&gt;POD_NAME&lt;/code&gt; environment variables are no longer used. &lt;code&gt;OPERATOR_NAME&lt;/code&gt; was used to define the name for a leader election config map. Operator authors should use the &lt;code&gt;LeaderElectionID&lt;/code&gt; attribute from the &lt;a href=&#34;https://pkg.go.dev/sigs.k8s.io/controller-runtime/pkg/manager#Options&#34;&gt;Manager Options&lt;/a&gt; which is hardcoded in &lt;code&gt;main.go&lt;/code&gt;:&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;main&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;...&lt;/span&gt;
	&lt;span style=&#34;color:#000&#34;&gt;mgr&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;ctrl&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;NewManager&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;ctrl&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;GetConfigOrDie&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(),&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;ctrl&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;Options&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;{&lt;/span&gt;
		&lt;span style=&#34;color:#000&#34;&gt;Scheme&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;                 &lt;span style=&#34;color:#000&#34;&gt;scheme&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;,&lt;/span&gt;
		&lt;span style=&#34;color:#000&#34;&gt;MetricsBindAddress&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;     &lt;span style=&#34;color:#000&#34;&gt;metricsAddr&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;,&lt;/span&gt;
		&lt;span style=&#34;color:#000&#34;&gt;Port&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;                   &lt;span style=&#34;color:#0000cf;font-weight:bold&#34;&gt;9443&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;,&lt;/span&gt;
		&lt;span style=&#34;color:#000&#34;&gt;HealthProbeBindAddress&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;probeAddr&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;,&lt;/span&gt;
		&lt;span style=&#34;color:#000&#34;&gt;LeaderElection&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;         &lt;span style=&#34;color:#000&#34;&gt;enableLeaderElection&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;,&lt;/span&gt;
		&lt;span style=&#34;color:#000&#34;&gt;LeaderElectionID&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;       &lt;span style=&#34;color:#4e9a06&#34;&gt;&amp;#34;86f835c3.example.com&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;,&lt;/span&gt;
	&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;})&lt;/span&gt;
&lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;...&lt;/span&gt;
&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;Ensure that you copy all customizations made in &lt;code&gt;cmd/manager/main.go&lt;/code&gt; to &lt;code&gt;main.go&lt;/code&gt;. You’ll also need to ensure that all needed schemes have been registered, if you have been using third-party APIs (i.e Route Api from OpenShift).&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;migrate-your-tests&#34;&gt;Migrate your tests&lt;/h3&gt;
&lt;p&gt;For the new layout, you will see that &lt;code&gt;controllers/suite_test.go&lt;/code&gt; is created when a controller is scaffolded by the tool. This file contains boilerplate for executing integration tests using &lt;a href=&#34;https://pkg.go.dev/sigs.k8s.io/controller-runtime/pkg/envtest&#34;&gt;envtest&lt;/a&gt; with &lt;a href=&#34;https://onsi.github.io/ginkgo/&#34;&gt;ginkgo&lt;/a&gt; and &lt;a href=&#34;https://onsi.github.io/gomega/&#34;&gt;gomega&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Operator SDK 1.0.0+ removes support for the legacy test framework and no longer supports the &lt;code&gt;operator-sdk test&lt;/code&gt; subcommand. All affected tests should be migrated to use &lt;code&gt;envtest&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The Operator SDK project recommends controller-runtime&amp;rsquo;s &lt;a href=&#34;https://pkg.go.dev/sigs.k8s.io/controller-runtime/pkg/envtest&#34;&gt;envtest&lt;/a&gt; because it has a more active contributor community, it is more mature than Operator SDK&amp;rsquo;s test framework, and it does not require an actual cluster to run tests, which can be a huge benefit in CI scenarios.&lt;/p&gt;
&lt;p&gt;To learn more about how you can test your controllers, see the documentation about &lt;a href=&#34;https://book.kubebuilder.io/cronjob-tutorial/writing-tests.html&#34;&gt;writing controller tests&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&#34;migrate-your-custom-resources&#34;&gt;Migrate your Custom Resources&lt;/h3&gt;
&lt;p&gt;Custom resource samples are stored in &lt;code&gt;./config/samples&lt;/code&gt; using the new project structure. Copy the examples from your existing project into this directory. In existing projects, CR files have the format &lt;code&gt;./deploy/crds/&amp;lt;group&amp;gt;.&amp;lt;domain&amp;gt;_&amp;lt;version&amp;gt;_&amp;lt;kind&amp;gt;_cr.yaml&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;In our example, we&amp;rsquo;ll copy the specs from &lt;code&gt;deploy/crds/cache.example.com_v1alpha1_memcached_cr.yaml&lt;/code&gt;
to &lt;code&gt;config/samples/cache_v1alpha1_memcached.yaml&lt;/code&gt;&lt;/p&gt;
&lt;h3 id=&#34;configure-your-operator&#34;&gt;Configure your Operator&lt;/h3&gt;
&lt;p&gt;In case your project has customizations in the &lt;code&gt;deploy/operator.yaml&lt;/code&gt;, it needs to be added to
&lt;code&gt;config/manager/manager.yaml&lt;/code&gt;. Note that &lt;code&gt;OPERATOR_NAME&lt;/code&gt; and &lt;code&gt;POD_NAME&lt;/code&gt; env vars are no longer used. For further information, check out the section &lt;a href=&#34;/docs/building-operators/golang/migration/#migrate-maingo&#34;&gt;Migrate &lt;code&gt;main.go&lt;/code&gt; &lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&#34;export-metrics&#34;&gt;Export Metrics&lt;/h3&gt;
&lt;p&gt;If you are using metrics and would like to keep them exported, see that the &lt;code&gt;func addMetrics()&lt;/code&gt; is no longer generated in the &lt;code&gt;main.go&lt;/code&gt; and it is now configurable via &lt;a href=&#34;https://github.com/kubernetes-sigs/kustomize&#34;&gt;kustomize&lt;/a&gt;.&lt;/p&gt;
&lt;h4 id=&#34;configure-prometheus-metrics&#34;&gt;Configure Prometheus metrics&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Ensure that you have Prometheus installed in the cluster:
To check if you have the required API resource to create the &lt;code&gt;ServiceMonitor&lt;/code&gt; run:&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;kubectl api-resources &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;|&lt;/span&gt; grep servicemonitors
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If not, you can install Prometheus via &lt;a href=&#34;https://github.com/coreos/kube-prometheus#installing&#34;&gt;kube-prometheus&lt;/a&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;kubectl apply -f https://raw.githubusercontent.com/coreos/prometheus-operator/release-0.33/bundle.yaml
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;Now uncomment the line &lt;code&gt;- ../prometheus&lt;/code&gt; in the &lt;code&gt;config/default/kustomization.yaml&lt;/code&gt; file. It creates the &lt;code&gt;ServiceMonitor&lt;/code&gt; resource which enables exporting the metrics:&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;# [PROMETHEUS] To enable prometheus monitor, uncomment all sections with &amp;#39;PROMETHEUS&amp;#39;.&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;&lt;/span&gt;- ../prometheus&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id=&#34;use-handler-from-operator-lib&#34;&gt;Use Handler from &lt;code&gt;operator-lib&lt;/code&gt;&lt;/h4&gt;
&lt;p&gt;By using the &lt;a href=&#34;https://pkg.go.dev/github.com/operator-framework/operator-lib@v0.1.0/handler?tab=doc#InstrumentedEnqueueRequestForObject&#34;&gt;InstrumentedEnqueueRequestForObject&lt;/a&gt; you will be able to export metrics from your Custom Resources. In our example, it would look like:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;import&lt;/span&gt; &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(&lt;/span&gt;
    &lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;...&lt;/span&gt;
	&lt;span style=&#34;color:#4e9a06&#34;&gt;&amp;#34;github.com/operator-framework/operator-lib/handler&amp;#34;&lt;/span&gt;
    &lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;...&lt;/span&gt;
&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;)&lt;/span&gt;

&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;r&lt;/span&gt; &lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;MemcachedReconciler&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;SetupWithManager&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;mgr&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;ctrl&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;Manager&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;error&lt;/span&gt; &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;{&lt;/span&gt;
	&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;// Create a new controller
&lt;/span&gt;&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;&lt;/span&gt;	&lt;span style=&#34;color:#000&#34;&gt;c&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;controller&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;New&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#4e9a06&#34;&gt;&amp;#34;memcached-controller&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;mgr&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;controller&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;Options&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;{&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;Reconciler&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;r&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;})&lt;/span&gt;
	&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;nil&lt;/span&gt; &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;{&lt;/span&gt;
		&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;err&lt;/span&gt;
	&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;}&lt;/span&gt;
    &lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;...&lt;/span&gt;
	&lt;span style=&#34;color:#000&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;c&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;Watch&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;source&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;Kind&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;{&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;Type&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;cachev1alpha1&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;Memcached&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;{}},&lt;/span&gt; &lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;handler&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;InstrumentedEnqueueRequestForObject&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;{})&lt;/span&gt;
	&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;nil&lt;/span&gt; &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;{&lt;/span&gt;
		&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#000&#34;&gt;err&lt;/span&gt;
	&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;}&lt;/span&gt;
	&lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;...&lt;/span&gt;
	&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;nil&lt;/span&gt;
&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Ensure that you have the &lt;a href=&#34;https://github.com/operator-framework/operator-lib/&#34;&gt;operator-lib&lt;/a&gt; added to your &lt;code&gt;go.mod&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;In this way, the following metric with the resource info will be exported:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;resource_created_at_seconds{&amp;quot;name&amp;quot;, &amp;quot;namespace&amp;quot;, &amp;quot;group&amp;quot;, &amp;quot;version&amp;quot;, &amp;quot;kind&amp;quot;}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; To check it you can create a pod to curl the &lt;code&gt;metrics/&lt;/code&gt; endpoint but note that it is now protected by the &lt;a href=&#34;https://github.com/brancz/kube-rbac-proxy&#34;&gt;kube-auth-proxy&lt;/a&gt; which means that you will need to create a &lt;code&gt;ClusterRoleBinding&lt;/code&gt; and obtain the token from the ServiceAccount&amp;rsquo;s secret which will be used in the requests. Otherwise, to test you can disable the &lt;a href=&#34;https://github.com/brancz/kube-rbac-proxy&#34;&gt;kube-auth-proxy&lt;/a&gt; as well.&lt;/p&gt;
&lt;p&gt;For more info see the &lt;a href=&#34;https://book.kubebuilder.io/reference/metrics.html?highlight=metr#metrics&#34;&gt;metrics&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&#34;operator-image&#34;&gt;Operator image&lt;/h3&gt;
&lt;p&gt;The Dockerfile image also changes and now it is &lt;code&gt;multi-stage&lt;/code&gt;, &lt;code&gt;distroless&lt;/code&gt; and still &lt;code&gt;rootless&lt;/code&gt;. However, users can change it to work as they want.&lt;/p&gt;
&lt;p&gt;You might need to port some customizations made in your old Dockerfile as well. Also, if you wish to still use the previous UBI image replace:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-docker&#34; data-lang=&#34;docker&#34;&gt;&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;# Use distroless as minimal base image to package the manager binary&lt;/span&gt;&lt;span style=&#34;color:#a40000&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#a40000&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;# Refer to https://github.com/GoogleContainerTools/distroless for more details&lt;/span&gt;&lt;span style=&#34;color:#a40000&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#a40000&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;FROM&lt;/span&gt;&lt;span style=&#34;color:#4e9a06&#34;&gt; gcr.io/distroless/static:nonroot&lt;/span&gt;&lt;span style=&#34;color:#a40000&#34;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;With:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-docker&#34; data-lang=&#34;docker&#34;&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;FROM&lt;/span&gt;&lt;span style=&#34;color:#4e9a06&#34;&gt; registry.access.redhat.com/ubi8/ubi-minimal:latest&lt;/span&gt;&lt;span style=&#34;color:#a40000&#34;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;generate-manifests-and-build-the-operator&#34;&gt;Generate Manifests and Build the operator&lt;/h3&gt;
&lt;p&gt;Note that:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;operator-sdk generate crds&lt;/code&gt; is replaced with &lt;code&gt;make manifests&lt;/code&gt;, which generates CRDs and RBAC rules.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;operator-sdk build&lt;/code&gt; is replaced with &lt;code&gt;make docker-build IMG=&amp;lt;some-registry&amp;gt;/&amp;lt;project-name&amp;gt;:&amp;lt;tag&amp;gt;&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In this way, run:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;make manifests docker-build docker-push &lt;span style=&#34;color:#000&#34;&gt;IMG&lt;/span&gt;&lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;=&lt;/span&gt;example.com/memcached-operator:v0.0.1
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;verify-the-migration&#34;&gt;Verify the migration&lt;/h3&gt;
&lt;p&gt;The project can now be deployed on cluster by running the command:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;make deploy &lt;span style=&#34;color:#000&#34;&gt;IMG&lt;/span&gt;&lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;=&lt;/span&gt;example.com/memcached-operator:v0.0.1
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You can troubleshoot your deployment by checking container logs:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;kubectl logs deployment.apps/memcached-operator-controller-manager -n memcached-operator-system -c manager
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;For further steps regarding the deployment of the operator, creation of custom resources, and cleaning up of resources, see the &lt;a href=&#34;/docs/building-operators/golang/tutorial/#run-the-operator&#34;&gt;tutorial&lt;/a&gt;.&lt;/p&gt;

      </description>
    </item>
    
  </channel>
</rss>
