<?xml version='1.0' encoding='UTF-8'?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
  <id>http://lernfunk.de/media/654321</id>
  <title>double12gzh - Posts tagged k8s源码分析</title>
  <updated>2020-11-08T14:11:59.642257+00:00</updated>
  <link href="double12gzhblogs.readthedocs.io"/>
  <link href="double12gzhblogs.readthedocs.io/blogs/tag/k8s源码分析/atom.xml"/>
  <generator uri="https://ablog.readthedocs.org" version="0.10.9">ABlog</generator>
  <entry>
    <id>double12gzhblogs.readthedocs.io/blogs/Kubernetes/2020-10-14-client-go%E7%B3%BB%E5%88%97%E4%B9%8B3---restclient%E7%9A%84%E4%BD%BF%E7%94%A8.html</id>
    <title>client-go系列之3—restclient的使用</title>
    <updated>2020-10-14T00:00:00+00:00</updated>
    <author>
      <name>JeffreyGuan</name>
    </author>
    <content type="html">&lt;div class="section" id="client-go3-restclient"&gt;

&lt;p&gt;摘要：介绍如何使用client-go中的restclient，可以结合“系列之1”来看。&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="https://gitee.com/double12gzh/wiki-pictures/raw/master/2020-10-13-client-go-kubeconfig/0.png" /&gt;&lt;/p&gt;
&lt;div class="section" id="id1"&gt;
&lt;h2&gt;0. 背景&lt;/h2&gt;
&lt;blockquote&gt;
&lt;div&gt;&lt;p&gt;个人主页: https://gzh.readthedocs.io&lt;/p&gt;
&lt;p&gt;关注容器技术、关注&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;Kubernetes&lt;/span&gt;&lt;/code&gt;。问题或建议，请公众号留言。&lt;/p&gt;
&lt;/div&gt;&lt;/blockquote&gt;
&lt;p&gt;首先我通过&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;kind&lt;/span&gt;&lt;/code&gt;创建了一个6节点的集群，本文章中所有的操作都是在这个集群中进行的。&lt;/p&gt;
&lt;p&gt;通过本文的讲解，希望您能了解如何使用client-go中的RESTClient来对资源进行操作，这里我只是举了最简单的例子—pod资源获取。&lt;/p&gt;
&lt;p&gt;文中用到的软件的版本如下：&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;kind&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight-bash notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;root@xxx-wsl ~/client-go-example&lt;span class="o"&gt;]&lt;/span&gt; kind version
kind v0.9.0 go1.15.2 linux/amd64
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="id2"&gt;
&lt;h2&gt;1. 环境准备&lt;/h2&gt;
&lt;p&gt;通过kind创建多节点的k8s集群: 3个master节点 + 3个worker节点&lt;/p&gt;
&lt;div class="highlight-bash notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;root@xxx-wsl ~/init_kind_clusters&lt;span class="o"&gt;]&lt;/span&gt; kind create cluster --config&lt;span class="o"&gt;=&lt;/span&gt;init_cluster.yaml
Creating cluster &lt;span class="s2"&gt;&amp;quot;kind&amp;quot;&lt;/span&gt; ...
 ✓ Ensuring node image &lt;span class="o"&gt;(&lt;/span&gt;kindest/node:v1.19.1&lt;span class="o"&gt;)&lt;/span&gt; 🖼
 ✓ Preparing nodes 📦 📦 📦 📦 📦 📦
 ✓ Configuring the external load balancer ⚖️
 ✓ Writing configuration 📜
 ✓ Starting control-plane 🕹️
 ✓ Installing CNI 🔌
 ✓ Installing StorageClass 💾
 ✓ Joining more control-plane nodes 🎮
 ✓ Joining worker nodes 🚜
Set kubectl context to &lt;span class="s2"&gt;&amp;quot;kind-kind&amp;quot;&lt;/span&gt;
You can now use your cluster with:

kubectl cluster-info --context kind-kind

Not sure what to &lt;span class="k"&gt;do&lt;/span&gt; next? 😅  Check out https://kind.sigs.k8s.io/docs/user/quick-start/
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;其中&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;init_cluster.yaml&lt;/span&gt;&lt;/code&gt;内容如下：&lt;/p&gt;
&lt;div class="highlight-yaml notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="p p-Indicator"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;root@xxx-wsl ~/init_kind_clusters&lt;/span&gt;&lt;span class="p p-Indicator"&gt;]&lt;/span&gt; &lt;span class="l l-Scalar l-Scalar-Plain"&gt;cat init_cluster.yaml&lt;/span&gt;
&lt;span class="l l-Scalar l-Scalar-Plain"&gt;# a cluster with 3 control-plane nodes and 3 workers&lt;/span&gt;
&lt;span class="l l-Scalar l-Scalar-Plain"&gt;kind&lt;/span&gt;&lt;span class="p p-Indicator"&gt;:&lt;/span&gt; &lt;span class="l l-Scalar l-Scalar-Plain"&gt;Cluster&lt;/span&gt;
&lt;span class="nt"&gt;apiVersion&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="l l-Scalar l-Scalar-Plain"&gt;kind.x-k8s.io/v1alpha4&lt;/span&gt;
&lt;span class="nt"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="p p-Indicator"&gt;-&lt;/span&gt; &lt;span class="nt"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="l l-Scalar l-Scalar-Plain"&gt;control-plane&lt;/span&gt;
&lt;span class="p p-Indicator"&gt;-&lt;/span&gt; &lt;span class="nt"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="l l-Scalar l-Scalar-Plain"&gt;control-plane&lt;/span&gt;
&lt;span class="p p-Indicator"&gt;-&lt;/span&gt; &lt;span class="nt"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="l l-Scalar l-Scalar-Plain"&gt;control-plane&lt;/span&gt;
&lt;span class="p p-Indicator"&gt;-&lt;/span&gt; &lt;span class="nt"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="l l-Scalar l-Scalar-Plain"&gt;worker&lt;/span&gt;
&lt;span class="p p-Indicator"&gt;-&lt;/span&gt; &lt;span class="nt"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="l l-Scalar l-Scalar-Plain"&gt;worker&lt;/span&gt;
&lt;span class="p p-Indicator"&gt;-&lt;/span&gt; &lt;span class="nt"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="l l-Scalar l-Scalar-Plain"&gt;worker&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="restclient"&gt;
&lt;h2&gt;2. RestClient使用示例&lt;/h2&gt;
&lt;p&gt;这段代码的作用：从namespace为&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;kube-system&lt;/span&gt;&lt;/code&gt;中获取所有的&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;pod&lt;/span&gt;&lt;/code&gt;并输出到屏幕&lt;/p&gt;
&lt;p&gt;&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;main.go&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;
&lt;div class="highlight-go notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kn"&gt;package&lt;/span&gt; &lt;span class="nx"&gt;main&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="s"&gt;&amp;quot;context&amp;quot;&lt;/span&gt;
        &lt;span class="s"&gt;&amp;quot;fmt&amp;quot;&lt;/span&gt;

        &lt;span class="nx"&gt;corev1&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;k8s.io/api/core/v1&amp;quot;&lt;/span&gt;
        &lt;span class="nx"&gt;metav1&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;k8s.io/apimachinery/pkg/apis/meta/v1&amp;quot;&lt;/span&gt;

        &lt;span class="s"&gt;&amp;quot;k8s.io/client-go/kubernetes/scheme&amp;quot;&lt;/span&gt;
        &lt;span class="s"&gt;&amp;quot;k8s.io/client-go/rest&amp;quot;&lt;/span&gt;
        &lt;span class="s"&gt;&amp;quot;k8s.io/client-go/tools/clientcmd&amp;quot;&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nx"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Prepare config object.&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c1"&gt;// 加载k8s配置文件，生成Config对象&lt;/span&gt;
        &lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nx"&gt;clientcmd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;BuildConfigFromFlags&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;/root/.kube/config&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nb"&gt;panic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;APIPath&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;api&amp;quot;&lt;/span&gt;
        &lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;GroupVersion&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;corev1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;SchemeGroupVersion&lt;/span&gt;
        &lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NegotiatedSerializer&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;scheme&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Codecs&lt;/span&gt;

        &lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Init RESTClient.&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c1"&gt;// 定义RestClient，用于与k8s API server进行交互&lt;/span&gt;
        &lt;span class="nx"&gt;restClient&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nx"&gt;rest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;RESTClientFor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nb"&gt;panic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Get Pods in cluster.&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c1"&gt;// 获取pod列表。这里只会从namespace为&amp;quot;kube-system&amp;quot;中获取指定的资源(pods)&lt;/span&gt;
        &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;corev1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PodList&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nx"&gt;restClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
                &lt;span class="nx"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;
                &lt;span class="nx"&gt;Namespace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;kube-system&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;
                &lt;span class="nx"&gt;Resource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;pods&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;
                &lt;span class="nx"&gt;VersionedParams&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;metav1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ListOptions&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;Limit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="nx"&gt;scheme&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ParameterCodec&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;
                &lt;span class="nx"&gt;Do&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;TODO&lt;/span&gt;&lt;span class="p"&gt;()).&lt;/span&gt;
                &lt;span class="nx"&gt;Into&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nb"&gt;panic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Print all listed pods.&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c1"&gt;// 打印所有获取到的pods资源，输出到标准输出&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;d&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="k"&gt;range&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Items&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;NAMESPACE: %v NAME: %v \t STATUS: %v \n&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Namespace&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Status&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Phase&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;go.mod&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;
&lt;div class="highlight-bash notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;module main

go &lt;span class="m"&gt;1&lt;/span&gt;.15

require &lt;span class="o"&gt;(&lt;/span&gt;
        github.com/go-logr/logr v0.2.1 // indirect
        github.com/google/gofuzz v1.2.0 // indirect
        github.com/imdario/mergo v0.3.11 // indirect
        golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0 // indirect
        golang.org/x/net v0.0.0-20201010224723-4f7140c49acb // indirect
        golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43 // indirect
        golang.org/x/sys v0.0.0-20201009025420-dfb3f7c4e634 // indirect
        golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e // indirect
        k8s.io/api v0.19.2
        k8s.io/apimachinery v0.19.2
        //k8s.io/client-go v11.0.0+incompatible
        //      k8s.io/client-go v11.0.0+incompatible
        k8s.io/klog v1.0.0 // indirect
        k8s.io/klog/v2 v2.3.0 // indirect
        k8s.io/utils v0.0.0-20201005171033-6301aaf42dc7 // indirect
&lt;span class="o"&gt;)&lt;/span&gt;

require k8s.io/client-go v0.19.2
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="id3"&gt;
&lt;h2&gt;3. 输出结果&lt;/h2&gt;
&lt;div class="highlight-bash notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;root@xxx-wsl ~/client-go-example&lt;span class="o"&gt;]&lt;/span&gt; go run main.go
Prepare config object.
Init RESTClient.
Get Pods in cluster.
Print all listed pods.
NAMESPACE: kube-system NAME: coredns-f9fd979d6-rhzfd     STATUS: Running
NAMESPACE: kube-system NAME: coredns-f9fd979d6-whrj2     STATUS: Running
NAMESPACE: kube-system NAME: etcd-kind-control-plane     STATUS: Running
NAMESPACE: kube-system NAME: etcd-kind-control-plane2    STATUS: Running
NAMESPACE: kube-system NAME: etcd-kind-control-plane3    STATUS: Running
NAMESPACE: kube-system NAME: kindnet-bpsfl       STATUS: Running
NAMESPACE: kube-system NAME: kindnet-ks6zv       STATUS: Running
NAMESPACE: kube-system NAME: kindnet-pm6zl       STATUS: Running
NAMESPACE: kube-system NAME: kindnet-qfhqt       STATUS: Running
NAMESPACE: kube-system NAME: kindnet-s7qqn       STATUS: Running
NAMESPACE: kube-system NAME: kindnet-trk5l       STATUS: Running
NAMESPACE: kube-system NAME: kube-apiserver-kind-control-plane   STATUS: Running
NAMESPACE: kube-system NAME: kube-apiserver-kind-control-plane2          STATUS: Running
NAMESPACE: kube-system NAME: kube-apiserver-kind-control-plane3          STATUS: Running
NAMESPACE: kube-system NAME: kube-controller-manager-kind-control-plane          STATUS: Running
NAMESPACE: kube-system NAME: kube-controller-manager-kind-control-plane2         STATUS: Running
NAMESPACE: kube-system NAME: kube-controller-manager-kind-control-plane3         STATUS: Running
NAMESPACE: kube-system NAME: kube-proxy-7gz67    STATUS: Running
NAMESPACE: kube-system NAME: kube-proxy-bvbkk    STATUS: Running
NAMESPACE: kube-system NAME: kube-proxy-clf72    STATUS: Running
NAMESPACE: kube-system NAME: kube-proxy-d8zpb    STATUS: Running
NAMESPACE: kube-system NAME: kube-proxy-dsmsj    STATUS: Running
NAMESPACE: kube-system NAME: kube-proxy-fplkk    STATUS: Running
NAMESPACE: kube-system NAME: kube-scheduler-kind-control-plane   STATUS: Running
NAMESPACE: kube-system NAME: kube-scheduler-kind-control-plane2          STATUS: Running
NAMESPACE: kube-system NAME: kube-scheduler-kind-control-plane3          STATUS: Running
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
</content>
    <link href="double12gzhblogs.readthedocs.io/blogs/Kubernetes/2020-10-14-client-go%E7%B3%BB%E5%88%97%E4%B9%8B3---restclient%E7%9A%84%E4%BD%BF%E7%94%A8.html" rel="alternate"/>
    <published>2020-10-14T00:00:00+00:00</published>
  </entry>
  <entry>
    <id>double12gzhblogs.readthedocs.io/blogs/Kubernetes/2020-10-17-client-go%E7%B3%BB%E5%88%97%E4%B9%8B4---Indexer.html</id>
    <title>client-go系列之4—Indexer</title>
    <updated>2020-10-17T00:00:00+00:00</updated>
    <author>
      <name>JeffreyGuan</name>
    </author>
    <content type="html">&lt;div class="section" id="client-go4-indexer"&gt;

&lt;p&gt;摘要：介绍client-go中Indexer机制。&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="https://gitee.com/double12gzh/wiki-pictures/raw/master/2020-10-13-client-go-kubeconfig/0.png" /&gt;&lt;/p&gt;
&lt;div class="section" id="id1"&gt;
&lt;h2&gt;1. 写在前面&lt;/h2&gt;
&lt;p&gt;在本系列教程的第一篇中，我们已经对如下这张图作了简单介绍。这张图非常重要，理解这张图对我们正确理解&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;client-go&lt;/span&gt;&lt;/code&gt;及&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;Controller&lt;/span&gt;&lt;/code&gt;非常有帮助(&lt;a class="reference external" href="https://github.com/kubernetes/sample-controller/blob/master/docs/controller-client-go.md"&gt;出处&lt;/a&gt;)。&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="https://raw.githubusercontent.com/kubernetes/sample-controller/master/docs/images/client-go-controller-interaction.jpeg" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;client-go&lt;/span&gt;&lt;/code&gt;中对其实现的代码位于&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;tools/cache&lt;/span&gt;&lt;/code&gt;，如下图：&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="https://gitee.com/double12gzh/wiki-pictures/raw/master/2020-10-16-custom-controller/code-path.png" /&gt;&lt;/p&gt;
&lt;p&gt;除了上图中展示的&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;Indexer&lt;/span&gt;&lt;/code&gt;的定义比较重要外，我们还需要关注&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;Indexer&lt;/span&gt;&lt;/code&gt;比较重要的数据结构：&lt;/p&gt;
&lt;div class="highlight-bash notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;root@xxxx-wsl /ACode/client-go&lt;span class="o"&gt;]&lt;/span&gt; cat tools/cache/index.go&lt;span class="p"&gt;|&lt;/span&gt; grep -B &lt;span class="m"&gt;1&lt;/span&gt; -A &lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="nb"&gt;type&lt;/span&gt;

// IndexFunc knows how to compute the &lt;span class="nb"&gt;set&lt;/span&gt; of indexed values &lt;span class="k"&gt;for&lt;/span&gt; an object.
&lt;span class="nb"&gt;type&lt;/span&gt; IndexFunc func&lt;span class="o"&gt;(&lt;/span&gt;obj interface&lt;span class="o"&gt;{})&lt;/span&gt; &lt;span class="o"&gt;([]&lt;/span&gt;string, error&lt;span class="o"&gt;)&lt;/span&gt;

--
// Index maps the indexed value to a &lt;span class="nb"&gt;set&lt;/span&gt; of keys in the store that match on that value
&lt;span class="nb"&gt;type&lt;/span&gt; Index map&lt;span class="o"&gt;[&lt;/span&gt;string&lt;span class="o"&gt;]&lt;/span&gt;sets.String

// Indexers maps a name to a IndexFunc
&lt;span class="nb"&gt;type&lt;/span&gt; Indexers map&lt;span class="o"&gt;[&lt;/span&gt;string&lt;span class="o"&gt;]&lt;/span&gt;IndexFunc

// Indices maps a name to an Index
&lt;span class="nb"&gt;type&lt;/span&gt; Indices map&lt;span class="o"&gt;[&lt;/span&gt;string&lt;span class="o"&gt;]&lt;/span&gt;Index
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;IndexFunc: 从接收的资源对象中，根据一系列的key来获取相应的值。&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Index: 建立key与被索引值的对应关系并存储到&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;Store&lt;/span&gt;&lt;/code&gt;中，即它里面的数据都是&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;Key/Value&lt;/span&gt;&lt;/code&gt;的形式。&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Indexers: 存储的是索引器的名字与索引器的实现函数。&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Indices: 存储缓存数据，形式&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;Key/Value&lt;/span&gt;&lt;/code&gt;，其中&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;Key&lt;/span&gt;&lt;/code&gt;为缓存器的字，&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;Value&lt;/span&gt;&lt;/code&gt;为缓存数据。&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="section" id="custom-controller"&gt;
&lt;h2&gt;2. Custom Controller中的组件&lt;/h2&gt;
&lt;p&gt;如图中所示，&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;Custom&lt;/span&gt; &lt;span class="pre"&gt;Controller&lt;/span&gt;&lt;/code&gt;是位于下半部分的内容。从图中可以很容易的看到，一个&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;Custom&lt;/span&gt; &lt;span class="pre"&gt;Controller&lt;/span&gt;&lt;/code&gt;主要包含以下内容：&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;Indexer&lt;/span&gt; &lt;span class="pre"&gt;Reference&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;Informer&lt;/span&gt; &lt;span class="pre"&gt;Reference&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;Resource&lt;/span&gt; &lt;span class="pre"&gt;Event&lt;/span&gt; &lt;span class="pre"&gt;Handler&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;WorkQueue&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;ProcessItem&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="section" id="indexer"&gt;
&lt;h3&gt;2.1 Indexer&lt;/h3&gt;
&lt;div class="section" id="id2"&gt;
&lt;h4&gt;2.1.1 简单介绍&lt;/h4&gt;
&lt;p&gt;它是一个知道如何使用CRD对象的 &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;Indexer&lt;/span&gt;&lt;/code&gt; 实例的引用(reference)。当我们写&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;自定义控制器&lt;/span&gt;&lt;/code&gt;(Custom Controller)代码时，将使用这个reference去做对象检索。&lt;/p&gt;
&lt;p&gt;&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;Indexer&lt;/span&gt;&lt;/code&gt;是client-go中实现的一个本地存储，它可以建立索引并存储Resource的对象。&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;Reflector&lt;/span&gt;&lt;/code&gt;通过&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;Delta&lt;/span&gt; &lt;span class="pre"&gt;FIFO&lt;/span&gt; &lt;span class="pre"&gt;Queue&lt;/span&gt;&lt;/code&gt;将资源对象存储到&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;Indexer&lt;/span&gt;&lt;/code&gt;中。&lt;/p&gt;
&lt;p&gt;需要注意的是，&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;Indexer&lt;/span&gt;&lt;/code&gt;中的数据与etcd中的数据是完全一致的，这样client-go需要数据时，无须每次都从api-server获取，从而减少了请求过多造成对api-server的压力。&lt;/p&gt;
&lt;blockquote&gt;
&lt;div&gt;&lt;p&gt;一句话总结：Indexer是用于存储+快速查找资源，即它的目的就是为了能够进行快速查找。&lt;/p&gt;
&lt;/div&gt;&lt;/blockquote&gt;
&lt;p&gt;&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;Indexer&lt;/span&gt;&lt;/code&gt;是如何实现“存储+快速查找资源”的呢？我们来看一下下面这张图，通过这张图方便我们理解一下&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;Indexer&lt;/span&gt;&lt;/code&gt;的存储结构：&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="https://gitee.com/double12gzh/wiki-pictures/raw/master/2020-10-17-indexer-data-structure/indexer_data_structure2.png" /&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;div&gt;&lt;p&gt;说明： 图中的&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;Indexers&lt;/span&gt;&lt;/code&gt;与&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;Indices&lt;/span&gt;&lt;/code&gt;虽然都指向了相同的&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;IndexFunc&lt;/span&gt;&lt;/code&gt;，这并不是说二者的数据是相同的，而是说二者使用的&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;IndexFunc&lt;/span&gt;&lt;/code&gt;是相同的。&lt;/p&gt;
&lt;/div&gt;&lt;/blockquote&gt;
&lt;p&gt;根据上面这个图，我们可以简单的规纳出与之对应的数据结构：&lt;/p&gt;
&lt;div class="highlight-go notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;// 包含的所有索引器/分类以及对应的实现&lt;/span&gt;
&lt;span class="nx"&gt;Indexers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
    &lt;span class="s"&gt;&amp;quot;namespace&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;NamespaceIndexFunc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;&amp;quot;nodeName&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;NodeNameIndexFunc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// 包含的所有索引分类中所有的索引数据&lt;/span&gt;
&lt;span class="nx"&gt;Indices&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;//namespace 这个索引分类下的所有索引数据&lt;/span&gt;
    &lt;span class="s"&gt;&amp;quot;namespace&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
         &lt;span class="c1"&gt;// Index 就是一个索引键下所有的对象键列表&lt;/span&gt;
        &lt;span class="s"&gt;&amp;quot;default&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;pod-1&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;pod-2&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; 
        &lt;span class="c1"&gt;// Index&lt;/span&gt;
        &lt;span class="s"&gt;&amp;quot;kube-system&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;pod-3&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;   
    &lt;span class="p"&gt;},&lt;/span&gt;

    &lt;span class="c1"&gt;//nodeName 这个索引分类下的所有索引数据(对象键列表)&lt;/span&gt;
    &lt;span class="s"&gt;&amp;quot;nodeName&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
         &lt;span class="c1"&gt;// Index&lt;/span&gt;
        &lt;span class="s"&gt;&amp;quot;node1&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;pod-1&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
         &lt;span class="c1"&gt;// Index&lt;/span&gt;
        &lt;span class="s"&gt;&amp;quot;node2&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;pod-2&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;pod-3&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;Indexers&lt;/span&gt;&lt;/code&gt;和&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;Indices&lt;/span&gt;&lt;/code&gt;都是按照&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;IndexFunc&lt;/span&gt;&lt;/code&gt;(名字)分组， 每个&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;IndexFunc&lt;/span&gt;&lt;/code&gt;输出多个&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;IndexKey&lt;/span&gt;&lt;/code&gt;，产生相同&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;IndexKey&lt;/span&gt;&lt;/code&gt;的多个对象存储在一个集合中。&lt;/p&gt;
&lt;p&gt;&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;IndexKey&lt;/span&gt;&lt;/code&gt;主要是用于快速查找&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;ObjectKey&lt;/span&gt;&lt;/code&gt;; 而&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;ObjectKey&lt;/span&gt;&lt;/code&gt;是对象存储时唯一命名的key(这个key方便在存储中快速找到相应的对象)。&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="id3"&gt;
&lt;h4&gt;2.1.2 代码位置&lt;/h4&gt;
&lt;p&gt;&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;$GOPATH/pkg/mod/k8s.io/client-go&amp;#64;v0.19.0/tools/cache/index.go&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="id4"&gt;
&lt;h4&gt;2.1.3 类图展示&lt;/h4&gt;
&lt;p&gt;从下图我们可以很容易的看到&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;Indexer&lt;/span&gt;&lt;/code&gt;与&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;cache&lt;/span&gt;&lt;/code&gt;、&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;Store&lt;/span&gt;&lt;/code&gt;及&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;ThreadSafeStore&lt;/span&gt;&lt;/code&gt;之间的调用关系。&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="https://gitee.com/double12gzh/wiki-pictures/raw/master/2020-10-16-custom-controller/indexers.png" /&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;div&gt;&lt;p&gt;上图如果长时间无法显示，请参考&lt;a class="reference external" href="https://gitee.com/double12gzh/wiki-pictures/raw/master/2020-10-16-custom-controller/indexers.png"&gt;这里&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Store: 是一个通用对象存储和处理接口。&lt;/p&gt;
&lt;div class="highlight-go notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="mi"&gt;26&lt;/span&gt; &lt;span class="c1"&gt;// Store is a generic object storage and processing interface.  A&lt;/span&gt;
&lt;span class="mi"&gt;27&lt;/span&gt; &lt;span class="c1"&gt;// Store holds a map from string keys to accumulators, and has&lt;/span&gt;
&lt;span class="mi"&gt;28&lt;/span&gt; &lt;span class="c1"&gt;// operations to add, update, and delete a given object to/from the&lt;/span&gt;
&lt;span class="mi"&gt;29&lt;/span&gt; &lt;span class="c1"&gt;// accumulator currently associated with a given key.  A Store also&lt;/span&gt;
&lt;span class="mi"&gt;30&lt;/span&gt; &lt;span class="c1"&gt;// knows how to extract the key from a given object, so many operations&lt;/span&gt;
&lt;span class="mi"&gt;31&lt;/span&gt; &lt;span class="c1"&gt;// are given only the object.&lt;/span&gt;
&lt;span class="mi"&gt;32&lt;/span&gt; &lt;span class="c1"&gt;//&lt;/span&gt;
&lt;span class="mi"&gt;33&lt;/span&gt; &lt;span class="c1"&gt;// In the simplest Store implementations each accumulator is simply&lt;/span&gt;
&lt;span class="mi"&gt;34&lt;/span&gt; &lt;span class="c1"&gt;// the last given object, or empty after Delete, and thus the Store&amp;#39;s&lt;/span&gt;
&lt;span class="mi"&gt;35&lt;/span&gt; &lt;span class="c1"&gt;// behavior is simple storage.&lt;/span&gt;
&lt;span class="mi"&gt;36&lt;/span&gt; &lt;span class="c1"&gt;//&lt;/span&gt;
&lt;span class="mi"&gt;37&lt;/span&gt; &lt;span class="c1"&gt;// Reflector knows how to watch a server and update a Store.  This&lt;/span&gt;
&lt;span class="mi"&gt;38&lt;/span&gt; &lt;span class="c1"&gt;// package provides a variety of implementations of Store.&lt;/span&gt;
&lt;span class="mi"&gt;39&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Store&lt;/span&gt; &lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="mi"&gt;40&lt;/span&gt;
&lt;span class="mi"&gt;41&lt;/span&gt;     &lt;span class="c1"&gt;// Add adds the given object to the accumulator associated with the given object&amp;#39;s key&lt;/span&gt;
&lt;span class="mi"&gt;42&lt;/span&gt;     &lt;span class="nx"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;obj&lt;/span&gt; &lt;span class="kd"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{})&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;
&lt;span class="mi"&gt;43&lt;/span&gt;
&lt;span class="mi"&gt;44&lt;/span&gt;     &lt;span class="c1"&gt;// Update updates the given object in the accumulator associated with the given object&amp;#39;s key&lt;/span&gt;
&lt;span class="mi"&gt;45&lt;/span&gt;     &lt;span class="nx"&gt;Update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;obj&lt;/span&gt; &lt;span class="kd"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{})&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;
&lt;span class="mi"&gt;46&lt;/span&gt;
&lt;span class="mi"&gt;47&lt;/span&gt;     &lt;span class="c1"&gt;// Delete deletes the given object from the accumulator associated with the given object&amp;#39;s key&lt;/span&gt;
&lt;span class="mi"&gt;48&lt;/span&gt;     &lt;span class="nx"&gt;Delete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;obj&lt;/span&gt; &lt;span class="kd"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{})&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;
&lt;span class="mi"&gt;49&lt;/span&gt;
&lt;span class="mi"&gt;50&lt;/span&gt;     &lt;span class="c1"&gt;// List returns a list of all the currently non-empty accumulators&lt;/span&gt;
&lt;span class="mi"&gt;51&lt;/span&gt;     &lt;span class="nx"&gt;List&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kd"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;
&lt;span class="mi"&gt;52&lt;/span&gt;
&lt;span class="mi"&gt;53&lt;/span&gt;     &lt;span class="c1"&gt;// ListKeys returns a list of all the keys currently associated with non-empty accumulators&lt;/span&gt;
&lt;span class="mi"&gt;54&lt;/span&gt;     &lt;span class="nx"&gt;ListKeys&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;
&lt;span class="mi"&gt;55&lt;/span&gt;
&lt;span class="mi"&gt;56&lt;/span&gt;     &lt;span class="c1"&gt;// Get returns the accumulator associated with the given object&amp;#39;s key&lt;/span&gt;
&lt;span class="mi"&gt;57&lt;/span&gt;     &lt;span class="nx"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;obj&lt;/span&gt; &lt;span class="kd"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{})&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="kd"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt; &lt;span class="nx"&gt;exists&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="mi"&gt;58&lt;/span&gt;
&lt;span class="mi"&gt;59&lt;/span&gt;     &lt;span class="c1"&gt;// GetByKey returns the accumulator associated with the given key&lt;/span&gt;
&lt;span class="mi"&gt;60&lt;/span&gt;     &lt;span class="nx"&gt;GetByKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="kd"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt; &lt;span class="nx"&gt;exists&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="mi"&gt;61&lt;/span&gt;
&lt;span class="mi"&gt;62&lt;/span&gt;     &lt;span class="c1"&gt;// Replace will delete the contents of the store, using instead the&lt;/span&gt;
&lt;span class="mi"&gt;63&lt;/span&gt;     &lt;span class="c1"&gt;// given list. Store takes ownership of the list, you should not reference&lt;/span&gt;
&lt;span class="mi"&gt;64&lt;/span&gt;     &lt;span class="c1"&gt;// it after calling this function.&lt;/span&gt;
&lt;span class="mi"&gt;65&lt;/span&gt;     &lt;span class="nx"&gt;Replace&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="kd"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;
&lt;span class="mi"&gt;66&lt;/span&gt;
&lt;span class="mi"&gt;67&lt;/span&gt;     &lt;span class="c1"&gt;// Resync is meaningless in the terms appearing here but has&lt;/span&gt;
&lt;span class="mi"&gt;68&lt;/span&gt;     &lt;span class="c1"&gt;// meaning in some implementations that have non-trivial&lt;/span&gt;
&lt;span class="mi"&gt;69&lt;/span&gt;     &lt;span class="c1"&gt;// additional behavior (e.g., DeltaFIFO).&lt;/span&gt;
&lt;span class="mi"&gt;70&lt;/span&gt;     &lt;span class="nx"&gt;Resync&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;
&lt;span class="mi"&gt;71&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Indexer: 扩展了多个索引的 &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;Store&lt;/span&gt;&lt;/code&gt;，并限制每个累加器只保存当前对象（删除后为空）。&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;ThreadSafeStore: 与&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;Indexer&lt;/span&gt;&lt;/code&gt;类似，是一个允许对存储后端进行并发索引访问的接口&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;cache: 根据 &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;ThreadSafeStore&lt;/span&gt;&lt;/code&gt; 和关联的 &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;KeyFunc&lt;/span&gt;&lt;/code&gt; 实现的 &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;Indexer&lt;/span&gt;&lt;/code&gt;。所有的对象都缓存在内存中，这不是一个外部可以调用的对象，在包的外部不能直接调用&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;cache&lt;/span&gt;&lt;/code&gt;。它的定义也比较简单， 如下：&lt;/p&gt;
&lt;div class="highlight-go notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="mi"&gt;131&lt;/span&gt; &lt;span class="c1"&gt;// 代码位置：client-go/tools/cache/store.go&lt;/span&gt;
&lt;span class="mi"&gt;132&lt;/span&gt; &lt;span class="c1"&gt;// `*cache` implements Indexer in terms of a ThreadSafeStore and an&lt;/span&gt;
&lt;span class="mi"&gt;133&lt;/span&gt; &lt;span class="c1"&gt;// associated KeyFunc.&lt;/span&gt;
&lt;span class="mi"&gt;134&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;cache&lt;/span&gt; &lt;span class="kd"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="mi"&gt;135&lt;/span&gt;     &lt;span class="c1"&gt;// cacheStorage bears the burden of thread safety for the cache&lt;/span&gt;
&lt;span class="mi"&gt;136&lt;/span&gt;     &lt;span class="nx"&gt;cacheStorage&lt;/span&gt; &lt;span class="nx"&gt;ThreadSafeStore&lt;/span&gt;
&lt;span class="mi"&gt;137&lt;/span&gt;     &lt;span class="c1"&gt;// keyFunc is used to make the key for objects stored in and retrieved from items, and&lt;/span&gt;
&lt;span class="mi"&gt;138&lt;/span&gt;     &lt;span class="c1"&gt;// should be deterministic.&lt;/span&gt;
&lt;span class="mi"&gt;139&lt;/span&gt;     &lt;span class="nx"&gt;keyFunc&lt;/span&gt; &lt;span class="nx"&gt;KeyFunc&lt;/span&gt;
&lt;span class="mi"&gt;140&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;blockquote&gt;
&lt;div&gt;&lt;p&gt;我们可以使用&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;NewStore&lt;/span&gt;&lt;/code&gt;或&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;NewIndexer&lt;/span&gt;&lt;/code&gt;来实例化一个&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;Store&lt;/span&gt;&lt;/code&gt;或&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;Indexer&lt;/span&gt;&lt;/code&gt;。&lt;/p&gt;
&lt;/div&gt;&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;threadSafeMap : 是 &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;ThreadSafeStore&lt;/span&gt;&lt;/code&gt;的实现，它实现了并发安全的存储(它是一个内存中的存储)，具备&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;CRUD&lt;/span&gt;&lt;/code&gt;等操作。它其中包含了三个比较重要的属性，见代码：&lt;/p&gt;
&lt;div class="highlight-go notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="mi"&gt;61&lt;/span&gt; &lt;span class="c1"&gt;// 代码位置：client-go/tools/cache/thread_safe_store.go&lt;/span&gt;
&lt;span class="mi"&gt;62&lt;/span&gt; &lt;span class="c1"&gt;// threadSafeMap implements ThreadSafeStore&lt;/span&gt;
&lt;span class="mi"&gt;63&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;threadSafeMap&lt;/span&gt; &lt;span class="kd"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="mi"&gt;64&lt;/span&gt;     &lt;span class="nx"&gt;lock&lt;/span&gt;  &lt;span class="nx"&gt;sync&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;RWMutex&lt;/span&gt;
&lt;span class="mi"&gt;65&lt;/span&gt;     &lt;span class="nx"&gt;items&lt;/span&gt; &lt;span class="kd"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="kd"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt; &lt;span class="c1"&gt;//用于保存数据&lt;/span&gt;
&lt;span class="mi"&gt;66&lt;/span&gt;
&lt;span class="mi"&gt;67&lt;/span&gt;     &lt;span class="c1"&gt;// indexers maps a name to an IndexFunc&lt;/span&gt;
&lt;span class="mi"&gt;68&lt;/span&gt;     &lt;span class="nx"&gt;indexers&lt;/span&gt; &lt;span class="nx"&gt;Indexers&lt;/span&gt;
&lt;span class="mi"&gt;69&lt;/span&gt;     &lt;span class="c1"&gt;// indices maps a name to an Index&lt;/span&gt;
&lt;span class="mi"&gt;70&lt;/span&gt;     &lt;span class="nx"&gt;indices&lt;/span&gt; &lt;span class="nx"&gt;Indices&lt;/span&gt;
&lt;span class="mi"&gt;71&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;对于&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;threadSafeMap&lt;/span&gt;&lt;/code&gt;中各种索引的关系，我们可以用下图来表示：&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="https://gitee.com/double12gzh/wiki-pictures/raw/master/2020-10-17-indexer-data-structure/indexer_indices_keys_mapping.png" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;threadSafeMap&lt;/span&gt;&lt;/code&gt;其实只会做两件事情：存储， 索引。存储即存储runtime.object到&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;items&lt;/span&gt;&lt;/code&gt;这个Map中； 索引即为&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;items&lt;/span&gt;&lt;/code&gt;这个Map建立三层索引：indices的Map类型的索引(如：namespace, nodeName等)；index Map的类型索引(如： namespace1, namespace2, …); runtime.object的索引。&lt;/p&gt;
&lt;p&gt;如果我们需要向&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;threadSafeMap&lt;/span&gt;&lt;/code&gt;中添加一个对象，只需要调用下以代码即可：&lt;/p&gt;
&lt;div class="highlight-go notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="mi"&gt;72&lt;/span&gt; &lt;span class="c1"&gt;// 代码位置：client-go/tools/cache/thread_safe_store.go&lt;/span&gt;
&lt;span class="mi"&gt;73&lt;/span&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;threadSafeMap&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;obj&lt;/span&gt; &lt;span class="kd"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="mi"&gt;74&lt;/span&gt;     &lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lock&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Lock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="mi"&gt;75&lt;/span&gt;     &lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lock&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Unlock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="mi"&gt;76&lt;/span&gt;     &lt;span class="nx"&gt;oldObject&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="mi"&gt;77&lt;/span&gt;     &lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;obj&lt;/span&gt;
&lt;span class="mi"&gt;78&lt;/span&gt;     &lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;updateIndices&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;oldObject&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="mi"&gt;79&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;blockquote&gt;
&lt;div&gt;&lt;p&gt;如果想了解更多的细节，请查看&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;updateIndices()&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;
&lt;/div&gt;&lt;/blockquote&gt;
&lt;p&gt;另外，从图中我们也可以看出，&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;Indexer&lt;/span&gt;&lt;/code&gt;实际上是对&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;threadSafeMap&lt;/span&gt;&lt;/code&gt;的封装，它继承了后者的所有方法，同时也实现了&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;IndexFunc&lt;/span&gt;&lt;/code&gt;。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="id5"&gt;
&lt;h3&gt;2.2 Indexer索引器实现&lt;/h3&gt;
&lt;p&gt;在kubernetes中使用的比较多的索引函数是&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;MetaNamespaceIndexFunc()&lt;/span&gt;&lt;/code&gt;（&lt;em&gt;代码位置: client-go/tools/cache/index.go&lt;/em&gt;）。&lt;/p&gt;
&lt;p&gt;&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;Indexer&lt;/span&gt;&lt;/code&gt;索引的实现是通过&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;index.ByIndex&lt;/span&gt;&lt;/code&gt;来完成的，&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;index.ByIndex&lt;/span&gt;&lt;/code&gt;的代码如下：&lt;/p&gt;
&lt;div class="highlight-go notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="mi"&gt;178&lt;/span&gt; &lt;span class="c1"&gt;// 代码位置：client-go/tools/cache/thread_safe_store.go&lt;/span&gt;
&lt;span class="mi"&gt;179&lt;/span&gt; &lt;span class="c1"&gt;// ByIndex returns a list of the items whose indexed values in the given index include the given indexed value&lt;/span&gt;
&lt;span class="mi"&gt;180&lt;/span&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;threadSafeMap&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;ByIndex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;indexName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;indexedValue&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="kd"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="mi"&gt;181&lt;/span&gt;     &lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lock&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;RLock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="mi"&gt;182&lt;/span&gt;     &lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lock&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;RUnlock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="mi"&gt;183&lt;/span&gt;
&lt;span class="mi"&gt;184&lt;/span&gt;     &lt;span class="nx"&gt;indexFunc&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;indexers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;indexName&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;  &lt;span class="c1"&gt;// 关键代码。获取索引器函数。&lt;/span&gt;
&lt;span class="mi"&gt;185&lt;/span&gt;     &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nx"&gt;indexFunc&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="mi"&gt;186&lt;/span&gt;         &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Index with name %s does not exist&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;indexName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="mi"&gt;187&lt;/span&gt;     &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="mi"&gt;188&lt;/span&gt;
&lt;span class="mi"&gt;189&lt;/span&gt;     &lt;span class="nx"&gt;index&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;indices&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;indexName&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;   &lt;span class="c1"&gt;// 关键代码。获取缓存器函数。&lt;/span&gt;
&lt;span class="mi"&gt;190&lt;/span&gt;
&lt;span class="mi"&gt;191&lt;/span&gt;     &lt;span class="nx"&gt;set&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;indexedValue&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;    &lt;span class="c1"&gt;// 关键代码。Index中的数据以Set类型存储在缓存中。&lt;/span&gt;
&lt;span class="mi"&gt;192&lt;/span&gt;     &lt;span class="nx"&gt;list&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="kd"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;set&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Len&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="mi"&gt;193&lt;/span&gt;     &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="k"&gt;range&lt;/span&gt; &lt;span class="nx"&gt;set&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="mi"&gt;194&lt;/span&gt;         &lt;span class="nx"&gt;list&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;list&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="mi"&gt;195&lt;/span&gt;     &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="mi"&gt;196&lt;/span&gt;
&lt;span class="mi"&gt;197&lt;/span&gt;     &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;list&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;nil&lt;/span&gt;
&lt;span class="mi"&gt;198&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;上述方法接收两个参数:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;indexName: 索引器的名字&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;indexedValue: 需要索引的key&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;此方法的基本思路如下：&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;根据索引器名字查找指定的索引器函数(&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;c.indexers[indexName]&lt;/span&gt;&lt;/code&gt;)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;根据索引器名字查找相应的缓存器函数(&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;c.indices[indexName]&lt;/span&gt;&lt;/code&gt;)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;根据索引key(即：&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;indexedValue&lt;/span&gt;&lt;/code&gt;)从缓存中进行数据查询，并返回查询结果&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
</content>
    <link href="double12gzhblogs.readthedocs.io/blogs/Kubernetes/2020-10-17-client-go%E7%B3%BB%E5%88%97%E4%B9%8B4---Indexer.html" rel="alternate"/>
    <published>2020-10-17T00:00:00+00:00</published>
  </entry>
  <entry>
    <id>double12gzhblogs.readthedocs.io/blogs/Kubernetes/2020-10-21-client-go%E7%B3%BB%E5%88%97%E4%B9%8B5---Informer.html</id>
    <title>client-go系列之5—Informer</title>
    <updated>2020-10-21T00:00:00+00:00</updated>
    <author>
      <name>JeffreyGuan</name>
    </author>
    <content type="html">&lt;div class="section" id="client-go5-informer"&gt;

&lt;p&gt;摘要：介绍client-go informer及controller.&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="https://gitee.com/double12gzh/wiki-pictures/raw/master/2020-10-13-client-go-kubeconfig/0.png" /&gt;&lt;/p&gt;
&lt;div class="section" id="id1"&gt;
&lt;h2&gt;1. 写在前面&lt;/h2&gt;
&lt;blockquote&gt;
&lt;div&gt;&lt;p&gt;个人主页: https://gzh.readthedocs.io&lt;/p&gt;
&lt;p&gt;关注容器技术、关注&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;Kubernetes&lt;/span&gt;&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;问题或建议，请公众号（&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;double12gzh&lt;/span&gt;&lt;/code&gt;）留言。&lt;/p&gt;
&lt;/div&gt;&lt;/blockquote&gt;
&lt;p&gt;依然秉承本系列的传统，在文章开始都会再次上一下下面这经经典的图(足见其重要性，哈哈哈)。&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="https://raw.githubusercontent.com/kubernetes/sample-controller/master/docs/images/client-go-controller-interaction.jpeg" /&gt;&lt;/p&gt;
&lt;p&gt;在&lt;a class="reference external" href="https://double12gzh.github.io/2020/10/11/client-go%E7%B3%BB%E5%88%97%E4%B9%8B1-client-go%E4%BB%A3%E7%A0%81%E7%BB%93%E6%9E%84%E8%AE%B2%E8%A7%A3/"&gt;client-go系列之1—client-go代码结构讲解&lt;/a&gt;中简单介绍一个client-go中的相关的模块(即图中上半部分)，其实，在client-go中不只是有前面提到的模块，还包括上图中下半部分的内容，即自定义控制器部分，如：&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;informer reference： 是一个&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;Informer&lt;/span&gt;&lt;/code&gt;的实例，主要用于处理与CRD（自定义资源）对象相关的。当我们开发自定义控制器（custom controller）时，需要这个控制器开创建相匹配的&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;Informer&lt;/span&gt;&lt;/code&gt;。&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;indexer reference：是一个&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;Indexer&lt;/span&gt;&lt;/code&gt;的实例，主要用于处理与CRD（自定义资源）对象相关的。当我们开发自定义控制器时，需要创建&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;Indexer&lt;/span&gt;&lt;/code&gt;的实例，这个实例主要作用是实现&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;存储+索引&lt;/span&gt;&lt;/code&gt;。&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;WorkQueue：工作者队列。前面我们提到过&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;Informer&lt;/span&gt;&lt;/code&gt;，它除了更新本地缓存之外，还要将数据同步给相应控制器，&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;WorkQueue&lt;/span&gt;&lt;/code&gt;就是为了数据同步的问题而产生的。当有资源被添加、修改或删除，&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;Informer&lt;/span&gt;&lt;/code&gt;/&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;SharedInformer&lt;/span&gt;&lt;/code&gt;就会将相应的事件加入到&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;WorkQueue&lt;/span&gt;&lt;/code&gt;中。其它所有的控制器需要排队对这个queue进行读取，如果某个控制器发现这个事件与自己相关，就执行相应的操作。如果操作失败，就会把刚才取出的事件再放回到&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;WorkQueue&lt;/span&gt;&lt;/code&gt;中，等再轮到自己执行时会再去重试这次失败的操作。如果操作成功，就将该事件从队列中删除。&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Resource Event Handler：这是一个回调函数，当一个&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;Informer&lt;/span&gt;&lt;/code&gt;/&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;SharedInformer&lt;/span&gt;&lt;/code&gt;要分发一个对象到控制器时，会调用此函数。例如：将对象的&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;Key&lt;/span&gt;&lt;/code&gt;放在&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;WorkQueue&lt;/span&gt;&lt;/code&gt;中并等待后续的处理。&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Process Item：用户自定义的处理&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;WorkQueue&lt;/span&gt;&lt;/code&gt;中的相应&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;Item&lt;/span&gt;&lt;/code&gt;的函数。 如，我们可以在这里面使用&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;Indexer&lt;/span&gt;&lt;/code&gt;或&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;Listing&lt;/span&gt; &lt;span class="pre"&gt;wrapper&lt;/span&gt;&lt;/code&gt;来根据相应的&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;Key&lt;/span&gt;&lt;/code&gt;检索对象。&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;div&gt;&lt;p&gt;Item的内容如下：&lt;/p&gt;
&lt;/div&gt;&lt;/blockquote&gt;
&lt;p&gt;&lt;img alt="" src="https://gitee.com/double12gzh/wiki-pictures/raw/master/2020-10-16-custom-controller/20201021-items.png" /&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;div&gt;&lt;p&gt;queue中的内容如下：&lt;/p&gt;
&lt;/div&gt;&lt;/blockquote&gt;
&lt;p&gt;&lt;img alt="" src="https://gitee.com/double12gzh/wiki-pictures/raw/master/2020-10-16-custom-controller/20201021-queue.png" /&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;div&gt;&lt;p&gt;在client-go的controller中给出了如何定义&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;Indexer&lt;/span&gt;&lt;/code&gt;和&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;Informer&lt;/span&gt;&lt;/code&gt;的方法，代码位置：client-go/tools/cache/controller.go，代码如下：&lt;/p&gt;
&lt;/div&gt;&lt;/blockquote&gt;
&lt;div class="highlight-go notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;  &lt;span class="mi"&gt;344&lt;/span&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nx"&gt;NewIndexerInformer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="mi"&gt;345&lt;/span&gt;     &lt;span class="nx"&gt;lw&lt;/span&gt; &lt;span class="nx"&gt;ListerWatcher&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;                 &lt;span class="c1"&gt;// 用于获取/监控需要Informer处理的资源&lt;/span&gt;
  &lt;span class="mi"&gt;346&lt;/span&gt;     &lt;span class="nx"&gt;objType&lt;/span&gt; &lt;span class="nx"&gt;runtime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;           &lt;span class="c1"&gt;// 订阅的对象类型&lt;/span&gt;
  &lt;span class="mi"&gt;347&lt;/span&gt;     &lt;span class="nx"&gt;resyncPeriod&lt;/span&gt; &lt;span class="nx"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Duration&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;       &lt;span class="c1"&gt;// 非0时，将会一直list我们所关心的对象； 0时，‘重新list’将会被推迟&lt;/span&gt;
  &lt;span class="mi"&gt;348&lt;/span&gt;     &lt;span class="nx"&gt;h&lt;/span&gt; &lt;span class="nx"&gt;ResourceEventHandler&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;           &lt;span class="c1"&gt;// 用于处理与resources相关的事件&lt;/span&gt;
  &lt;span class="mi"&gt;349&lt;/span&gt;     &lt;span class="nx"&gt;indexers&lt;/span&gt; &lt;span class="nx"&gt;Indexers&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="mi"&gt;350&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Indexer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Controller&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="mi"&gt;351&lt;/span&gt;     &lt;span class="c1"&gt;// This will hold the client state, as we know it.&lt;/span&gt;
  &lt;span class="mi"&gt;352&lt;/span&gt;     &lt;span class="nx"&gt;clientState&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nx"&gt;NewIndexer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;DeletionHandlingMetaNamespaceKeyFunc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;indexers&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="mi"&gt;353&lt;/span&gt;
  &lt;span class="mi"&gt;354&lt;/span&gt;     &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;clientState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;newInformer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;lw&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;objType&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;resyncPeriod&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;h&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;clientState&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="mi"&gt;355&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;blockquote&gt;
&lt;div&gt;&lt;p&gt;ResourceEventHandler的定义如下。其代码位置: client-go/tools/cache/controller.go。这里的&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;Evnet&lt;/span&gt;&lt;/code&gt;只是具有&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;通知&lt;/span&gt;&lt;/code&gt;的作用，因为，我们不应该对这里收到的对象进行任何修改。&lt;/p&gt;
&lt;/div&gt;&lt;/blockquote&gt;
&lt;div class="highlight-go notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="mi"&gt;212&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;ResourceEventHandler&lt;/span&gt; &lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="mi"&gt;213&lt;/span&gt;     &lt;span class="nx"&gt;OnAdd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;obj&lt;/span&gt; &lt;span class="kd"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{})&lt;/span&gt;                  &lt;span class="c1"&gt;// 当有新的对象被创建时，将会调用这个函数&lt;/span&gt;
&lt;span class="mi"&gt;214&lt;/span&gt;     &lt;span class="nx"&gt;OnUpdate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;oldObj&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;newObj&lt;/span&gt; &lt;span class="kd"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{})&lt;/span&gt;    &lt;span class="c1"&gt;// 当对象被修改时，将会调用这个函数。除此之外，当有`re-list`操作时，这个函数也会被再次调用&lt;/span&gt;
&lt;span class="mi"&gt;215&lt;/span&gt;     &lt;span class="nx"&gt;OnDelete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;obj&lt;/span&gt; &lt;span class="kd"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{})&lt;/span&gt;               &lt;span class="c1"&gt;// 当对象被删除时，将会调用这个函数。&lt;/span&gt;
&lt;span class="mi"&gt;216&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="informer"&gt;
&lt;h2&gt;2. Informer简介&lt;/h2&gt;
&lt;p&gt;一句话背景介绍：为了减少当多个控制器对k8s-api-server进行大量访问时对api-server造成压力。&lt;/p&gt;
&lt;div class="section" id="id2"&gt;
&lt;h3&gt;2.1 产生的背景&lt;/h3&gt;
&lt;p&gt;随着Controller越来越多，如果Controller直接访问k8s-apiserver，那么将会导致其压力过大，于是在这样的背景下就有了&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;Informer&lt;/span&gt;&lt;/code&gt;的概念。其发展到今天这个架构，大概可以总结出以下迭代思路：&lt;/p&gt;
&lt;p&gt;第一阶段，&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;Controller&lt;/span&gt;&lt;/code&gt;直接访问k8s-api-server。存在的问题：多个控制器大量访问k8s-apiserver时会对其造成巨大的压力。&lt;/p&gt;
&lt;p&gt;第二阶段，&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;Informer&lt;/span&gt;&lt;/code&gt;代替&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;Controller&lt;/span&gt;&lt;/code&gt;去访问k8s-apiserver。而&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;Controller&lt;/span&gt;&lt;/code&gt;的所有操作操作(如：查状态、对资源进行伸缩等）都和&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;Informer&lt;/span&gt;&lt;/code&gt;进行交互。但&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;Informer&lt;/span&gt;&lt;/code&gt;没有必要每次都去访问k8s-apiserver，它只要在需要的时候通过&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;ListAndWatch&lt;/span&gt;&lt;/code&gt;(即通过k8s List API获取所有资源的最新状态；通过Wath API去监听这些资源状态的变化)与k8s-apiserver交互即可。&lt;/p&gt;
&lt;blockquote&gt;
&lt;div&gt;&lt;p&gt;ListAndWatch的代码位置: client-go/tools/cache/reflector.go&lt;/p&gt;
&lt;p&gt;func (r *Reflector) ListAndWatch(stopCh &amp;lt;-chan struct{}) error{
…
}&lt;/p&gt;
&lt;/div&gt;&lt;/blockquote&gt;
&lt;p&gt;第三阶段， &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;Informer&lt;/span&gt;&lt;/code&gt;并没有直接访问k8s-api-server，而是通过一个叫&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;Reflector&lt;/span&gt;&lt;/code&gt;的对象进行api-server的访问。上面所说的 &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;ListAndWatch&lt;/span&gt;&lt;/code&gt; 事实上是由Reflector`实现的。&lt;/p&gt;
&lt;p&gt;第四阶段, 通过指定资源类型来&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;Watch&lt;/span&gt;&lt;/code&gt;特定资源。&lt;/p&gt;
&lt;div class="highlight-go notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;// 代码位置: client-go/tools/cache/listwatch.go&lt;/span&gt;
&lt;span class="mi"&gt;36&lt;/span&gt; &lt;span class="c1"&gt;// Watcher is any object that knows how to start a watch on a resource.&lt;/span&gt;
&lt;span class="mi"&gt;37&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Watcher&lt;/span&gt; &lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="mi"&gt;38&lt;/span&gt;     &lt;span class="c1"&gt;// Watch should begin a watch at the specified version.&lt;/span&gt;
&lt;span class="mi"&gt;39&lt;/span&gt;     &lt;span class="nx"&gt;Watch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;options&lt;/span&gt; &lt;span class="nx"&gt;metav1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ListOptions&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;watch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Interface&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="mi"&gt;40&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;第五阶段，定义&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;SharedInformer&lt;/span&gt;&lt;/code&gt;。如果&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;Controller&lt;/span&gt;&lt;/code&gt;与&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;Informer&lt;/span&gt;&lt;/code&gt;是一一对应的关系，那么k8s-api-server的压力也还是挺大的。但是类似于Pod这样的资源来说，&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;Deployment&lt;/span&gt;&lt;/code&gt;和&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;StatefulSet&lt;/span&gt;&lt;/code&gt;都能对它进行管理，当多个控制器同时想查Pod的状态时，实现上，只需要有一个&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;Informer&lt;/span&gt;&lt;/code&gt;就能满足需求了，即: &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;SharedInformered&lt;/span&gt;&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;第六阶段，解决多个不同的控制器排除与重试问题，引入&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;DeltaFIFOQueue&lt;/span&gt;&lt;/code&gt;。每当资源被修改时，&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;Reflector&lt;/span&gt;&lt;/code&gt;就会收到事件通知，并将对应的事件放入&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;DeltaFIFOQueue&lt;/span&gt;&lt;/code&gt;中。另外，&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;SharedInformer&lt;/span&gt;&lt;/code&gt;会不断从&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;DeltaFIFOQueue&lt;/span&gt;&lt;/code&gt;中读取事件并更新本地缓存(&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;ThreadSafeStore&lt;/span&gt;&lt;/code&gt;)的状态。&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="id3"&gt;
&lt;h3&gt;2.2 主要功能&lt;/h3&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;通过&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;List()&lt;/span&gt;&lt;/code&gt;/&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;Get()&lt;/span&gt;&lt;/code&gt;（代码位置：client-go/tools/cache/listwatch.go）获取资源对象&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;监听事件(&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;OnAdd&lt;/span&gt;&lt;/code&gt;, &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;OnUpdate&lt;/span&gt;&lt;/code&gt;, &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;OnDelete&lt;/span&gt;&lt;/code&gt;)，并触发回调(&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;ResourceEventHandler&lt;/span&gt;&lt;/code&gt;)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;支持二级缓存(&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;DeltaFIFOQueue&lt;/span&gt;&lt;/code&gt;和&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;ThreadSafeStore&lt;/span&gt;&lt;/code&gt;，前者用于存储&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;Watch&lt;/span&gt;&lt;/code&gt;返回的事件，后者是一个LocalStore，能够被&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;Lister&lt;/span&gt;&lt;/code&gt;的&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;List()&lt;/span&gt;&lt;/code&gt;和&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;Getter&lt;/span&gt;&lt;/code&gt;的&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;Get()&lt;/span&gt;&lt;/code&gt;方法访问)&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;div&gt;&lt;p&gt;需要注意的是，&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;Informer&lt;/span&gt;&lt;/code&gt;与&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;k8s-apiserver&lt;/span&gt;&lt;/code&gt;之间没有同步机制，但是&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;Informer&lt;/span&gt;&lt;/code&gt;内部的二级缓存之间是有同步机制的。&lt;/p&gt;
&lt;/div&gt;&lt;/blockquote&gt;
&lt;p&gt;上面提到的&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;List()&lt;/span&gt;&lt;/code&gt;/&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;Get()&lt;/span&gt;&lt;/code&gt;的定义位于：client-go/tools/cache/listwatch.go&lt;/p&gt;
&lt;div class="highlight-go notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="mi"&gt;29&lt;/span&gt; &lt;span class="c1"&gt;// Lister is any object that knows how to perform an initial list.&lt;/span&gt;
&lt;span class="mi"&gt;30&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Lister&lt;/span&gt; &lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="mi"&gt;31&lt;/span&gt;     &lt;span class="c1"&gt;// List should return a list type object; the Items field will be extracted, and the&lt;/span&gt;
&lt;span class="mi"&gt;32&lt;/span&gt;     &lt;span class="c1"&gt;// ResourceVersion field will be used to start the watch in the right place.&lt;/span&gt;
&lt;span class="mi"&gt;33&lt;/span&gt;     &lt;span class="nx"&gt;List&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;options&lt;/span&gt; &lt;span class="nx"&gt;metav1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ListOptions&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;runtime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="mi"&gt;34&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt; 
&lt;span class="mi"&gt;64&lt;/span&gt; &lt;span class="c1"&gt;// Getter interface knows how to access Get method from RESTClient.&lt;/span&gt;
&lt;span class="mi"&gt;65&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Getter&lt;/span&gt; &lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="mi"&gt;66&lt;/span&gt;     &lt;span class="nx"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;restclient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Request&lt;/span&gt;
&lt;span class="mi"&gt;67&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="id4"&gt;
&lt;h3&gt;2.3 主要模块&lt;/h3&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;Reflector&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;DeltaFIFO&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;ThreadSafeStore（LocalStore）&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Controller&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Lister&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Processor&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;div&gt;&lt;p&gt;需要注意的是：&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;这里提到的&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;Controller&lt;/span&gt;&lt;/code&gt;不是&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;Kubernetes&lt;/span&gt; &lt;span class="pre"&gt;Controller&lt;/span&gt;&lt;/code&gt;（前几篇文章中我们实际上已经提到过，再次重审一下，这两个Controller并没有任何联系）&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;Reflector&lt;/span&gt;&lt;/code&gt;主要用于监听与指定资源类型相关的事件&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;DeltaFIFO&lt;/span&gt;&lt;/code&gt;和&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;ThreadSafeStore（LocalStore）&lt;/span&gt;&lt;/code&gt;是&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;Informer&lt;/span&gt;&lt;/code&gt;的二级缓存&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;Lister&lt;/span&gt;&lt;/code&gt;主要是被调用&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;List/Get&lt;/span&gt;&lt;/code&gt;方法&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;Processor&lt;/span&gt;&lt;/code&gt;中记录了所有的回调函数（即 &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;ResourceEventHandler&lt;/span&gt;&lt;/code&gt;）的实例，并负责触发之&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;&lt;/blockquote&gt;
&lt;/div&gt;
&lt;div class="section" id="id5"&gt;
&lt;h3&gt;2.4 类图&lt;/h3&gt;
&lt;p&gt;&lt;img alt="" src="https://gitee.com/double12gzh/wiki-pictures/raw/master/2020-10-11-client-go/2020-shared-informer.png" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;a class="reference external" href="https://gitee.com/double12gzh/wiki-pictures/raw/master/2020-10-11-client-go/2020-shared-informer.png"&gt;出处&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="sharedinformer"&gt;
&lt;h3&gt;2.5 SharedInformer实现机制&lt;/h3&gt;
&lt;blockquote&gt;
&lt;div&gt;&lt;p&gt;当同一个资源(如：pdod)的&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;Informer&lt;/span&gt;&lt;/code&gt;被实例化多次后，将会产生多个&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;Reflector&lt;/span&gt;&lt;/code&gt;，如果这些&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;Reflector&lt;/span&gt;&lt;/code&gt;都去调用&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;ListAndWatch&lt;/span&gt;&lt;/code&gt;来获取资源时，将会对k8s-apiserver造成巨大的压力。&lt;/p&gt;
&lt;/div&gt;&lt;/blockquote&gt;
&lt;p&gt;&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;SharedInformer&lt;/span&gt;&lt;/code&gt;的意思是指：对于属于同一类型的资源来说，他们将会共享同一个&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;Informer&lt;/span&gt;&lt;/code&gt;和&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;Reflector&lt;/span&gt;&lt;/code&gt;，其实现代码如下：&lt;/p&gt;
&lt;div class="highlight-go notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;// 代码位置: client-go/informers/factory.go&lt;/span&gt;
&lt;span class="mi"&gt;55&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;sharedInformerFactory&lt;/span&gt; &lt;span class="kd"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="mi"&gt;56&lt;/span&gt;     &lt;span class="nx"&gt;client&lt;/span&gt;           &lt;span class="nx"&gt;kubernetes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Interface&lt;/span&gt;
&lt;span class="mi"&gt;57&lt;/span&gt;     &lt;span class="nx"&gt;namespace&lt;/span&gt;        &lt;span class="kt"&gt;string&lt;/span&gt;
&lt;span class="mi"&gt;58&lt;/span&gt;     &lt;span class="nx"&gt;tweakListOptions&lt;/span&gt; &lt;span class="nx"&gt;internalinterfaces&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;TweakListOptionsFunc&lt;/span&gt;
&lt;span class="mi"&gt;59&lt;/span&gt;     &lt;span class="nx"&gt;lock&lt;/span&gt;             &lt;span class="nx"&gt;sync&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Mutex&lt;/span&gt;
&lt;span class="mi"&gt;60&lt;/span&gt;     &lt;span class="nx"&gt;defaultResync&lt;/span&gt;    &lt;span class="nx"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Duration&lt;/span&gt;
&lt;span class="mi"&gt;61&lt;/span&gt;     &lt;span class="nx"&gt;customResync&lt;/span&gt;     &lt;span class="kd"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;reflect&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="nx"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Duration&lt;/span&gt;
&lt;span class="mi"&gt;62&lt;/span&gt;
&lt;span class="mi"&gt;63&lt;/span&gt;     &lt;span class="nx"&gt;informers&lt;/span&gt; &lt;span class="kd"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;reflect&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="nx"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;SharedIndexInformer&lt;/span&gt;     &lt;span class="c1"&gt;// sharedInformer的数据都存放在这个map中。&lt;/span&gt;
&lt;span class="mi"&gt;64&lt;/span&gt;     &lt;span class="c1"&gt;// startedInformers is used for tracking which informers have been started.&lt;/span&gt;
&lt;span class="mi"&gt;65&lt;/span&gt;     &lt;span class="c1"&gt;// This allows Start() to be called multiple times safely.&lt;/span&gt;
&lt;span class="mi"&gt;66&lt;/span&gt;     &lt;span class="nx"&gt;startedInformers&lt;/span&gt; &lt;span class="kd"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;reflect&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;
&lt;span class="mi"&gt;67&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="id6"&gt;
&lt;h3&gt;2.6 不同资源的Informer定义&lt;/h3&gt;
&lt;p&gt;对于不同的资源(如：pods, deployments, …)都有一个与之相对应的&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;xxxInformer&lt;/span&gt;&lt;/code&gt;存在，他们的位置为(以pod为例):&lt;/p&gt;
&lt;div class="highlight-go notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;// 代码位置：clent-go/informers/core/v1/pod.go&lt;/span&gt;
   &lt;span class="mi"&gt;35&lt;/span&gt; &lt;span class="c1"&gt;// PodInformer 提供了与pod相关的shared informer及lister进行交互的途径 &lt;/span&gt;
   &lt;span class="mi"&gt;36&lt;/span&gt; &lt;span class="c1"&gt;// 每个k8s resource都会有这样一个Informer，且Informer中都有以下两个方法：Informer(), Lister()&lt;/span&gt;
   &lt;span class="mi"&gt;37&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;PodInformer&lt;/span&gt; &lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="mi"&gt;38&lt;/span&gt;     &lt;span class="nx"&gt;Informer&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="nx"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;SharedIndexInformer&lt;/span&gt;
   &lt;span class="mi"&gt;39&lt;/span&gt;     &lt;span class="nx"&gt;Lister&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="nx"&gt;v1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PodLister&lt;/span&gt;
   &lt;span class="mi"&gt;40&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
   &lt;span class="mi"&gt;41&lt;/span&gt;
   &lt;span class="mi"&gt;42&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;podInformer&lt;/span&gt; &lt;span class="kd"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="mi"&gt;43&lt;/span&gt;     &lt;span class="nx"&gt;factory&lt;/span&gt;          &lt;span class="nx"&gt;internalinterfaces&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;SharedInformerFactory&lt;/span&gt;
   &lt;span class="mi"&gt;44&lt;/span&gt;     &lt;span class="nx"&gt;tweakListOptions&lt;/span&gt; &lt;span class="nx"&gt;internalinterfaces&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;TweakListOptionsFunc&lt;/span&gt;
   &lt;span class="mi"&gt;45&lt;/span&gt;     &lt;span class="nx"&gt;namespace&lt;/span&gt;        &lt;span class="kt"&gt;string&lt;/span&gt;
   &lt;span class="mi"&gt;46&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;调用不同资源的Informer的使用示例如下：&lt;/p&gt;
&lt;div class="highlight-go notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="nx"&gt;deployInformer&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;sharedInformer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
               &lt;span class="nx"&gt;apps&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;              &lt;span class="c1"&gt;// client-go/informers/apps&lt;/span&gt;
               &lt;span class="nx"&gt;V1&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;                &lt;span class="c1"&gt;// client-go/informers/apps/v1&lt;/span&gt;
               &lt;span class="nx"&gt;Deployments&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;       &lt;span class="c1"&gt;// client-go/informers/apps/v1/deployment.go&lt;/span&gt;
               &lt;span class="nx"&gt;Informer&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;           &lt;span class="c1"&gt;// client-go/informers/apps/v1/deployment.go: type DeploymentInformer interface{}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="controller"&gt;
&lt;h2&gt;3. Controller&lt;/h2&gt;
&lt;div class="section" id="id7"&gt;
&lt;h3&gt;3.1 Controller定义&lt;/h3&gt;
&lt;p&gt;代码位置: &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;client-go/tools/cache/controller.go&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;
&lt;div class="highlight-go notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="mi"&gt;96&lt;/span&gt; &lt;span class="c1"&gt;// 这是一个Base Controller, 是其它所有控制器的`基类`。在`SharedInformer`中将会被用到。&lt;/span&gt;
&lt;span class="mi"&gt;97&lt;/span&gt; &lt;span class="c1"&gt;// &lt;/span&gt;
&lt;span class="mi"&gt;98&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Controller&lt;/span&gt; &lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="mi"&gt;99&lt;/span&gt;      &lt;span class="c1"&gt;// Run 只做两件事情：&lt;/span&gt;
&lt;span class="mi"&gt;100&lt;/span&gt;     &lt;span class="c1"&gt;// 1. 构建并启动一个`Reflector`。把从`Config.ListerWatcher`中抛出的对象或通知发送到`Config.Queue`中，另外也可能会触发队列同步`Resync`&lt;/span&gt;
&lt;span class="mi"&gt;102&lt;/span&gt;     &lt;span class="c1"&gt;// 2. 不断的从queue中弹出item，并使用Config.ProcessFunc进行处理。&lt;/span&gt;
&lt;span class="mi"&gt;103&lt;/span&gt;     &lt;span class="c1"&gt;// &lt;/span&gt;
&lt;span class="mi"&gt;104&lt;/span&gt;     &lt;span class="c1"&gt;// 当channel `stopCh`被关闭时，上面两个操作会停止。&lt;/span&gt;
&lt;span class="mi"&gt;105&lt;/span&gt;     &lt;span class="nx"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;stopCh&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="kd"&gt;chan&lt;/span&gt; &lt;span class="kd"&gt;struct&lt;/span&gt;&lt;span class="p"&gt;{})&lt;/span&gt;
&lt;span class="mi"&gt;106&lt;/span&gt;
&lt;span class="mi"&gt;107&lt;/span&gt;     &lt;span class="c1"&gt;// HasSynced Config的队列是否已经同步过了&lt;/span&gt;
&lt;span class="mi"&gt;108&lt;/span&gt;     &lt;span class="nx"&gt;HasSynced&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt;
&lt;span class="mi"&gt;109&lt;/span&gt;
&lt;span class="mi"&gt;110&lt;/span&gt;     &lt;span class="c1"&gt;// LastSyncResourceVersion delegates to the Reflector when there&lt;/span&gt;
&lt;span class="mi"&gt;111&lt;/span&gt;     &lt;span class="c1"&gt;// is one, otherwise returns the empty string&lt;/span&gt;
&lt;span class="mi"&gt;112&lt;/span&gt;     &lt;span class="nx"&gt;LastSyncResourceVersion&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;
&lt;span class="mi"&gt;113&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;Controller&lt;/span&gt;&lt;/code&gt;的具体实现如下：&lt;/p&gt;
&lt;div class="highlight-go notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;   &lt;span class="mi"&gt;89&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;controller&lt;/span&gt; &lt;span class="kd"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="mi"&gt;90&lt;/span&gt;     &lt;span class="nx"&gt;config&lt;/span&gt;         &lt;span class="nx"&gt;Config&lt;/span&gt;
   &lt;span class="mi"&gt;91&lt;/span&gt;     &lt;span class="nx"&gt;reflector&lt;/span&gt;      &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;Reflector&lt;/span&gt;
   &lt;span class="mi"&gt;92&lt;/span&gt;     &lt;span class="nx"&gt;reflectorMutex&lt;/span&gt; &lt;span class="nx"&gt;sync&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;RWMutex&lt;/span&gt;
   &lt;span class="mi"&gt;93&lt;/span&gt;     &lt;span class="nx"&gt;clock&lt;/span&gt;          &lt;span class="nx"&gt;clock&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Clock&lt;/span&gt;
   &lt;span class="mi"&gt;94&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;从上面的实现中， 我们可以看到， 一个&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;Controller&lt;/span&gt;&lt;/code&gt;实际上是一个以&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;Config&lt;/span&gt;&lt;/code&gt;为参数，并将会被&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;Informer&lt;/span&gt;&lt;/code&gt;使用到的一个low-level的控制器。&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="id8"&gt;
&lt;h3&gt;3.2 Controller关键方法&lt;/h3&gt;
&lt;div class="highlight-go notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;// 代码位置: client-go/tools/cache/controller.go&lt;/span&gt;
&lt;span class="c1"&gt;// Run 开始处理items，当stopCh被关闭或stopCh收到某个值是将会停止执行。&lt;/span&gt;
&lt;span class="mi"&gt;127&lt;/span&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;controller&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;stopCh&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="kd"&gt;chan&lt;/span&gt; &lt;span class="kd"&gt;struct&lt;/span&gt;&lt;span class="p"&gt;{})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="mi"&gt;128&lt;/span&gt;     &lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="nx"&gt;utilruntime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;HandleCrash&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="mi"&gt;129&lt;/span&gt;     &lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="mi"&gt;130&lt;/span&gt;         &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="nx"&gt;stopCh&lt;/span&gt;
&lt;span class="mi"&gt;131&lt;/span&gt;         &lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Queue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="mi"&gt;132&lt;/span&gt;     &lt;span class="p"&gt;}()&lt;/span&gt;
&lt;span class="mi"&gt;133&lt;/span&gt;     &lt;span class="nx"&gt;r&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nx"&gt;NewReflector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;             &lt;span class="c1"&gt;// 创建一个Reflector， 用于ListAndWatch， 从而获取指定资源的当前状态&lt;/span&gt;
&lt;span class="mi"&gt;134&lt;/span&gt;         &lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ListerWatcher&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;    &lt;span class="c1"&gt;// List/Watch指定的资源对象&lt;/span&gt;
&lt;span class="mi"&gt;135&lt;/span&gt;         &lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ObjectType&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="mi"&gt;136&lt;/span&gt;         &lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Queue&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="mi"&gt;137&lt;/span&gt;         &lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;FullResyncPeriod&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="mi"&gt;138&lt;/span&gt;     &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="mi"&gt;139&lt;/span&gt;     &lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ShouldResync&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ShouldResync&lt;/span&gt;
&lt;span class="mi"&gt;140&lt;/span&gt;     &lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;WatchListPageSize&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;WatchListPageSize&lt;/span&gt;
&lt;span class="mi"&gt;141&lt;/span&gt;     &lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;clock&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;clock&lt;/span&gt;
&lt;span class="mi"&gt;142&lt;/span&gt;     &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;WatchErrorHandler&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="mi"&gt;143&lt;/span&gt;         &lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;watchErrorHandler&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;WatchErrorHandler&lt;/span&gt;
&lt;span class="mi"&gt;144&lt;/span&gt;     &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="mi"&gt;145&lt;/span&gt;
&lt;span class="mi"&gt;146&lt;/span&gt;     &lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;reflectorMutex&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Lock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="mi"&gt;147&lt;/span&gt;     &lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;reflector&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt;
&lt;span class="mi"&gt;148&lt;/span&gt;     &lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;reflectorMutex&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Unlock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="mi"&gt;149&lt;/span&gt;
&lt;span class="mi"&gt;150&lt;/span&gt;     &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;wg&lt;/span&gt; &lt;span class="nx"&gt;wait&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Group&lt;/span&gt;
&lt;span class="mi"&gt;151&lt;/span&gt;
&lt;span class="mi"&gt;152&lt;/span&gt;     &lt;span class="nx"&gt;wg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;StartWithChannel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;stopCh&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// r.Run中的最主要的方法就是执行Reflector的ListAndWatch()获取资源对象的值&lt;/span&gt;
&lt;span class="mi"&gt;153&lt;/span&gt;     &lt;span class="c1"&gt;// c.ProcessLoop(client-go/tools/cache/controller.go)会从queue中取出资源Delta并进行处理&lt;/span&gt;
&lt;span class="mi"&gt;154&lt;/span&gt;     &lt;span class="nx"&gt;wait&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Until&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;processLoop&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Second&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;stopCh&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="mi"&gt;155&lt;/span&gt;     &lt;span class="nx"&gt;wg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Wait&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="mi"&gt;156&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;blockquote&gt;
&lt;div&gt;&lt;p&gt;c.processLoop的实现如下：&lt;/p&gt;
&lt;/div&gt;&lt;/blockquote&gt;
&lt;div class="highlight-go notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="mi"&gt;181&lt;/span&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;controller&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;processLoop&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="mi"&gt;182&lt;/span&gt;     &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="mi"&gt;183&lt;/span&gt;         &lt;span class="nx"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Queue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Pop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;PopProcessFunc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Process&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="mi"&gt;184&lt;/span&gt;         &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="mi"&gt;185&lt;/span&gt;             &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nx"&gt;ErrFIFOClosed&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="mi"&gt;186&lt;/span&gt;                 &lt;span class="k"&gt;return&lt;/span&gt;
&lt;span class="mi"&gt;187&lt;/span&gt;             &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="mi"&gt;188&lt;/span&gt;             &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;RetryOnError&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="mi"&gt;189&lt;/span&gt;                 &lt;span class="c1"&gt;// This is the safe way to re-enqueue.&lt;/span&gt;
&lt;span class="mi"&gt;190&lt;/span&gt;                 &lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Queue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;AddIfNotPresent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;// Queue是一个DeltaFIFO&lt;/span&gt;
&lt;span class="mi"&gt;191&lt;/span&gt;             &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="mi"&gt;192&lt;/span&gt;         &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="mi"&gt;193&lt;/span&gt;     &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="mi"&gt;194&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="id9"&gt;
&lt;h3&gt;3.3 Controller小结&lt;/h3&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;有一个FIFO Queue的索引&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;有一个ListWatcher的索引&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;通过Pop从FIFO queue中消费资源对象(即: items)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;创建Reflector&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;提供一个proccessLoop处理资源对象以达到期望的状态&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;div&gt;&lt;p&gt;另外需要注意的是，不要把tools/cache/controller.go中的&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;Controller&lt;/span&gt;&lt;/code&gt;与&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;Cumstom&lt;/span&gt; &lt;span class="pre"&gt;Controller&lt;/span&gt;&lt;/code&gt;混为一谈，两者是完全不同的两个东西。&lt;/p&gt;
&lt;/div&gt;&lt;/blockquote&gt;
&lt;/div&gt;
&lt;div class="section" id="id10"&gt;
&lt;h3&gt;3.4 Controller示例&lt;/h3&gt;
&lt;p&gt;前面从“理论”方面对Controller/Informer做了简单的介绍，俗话说的好“纸上得来终觉浅，绝知此事要耕行”，建议学完上面的理论后，还是结合下面例子在实践中再体会一下。&lt;/p&gt;
&lt;p&gt;Controller的工作流程：
请参考: client-go/tools/cache/controller_test.go: Example()&lt;/p&gt;
&lt;hr class="docutils" /&gt;
&lt;p&gt;欢迎关注我的微信公众号：&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="https://gitee.com/double12gzh/wiki-pictures/raw/master/wechat_public.jpg" /&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
</content>
    <link href="double12gzhblogs.readthedocs.io/blogs/Kubernetes/2020-10-21-client-go%E7%B3%BB%E5%88%97%E4%B9%8B5---Informer.html" rel="alternate"/>
    <published>2020-10-21T00:00:00+00:00</published>
  </entry>
  <entry>
    <id>double12gzhblogs.readthedocs.io/blogs/Kubernetes/2020-11-03-kubernetes%E7%9A%84%E5%86%85%E9%83%A8%E6%9C%BA%E5%88%B6.html</id>
    <title>kubernetes内部机制</title>
    <updated>2020-11-08T00:00:00+00:00</updated>
    <author>
      <name>JeffreyGuan</name>
    </author>
    <content type="html">&lt;div class="section" id="kubernetes"&gt;

&lt;p&gt;摘要：kubernetes内部机制简介。&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="https://gitee.com/double12gzh/wiki-pictures/raw/master/2020-10-13-client-go-kubeconfig/0.png" /&gt;&lt;/p&gt;
&lt;div class="section" id="id1"&gt;
&lt;h2&gt;1. 写在前面&lt;/h2&gt;
&lt;blockquote&gt;
&lt;div&gt;&lt;p&gt;个人主页: https://gzh.readthedocs.io&lt;/p&gt;
&lt;p&gt;关注容器技术、关注&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;Kubernetes&lt;/span&gt;&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;问题或建议，请公众号（&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;double12gzh&lt;/span&gt;&lt;/code&gt;）留言。&lt;/p&gt;
&lt;/div&gt;&lt;/blockquote&gt;
&lt;p&gt;Kubernetes是一个容器编排引擎，设计用于在一组节点（通常称为集群）上托管容器化应用。使用系统建模方法，本系列旨在推进对Kubernetes及其基础概念的理解。
对于本篇博文，建议您需要提前对Kubernetes、Kubernetes对象和Kubernetes控制器有所理解。&lt;/p&gt;
&lt;p&gt;Kubernetes的特点是声明式容器编排引擎：在声明式系统中，用户向系统提供系统的期望状态的表示。然后，系统考虑当前状态和期望状态，确定从当前状态过渡到期望状态的需要执行哪些命令序列。
因此，”声明式系统 “这个术语激发了一个经过计算的、具有明确目的的协调工作的概念，其最终目的是以便从当前状态过渡到期望状态。&lt;/p&gt;
&lt;p&gt;然而，这不是Kubernetes的实际工作方式!&lt;/p&gt;
&lt;p&gt;Kubernetes并没有根据当前状态和期望状态确定一个经过计算、协调的命令执行序列。相反，Kubernetes仅根据当前状态迭代确定下一个要执行的命令。如果以及无法确定下一条命令时，Kubernetes就达到了稳定状态。&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="id2"&gt;
&lt;h2&gt;2. 状态转换机制&lt;/h2&gt;
&lt;p&gt;本段概述了Kubernetes的状态转换语义的抽象模型。接下来的段落概述了一个基于部署对象和部署控制器的具体示例。&lt;/p&gt;
&lt;p&gt;&lt;img alt="图1" src="https://gitee.com/double12gzh/wiki-pictures/raw/master/2020-11-03-k8s-mechanics/1.png" /&gt;&lt;/p&gt;
&lt;div class="highlight-als notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;fact {
    all k8s : K8s - last | let k8s&amp;#39; = k8s.next {
        some c : NextCommand[k8s] {
            command.source = k8s and command.target = k8s&amp;#39;
        }
    }
    NextCommand[k8s.last] = none
}
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;上述代码展示了Kubernetes的状态转换语义。给定下一个命令函数，系统将根据当前状态k8s确定下一个命令，将系统从当前状态k8s过渡到下一个状态k8s’。&lt;/p&gt;
&lt;p&gt;上述代码中使用到的&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;NextCommand()&lt;/span&gt;&lt;/code&gt;的实现逻辑如下：&lt;/p&gt;
&lt;div class="highlight-als notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;fun NextCommand(k8s : K8s) : set Command {
  DeploymentController.NextCommand[k8s] +
  ReplicaSetController.NextCommand[k8s] +
  ...
}
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;从概念上讲，&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;NextCommand&lt;/span&gt;&lt;/code&gt;函数是由每个Kubernetes控制器的&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;NextCommand&lt;/span&gt;&lt;/code&gt;函数的组成。&lt;/p&gt;
&lt;div class="highlight-als notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;pred Steady(k8s : K8s) { NextCommand[k8s] = none }

&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;状态序列以一个状态k8s.last结束，对于这个状态，&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;NextCommand&lt;/span&gt;&lt;/code&gt;函数没有产生下一条命令，这个状态通常称为稳态。&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="k8s"&gt;
&lt;h2&gt;3. k8s对象&lt;/h2&gt;
&lt;p&gt;Kubernetes对象存储是一组Kubernetes对象。Kubernetes对象是一些有不同规格的数据记录，称为&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;kind&lt;/span&gt;&lt;/code&gt;。&lt;/p&gt;
&lt;div class="highlight-yaml notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="nt"&gt;apiVersion&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="l l-Scalar l-Scalar-Plain"&gt;apps/v1&lt;/span&gt;
&lt;span class="nt"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="l l-Scalar l-Scalar-Plain"&gt;Deployment&lt;/span&gt;
&lt;span class="nt"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
  &lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="l l-Scalar l-Scalar-Plain"&gt;gzh-deployment&lt;/span&gt;
&lt;span class="nt"&gt;spec&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
  &lt;span class="nt"&gt;replicas&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="l l-Scalar l-Scalar-Plain"&gt;3&lt;/span&gt;
  &lt;span class="nt"&gt;template&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nt"&gt;spec&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="nt"&gt;containers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="p p-Indicator"&gt;-&lt;/span&gt; &lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="l l-Scalar l-Scalar-Plain"&gt;mydemo&lt;/span&gt;
        &lt;span class="nt"&gt;image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="l l-Scalar l-Scalar-Plain"&gt;busybox:latest&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;如上所示即为一种k8s对象。&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="id3"&gt;
&lt;h2&gt;4. k8s控制器&lt;/h2&gt;
&lt;p&gt;每个Kubernetes Controller都会为下一条命令产生输入，一个Controller被实现为一个连续的过程，它根据Kubernetes的当前状态产生后续的命令。&lt;/p&gt;
&lt;div class="highlight-tla notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;process Controller = &amp;quot;Deployment Controller&amp;quot;
begin
    ControlLoop:
      while TRUE do
        \* The Deployment Controller monitors Deployment Objects
        with d ∈ {d ∈ k8s: d.kind = &amp;quot;Deployment&amp;quot;} do
          \* 1. Enabling Condition
          if Cardinality({r \in k8s: r.kind = &amp;quot;ReplicaSet&amp;quot; ∧ match(d.spec.labelSelector, r.meta.labels)}) &amp;lt; 1 then
            \* Reconciling Command
            CREATE([kind |-&amp;gt; &amp;quot;ReplicaSet&amp;quot;, spec |-&amp;gt; [replicas |-&amp;gt; d.spec.replicas, template |-&amp;gt; d.spec.template]]);
          end if;
          \* 2. Enabling Condition
          if Cardinality({r \in k8s: r.kind = &amp;quot;ReplicaSet&amp;quot; ∧ match(d.spec.labelSelector, r.meta.labels)}) &amp;gt; 1 then
            \* Reconciling Command
            with r ∈ {r \in k8s: r.kind = &amp;quot;ReplicaSet&amp;quot; ∧ match(d.spec.labelSelector, r.meta.labels)} do
               DELETE(r);
            end with;
          end if;
        end with;
      end while;
end process;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;上述代码5说明了deployment控制器。控制器监控deployment对象，并对每个对象执行一组条件语句。&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;条件&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;如果匹配的ReplicaSet对象少于1个&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;命令
然后，deployment控制器将产生一个&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;创建&lt;/span&gt; &lt;span class="pre"&gt;ReplicaSet&lt;/span&gt; &lt;/code&gt;命令。&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;条件&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;如果有超过1个匹配的ReplicaSet对象。&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;命令
然后，deployment控制器将发出&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;删除&lt;/span&gt; &lt;span class="pre"&gt;ReplicaSet&lt;/span&gt; &lt;span class="pre"&gt;命令&lt;/span&gt;&lt;/code&gt;。&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;从Controller的角度来看，如果Controller的条件都没有启用，Kubernetes就处于稳定状态，也就是说，Controller不会产生任何命令。&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="id4"&gt;
&lt;h2&gt;5. 级联指令&lt;/h2&gt;
&lt;p&gt;控制器（可以）级联地相互启用:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;给定k8s的状态，如果Kubernetes控制器C被启用，C将执行一个过渡到k8s’的命令。&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;给定k8s’的状态，如果启用了Kubernetes控制器C’，C’将执行一个过渡到k8s’‘的命令。&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img alt="图2" src="https://gitee.com/double12gzh/wiki-pictures/raw/master/2020-11-03-k8s-mechanics/2.png" /&gt;&lt;/p&gt;
&lt;p&gt;图2显示了用户向API服务器提交deployment对象后产生的命令级联。&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="id5"&gt;
&lt;h2&gt;6. k8s是一个声明式系统吗？&lt;/h2&gt;
&lt;p&gt;&lt;img alt="图3" src="https://gitee.com/double12gzh/wiki-pictures/raw/master/2020-11-03-k8s-mechanics/3.png" /&gt;&lt;/p&gt;
&lt;div class="highlight-als notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;fact {
    all sys : Sys - last | let sys&amp;#39; = sys.next {
        some c : Command {
            command.source = sys and command.target = sys&amp;#39;
        }
    }
    Desired[sys.last]
}
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;上述代码定义了声明式系统的状态转换机制。给定一个期望状态谓词，系统将确定一个命令序列，使系统从当前状态k8s.first过渡到期望状态k8s.last。&lt;/p&gt;
&lt;p&gt;&lt;img alt="图4" src="https://gitee.com/double12gzh/wiki-pictures/raw/master/2020-11-03-k8s-mechanics/4.png" /&gt;&lt;/p&gt;
&lt;p&gt;如果我们不把Kubernetes对象解释为事实的记录，而是解释为意图的记录，那么我们就可以认同Kubernetes是一个声明式系统的概念。&lt;/p&gt;
&lt;div class="highlight-yaml notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="nt"&gt;apiVersion&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="l l-Scalar l-Scalar-Plain"&gt;apps/v1&lt;/span&gt;
&lt;span class="nt"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="l l-Scalar l-Scalar-Plain"&gt;Deployment&lt;/span&gt;
&lt;span class="nt"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
  &lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="l l-Scalar l-Scalar-Plain"&gt;gzh-deployment&lt;/span&gt;
&lt;span class="nt"&gt;spec&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
  &lt;span class="nt"&gt;replicas&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="l l-Scalar l-Scalar-Plain"&gt;3&lt;/span&gt;
  &lt;span class="nt"&gt;template&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nt"&gt;spec&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="nt"&gt;containers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="p p-Indicator"&gt;-&lt;/span&gt; &lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="l l-Scalar l-Scalar-Plain"&gt;mydemo&lt;/span&gt;
      &lt;span class="nt"&gt;image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="l l-Scalar l-Scalar-Plain"&gt;busybox:latest&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;例如，我们可以将代码中的deployment对象解释为存在一组3个副本对象的意图，因此对象的&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;.spec.container[0].image&lt;/span&gt;&lt;/code&gt;等于&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;busyBox:latest&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;然而，这一概念并非没有微妙之处：如果将一个对象解释为意图记录，则会出现多个选项。例如，Deployment Object 可以解释为：&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;应有一个 ReplicaSet 或&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;有一些pods&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;根据解释，当前状态可能与所需状态相匹配，也可能不相匹配:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;如果有ReplicaSet和可选的Pods或&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;如果有一个ReplicaSet，并且必须有一组Pods&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;与我们的解释无关&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;如果有ReplicaSet对象，K8s与部署对象的关系处于稳定状态（deployment控制器不会产生Commands）。&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;如果有一组pod对象，K8s与ReplicaSet对象的关系处于稳定状态（ReplicaSet控制器不会产生命令）。&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="section" id="id6"&gt;
&lt;h2&gt;7. 结论&lt;/h2&gt;
&lt;p&gt;Kubernetes可能被描述为一个声明式系统，而Kubernetes对象可能被描述为意向记录。
然而，当你推理Kubernetes和Kubernetes的行为时，你应该记住，Kubernetes不会做出协调的努力来过渡到所需的状态。
相反，Kubernetes会做出持续的、不协调的努力来过渡到稳定状态。&lt;/p&gt;
&lt;hr class="docutils" /&gt;
&lt;p&gt;欢迎关注我的微信公众号：&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="https://gitee.com/double12gzh/wiki-pictures/raw/master/wechat_public.jpg" /&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
</content>
    <link href="double12gzhblogs.readthedocs.io/blogs/Kubernetes/2020-11-03-kubernetes%E7%9A%84%E5%86%85%E9%83%A8%E6%9C%BA%E5%88%B6.html" rel="alternate"/>
    <published>2020-11-08T00:00:00+00:00</published>
  </entry>
</feed>
