<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Controller-Runtime on K-Life Hack | Systems Architecture &amp; DevOps</title><link>https://klifehack.com/en/tags/controller-runtime/</link><description>Recent content in Controller-Runtime on K-Life Hack | Systems Architecture &amp; DevOps</description><generator>Hugo -- gohugo.io</generator><language>en</language><lastBuildDate>Wed, 11 Nov 2026 11:00:35 +0900</lastBuildDate><atom:link href="https://klifehack.com/en/tags/controller-runtime/index.xml" rel="self" type="application/rss+xml"/><item><title>Basic Verification of Custom CRD Design and Controller Implementation with Kubebuilder</title><link>https://klifehack.com/en/p/kubebuilder-crd-controller-implementation/</link><pubDate>Wed, 11 Nov 2026 11:00:35 +0900</pubDate><guid>https://klifehack.com/en/p/kubebuilder-crd-controller-implementation/</guid><description>&lt;p&gt;In the process of operating a Kubernetes cluster, relying solely on standard primitives such as Pods, Services, and Deployments introduces challenges where domain-specific lifecycle management and declarative state maintenance cannot be fully automated. Because ad-hoc operations using shell scripts or external scripts are prone to human error and state drift, it becomes necessary to apply the Operator pattern—registering custom resource types directly into the Kubernetes Control Plane and managing their lifecycle via the API server.&lt;/p&gt;
&lt;p&gt;This article outlines the workflow from formulating a Custom Resource Definition (CRD) schema using the Kubebuilder framework to implementing a state-tracking controller via a Reconcile loop and verifying connectivity in a local environment.&lt;/p&gt;
&lt;h2 id="1-components-of-the-kubernetes-extension-architecture"&gt;1. Components of the Kubernetes Extension Architecture
&lt;/h2&gt;&lt;p&gt;The Kubernetes extension mechanism is based on a feedback control model that reconciles the declared specification (Desired State) with the actual system state (Actual State).&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;b&gt;Custom Resource (CR):&lt;/b&gt; An instance of a user-defined custom object. Data is persisted to etcd, the cluster&amp;rsquo;s storage backend, enabling CRUD operations via the API server.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Custom Resource Definition (CRD):&lt;/b&gt; The blueprint defining the OpenAPI v3 schema of a CR. It specifies field type validation, required checks, and the presence or absence of status subresources.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Controller:&lt;/b&gt; An autonomous process that watches for events (create, update, delete) on specified resources and executes a &lt;code&gt;Reconcile()&lt;/code&gt; function within an infinite loop structure to eliminate discrepancies.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="characteristics-of-development-framework-options"&gt;Characteristics of Development Framework Options
&lt;/h3&gt;&lt;p&gt;For implementing Kubernetes controllers, Kubebuilder and Operator SDK are the two primary options. Their characteristics are compared below:&lt;/p&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th style="text-align: left"&gt;Item&lt;/th&gt;
 &lt;th style="text-align: left"&gt;Kubebuilder&lt;/th&gt;
 &lt;th style="text-align: left"&gt;Operator SDK&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td style="text-align: left"&gt;Primary Maintainer&lt;/td&gt;
 &lt;td style="text-align: left"&gt;Kubernetes SIGs&lt;/td&gt;
 &lt;td style="text-align: left"&gt;Operator Framework (CNCF/Red Hat)&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td style="text-align: left"&gt;Supported Languages&lt;/td&gt;
 &lt;td style="text-align: left"&gt;Go&lt;/td&gt;
 &lt;td style="text-align: left"&gt;Go, Ansible, Helm&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td style="text-align: left"&gt;Scope&lt;/td&gt;
 &lt;td style="text-align: left"&gt;Scaffolding, code generation, testing&lt;/td&gt;
 &lt;td style="text-align: left"&gt;Scaffolding, OLM integration, packaging&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td style="text-align: left"&gt;Structural Relationship&lt;/td&gt;
 &lt;td style="text-align: left"&gt;Standard core for controller implementation&lt;/td&gt;
 &lt;td style="text-align: left"&gt;Adopts Kubebuilder internally as the engine for Go-based implementations&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;In this implementation, Kubebuilder is adopted to minimize dependencies and rapidly verify pure Go controller logic.&lt;/p&gt;
&lt;h2 id="2-project-initialization-and-api-schema-definition"&gt;2. Project Initialization and API Schema Definition
&lt;/h2&gt;&lt;p&gt;First, create a working directory and run scaffolding by specifying the project domain and repository module name.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;mkdir cinema-operator &amp;amp;amp;&amp;amp;amp; cd cinema-operator
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;kubebuilder init --domain cinema.com --repo cinema.com/operator
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Next, generate the API resource structure with group name &lt;code&gt;entertainment&lt;/code&gt;, version &lt;code&gt;v1&lt;/code&gt;, and Kind name &lt;code&gt;Movie&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;kubebuilder create api --group entertainment --version v1 --kind Movie
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Edit the generated &lt;code&gt;api/v1/movie_types.go&lt;/code&gt; and declare domain-specific fields in &lt;code&gt;MovieSpec&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-go" data-lang="go"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;package&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;v1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;metav1&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;k8s.io/apimachinery/pkg/apis/meta/v1&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;type&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;MovieSpec&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;Title&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;string&lt;/span&gt; &lt;span style="color:#e6db74"&gt;`json:&amp;#34;title,omitempty&amp;#34;`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;Genre&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;string&lt;/span&gt; &lt;span style="color:#e6db74"&gt;`json:&amp;#34;genre,omitempty&amp;#34;`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;RunningTime&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; &lt;span style="color:#e6db74"&gt;`json:&amp;#34;runningTime,omitempty&amp;#34;`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;IsReleased&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;bool&lt;/span&gt; &lt;span style="color:#e6db74"&gt;`json:&amp;#34;isReleased,omitempty&amp;#34;`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;type&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;MovieStatus&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Add status fields for state management as necessary&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// +kubebuilder:object:root=true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// +kubebuilder:subresource:status&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;type&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Movie&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;metav1&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;TypeMeta&lt;/span&gt; &lt;span style="color:#e6db74"&gt;`json:&amp;#34;,inline&amp;#34;`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;metav1&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;ObjectMeta&lt;/span&gt; &lt;span style="color:#e6db74"&gt;`json:&amp;#34;metadata,omitempty&amp;#34;`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;Spec&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;MovieSpec&lt;/span&gt; &lt;span style="color:#e6db74"&gt;`json:&amp;#34;spec,omitempty&amp;#34;`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;Status&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;MovieStatus&lt;/span&gt; &lt;span style="color:#e6db74"&gt;`json:&amp;#34;status,omitempty&amp;#34;`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// +kubebuilder:object:root=true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;type&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;MovieList&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;metav1&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;TypeMeta&lt;/span&gt; &lt;span style="color:#e6db74"&gt;`json:&amp;#34;,inline&amp;#34;`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;metav1&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;ListMeta&lt;/span&gt; &lt;span style="color:#e6db74"&gt;`json:&amp;#34;metadata,omitempty&amp;#34;`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;Items&lt;/span&gt; []&lt;span style="color:#a6e22e"&gt;Movie&lt;/span&gt; &lt;span style="color:#e6db74"&gt;`json:&amp;#34;items&amp;#34;`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;init&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;SchemeBuilder&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Register&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;amp&lt;/span&gt;;&lt;span style="color:#a6e22e"&gt;Movie&lt;/span&gt;{}, &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;amp&lt;/span&gt;;&lt;span style="color:#a6e22e"&gt;MovieList&lt;/span&gt;{})
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="3-implementing-controller-reconcile-logic"&gt;3. Implementing Controller Reconcile Logic
&lt;/h2&gt;&lt;p&gt;Implement the processing flow upon event detection in &lt;code&gt;internal/controller/movie_controller.go&lt;/code&gt;. Retrieve the instance of the target resource from the API server; if it does not exist, ignore the NotFound error and terminate the loop.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-go" data-lang="go"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;package&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;controller&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;context&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;k8s.io/apimachinery/pkg/runtime&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;ctrl&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;sigs.k8s.io/controller-runtime&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;sigs.k8s.io/controller-runtime/pkg/client&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;sigs.k8s.io/controller-runtime/pkg/log&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;entertainmentv1&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;cinema.com/operator/api/v1&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;type&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;MovieReconciler&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;client&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Client&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;Scheme&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;runtime&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Scheme&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// +kubebuilder:rbac:groups=entertainment.cinema.com,resources=movies,verbs=get;list;watch;create;update;patch;delete&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// +kubebuilder:rbac:groups=entertainment.cinema.com,resources=movies/status,verbs=get;update;patch&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;r&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;MovieReconciler&lt;/span&gt;) &lt;span style="color:#a6e22e"&gt;Reconcile&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;ctx&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;context&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Context&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;req&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ctrl&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Request&lt;/span&gt;) (&lt;span style="color:#a6e22e"&gt;ctrl&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Result&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;error&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;logger&lt;/span&gt; &lt;span style="color:#f92672"&gt;:=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;FromContext&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;ctx&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;movie&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;entertainmentv1&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Movie&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;err&lt;/span&gt; &lt;span style="color:#f92672"&gt;:=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;r&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Get&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;ctx&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;req&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;NamespacedName&lt;/span&gt;, &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;amp&lt;/span&gt;;&lt;span style="color:#a6e22e"&gt;movie&lt;/span&gt;); &lt;span style="color:#a6e22e"&gt;err&lt;/span&gt; &lt;span style="color:#f92672"&gt;!=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;nil&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ctrl&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Result&lt;/span&gt;{}, &lt;span style="color:#a6e22e"&gt;client&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;IgnoreNotFound&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;err&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;logger&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Info&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Reconciling Movie resource&amp;#34;&lt;/span&gt;, 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;Name&amp;#34;&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;movie&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Name&lt;/span&gt;, 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;Title&amp;#34;&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;movie&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Spec&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Title&lt;/span&gt;, 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;Genre&amp;#34;&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;movie&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Spec&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Genre&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;RunningTime&amp;#34;&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;movie&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Spec&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;RunningTime&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;IsReleased&amp;#34;&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;movie&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Spec&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;IsReleased&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; )
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ctrl&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Result&lt;/span&gt;{}, &lt;span style="color:#66d9ef"&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;r&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;MovieReconciler&lt;/span&gt;) &lt;span style="color:#a6e22e"&gt;SetupWithManager&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;mgr&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ctrl&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Manager&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;error&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ctrl&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;NewControllerManagedBy&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;mgr&lt;/span&gt;).
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;For&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;amp&lt;/span&gt;;&lt;span style="color:#a6e22e"&gt;entertainmentv1&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Movie&lt;/span&gt;{}).
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;Complete&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;r&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="4-manifest-generation-and-local-endpoint-verification"&gt;4. Manifest Generation and Local Endpoint Verification
&lt;/h2&gt;&lt;p&gt;Automatically generate CRD manifest files from the marker comments (&lt;code&gt;+kubebuilder:...&lt;/code&gt;) attached to the Go structs.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;make manifests
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Apply the generated manifest file &lt;code&gt;config/crd/bases/entertainment.cinema.com_movies.yaml&lt;/code&gt; to the verification API server. Below is the procedure to launch a temporary container for development verification and register the resource.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;docker run -d --name&lt;span style="color:#f92672"&gt;=&lt;/span&gt;k8s-api --net&lt;span style="color:#f92672"&gt;=&lt;/span&gt;host &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; registry.k8s.io/kube-apiserver:v1.19.0 &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; kube-apiserver --etcd-servers&lt;span style="color:#f92672"&gt;=&lt;/span&gt;http://127.0.0.1:8888 &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --authorization-mode&lt;span style="color:#f92672"&gt;=&lt;/span&gt;AlwaysAllow --bind-address&lt;span style="color:#f92672"&gt;=&lt;/span&gt;0.0.0.0 &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --insecure-port&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;8080&lt;/span&gt; --secure-port&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;6444&lt;/span&gt; --allow-privileged&lt;span style="color:#f92672"&gt;=&lt;/span&gt;true
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;kubectl --server&lt;span style="color:#f92672"&gt;=&lt;/span&gt;http://127.0.0.1:8080 apply -f config/crd/bases/entertainment.cinema.com_movies.yaml
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Write a CR instance manifest &lt;code&gt;movie-sample.yaml&lt;/code&gt; that conforms to the defined schema.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;apiVersion&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;entertainment.cinema.com/v1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;kind&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;Movie&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;metadata&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;name&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;the-outlaws&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;spec&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;title&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;The Outlaws 4&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;genre&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;Action&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;runningTime&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;109&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;isReleased&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Register the CR into the cluster.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;kubectl --server&lt;span style="color:#f92672"&gt;=&lt;/span&gt;http://127.0.0.1:8080 apply -f movie-sample.yaml
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Start the controller process and synchronize it with the API server.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;export KUBERNETES_MASTER&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;http://127.0.0.1:8080&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;make run
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="5-troubleshooting"&gt;5. Troubleshooting
&lt;/h2&gt;&lt;h3 id="schema-validation-errors-during-crd-application"&gt;Schema Validation Errors During CRD Application
&lt;/h3&gt;&lt;p&gt;When applying a CRD, syntax errors in Kubebuilder tags or type mismatches may trigger the following error:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;error: unable to recognize &amp;#34;config/crd/bases/entertainment.cinema.com_movies.yaml&amp;#34;: no matches for kind &amp;#34;CustomResourceDefinition&amp;#34; in version &amp;#34;apiextensions.k8s.io/v1&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In this scenario, verify whether the target API server version matches the CRD API specification (&lt;code&gt;v1&lt;/code&gt; or &lt;code&gt;v1beta1&lt;/code&gt;). If backward compatibility is required, re-specify &lt;code&gt;crd:crdVersions=v1beta1&lt;/code&gt; in the Controller-tools generation options within the &lt;code&gt;Makefile&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id="reconcile-failure-due-to-insufficient-rbac-permissions"&gt;Reconcile Failure Due to Insufficient RBAC Permissions
&lt;/h3&gt;&lt;p&gt;When running the controller as a Pod in an actual cluster environment, missing RoleBindings for the ServiceAccount will lead to access denial errors such as:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ERROR controllers.Movie unable to fetch Movie {&amp;#34;error&amp;#34;: &amp;#34;movies.entertainment.cinema.com is forbidden: User \&amp;#34;system:serviceaccount:cinema-system:cinema-operator\&amp;#34; cannot get resource \&amp;#34;movies\&amp;#34; in API group \&amp;#34;entertainment.cinema.com\&amp;#34;&amp;#34;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This issue originates either from missing RBAC markers (&lt;code&gt;// +kubebuilder:rbac:groups=...&lt;/code&gt;) in the Go code or from not applying the generated Role configurations. After updating the markers, re-run &lt;code&gt;make manifests&lt;/code&gt; and redeploy the generated ClusterRole/Role manifests.&lt;/p&gt;
&lt;h2 id="6-verification-logs-and-execution-protocol"&gt;6. Verification Logs and Execution Protocol
&lt;/h2&gt;&lt;p&gt;Inspect the logs from CR application and controller startup to verify that the Reconcile process executes correctly.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ kubectl --server=http://127.0.0.1:8080 get crd
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;NAME CREATED AT
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;movies.entertainment.cinema.com 2026-11-11T09:12:44Z
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ kubectl --server=http://127.0.0.1:8080 get movie the-outlaws -o yaml
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;apiVersion: entertainment.cinema.com/v1
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;kind: Movie
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;metadata:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; name: the-outlaws
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; namespace: default
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;spec:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; genre: Action
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; isReleased: true
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; runningTime: 109
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; title: The Outlaws 4
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ make run
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;/home/user/cinema-operator/bin/controller-gen rbac:roleName=manager-role crd webhook paths=&amp;#34;./...&amp;#34; output:crd:artifacts:config=config/crd/bases
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;go run ./cmd/main.go
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2026-11-11T09:15:02.114Z INFO controller-runtime.metrics Metrics server is starting to listen {&amp;#34;addr&amp;#34;: &amp;#34;:8080&amp;#34;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2026-11-11T09:15:02.115Z INFO Starting server {&amp;#34;path&amp;#34;: &amp;#34;/metrics&amp;#34;, &amp;#34;kind&amp;#34;: &amp;#34;metrics&amp;#34;, &amp;#34;addr&amp;#34;: &amp;#34;[::]:8080&amp;#34;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2026-11-11T09:15:02.116Z INFO Starting EventSource {&amp;#34;controller&amp;#34;: &amp;#34;movie&amp;#34;, &amp;#34;controllerGroup&amp;#34;: &amp;#34;entertainment.cinema.com&amp;#34;, &amp;#34;controllerKind&amp;#34;: &amp;#34;Movie&amp;#34;, &amp;#34;source&amp;#34;: &amp;#34;kind source: *v1.Movie&amp;#34;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2026-11-11T09:15:02.116Z INFO Starting Controller {&amp;#34;controller&amp;#34;: &amp;#34;movie&amp;#34;, &amp;#34;controllerGroup&amp;#34;: &amp;#34;entertainment.cinema.com&amp;#34;, &amp;#34;controllerKind&amp;#34;: &amp;#34;Movie&amp;#34;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2026-11-11T09:15:02.218Z INFO Starting workers {&amp;#34;controller&amp;#34;: &amp;#34;movie&amp;#34;, &amp;#34;controllerGroup&amp;#34;: &amp;#34;entertainment.cinema.com&amp;#34;, &amp;#34;controllerKind&amp;#34;: &amp;#34;Movie&amp;#34;, &amp;#34;worker count&amp;#34;: 1}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2026-11-11T09:15:02.219Z INFO Reconciling Movie resource {&amp;#34;controller&amp;#34;: &amp;#34;movie&amp;#34;, &amp;#34;controllerGroup&amp;#34;: &amp;#34;entertainment.cinema.com&amp;#34;, &amp;#34;controllerKind&amp;#34;: &amp;#34;Movie&amp;#34;, &amp;#34;Movie&amp;#34;: {&amp;#34;name&amp;#34;:&amp;#34;the-outlaws&amp;#34;,&amp;#34;namespace&amp;#34;:&amp;#34;default&amp;#34;}, &amp;#34;namespace&amp;#34;: &amp;#34;default&amp;#34;, &amp;#34;name&amp;#34;: &amp;#34;the-outlaws&amp;#34;, &amp;#34;reconcileID&amp;#34;: &amp;#34;84e3d179-8ab3-4c91-921c-cb9716ebff12&amp;#34;, &amp;#34;Name&amp;#34;: &amp;#34;the-outlaws&amp;#34;, &amp;#34;Title&amp;#34;: &amp;#34;The Outlaws 4&amp;#34;, &amp;#34;Genre&amp;#34;: &amp;#34;Action&amp;#34;, &amp;#34;RunningTime&amp;#34;: 109, &amp;#34;IsReleased&amp;#34;: true}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="7-architectural-separation-between-crds-and-annotations"&gt;7. Architectural Separation Between CRDs and Annotations
&lt;/h2&gt;&lt;p&gt;When storing custom data in Kubernetes, two primary approaches are considered: using Annotations or introducing a new CRD. The boundary between the two directly impacts system responsibility design.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;b&gt;CRD:&lt;/b&gt; Used when strict system schema validation is required and a typed API endpoint needs to be established. CRDs are mandatory for constructing the Operator pattern, where other resources (Pods, Jobs, external cloud services, etc.) are actively created, updated, or deleted via the Reconcile loop.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Annotation:&lt;/b&gt; Used exclusively for attaching incidental metadata, external audit information, or temporary unstructured text. No type validation is performed by the API server.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="operational-notes"&gt;Operational Notes
&lt;/h2&gt;&lt;p&gt;When designing custom resources and controllers, the Reconcile logic must be guaranteed to be idempotent. Because the Kubernetes event notification mechanism follows an At-Least-Once delivery model, the logic structure must prevent duplicate resource creation and state inconsistencies even if Reconcile is invoked multiple consecutive times for the same object.&lt;/p&gt;</description></item></channel></rss>