<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Kubernetes Controller 如何管理資源?

          共 13598字,需瀏覽 28分鐘

           ·

          2021-12-29 09:59


          一、Introduction

          起因:工作上要重構(gòu)一個(gè)現(xiàn)有的組件管理工具,要求實(shí)現(xiàn)全生命周期管理,還有上下游解耦,我心里一想這不就是 k8s controller 嘛!所以決定在動(dòng)手前先學(xué)習(xí)一下 k8s 的先進(jìn)理念。

          此文就是通過對(duì)代碼的簡單分析,以及一些經(jīng)驗(yàn)總結(jié),來描述 k8s controller 管理資源的主要流程。

          二、Concepts

          resource: 資源,k8s 中定義的每一個(gè)實(shí)例都是一個(gè)資源,比如一個(gè) rs、一個(gè) deployment。資源有不同的 kind,比如 rs、deployment。資源間存在上下游關(guān)系。

          注意:下文中提到的所有“資源”,都是指 k8s 中抽象的資源聲明,而不是指 CPU、存儲(chǔ)等真實(shí)的物理資源。

          高度抽象 k8s 的話其實(shí)就三大件:

          • apiserver: 負(fù)責(zé)存儲(chǔ)資源,并且提供查詢、修改資源的接口
          • controller: 負(fù)責(zé)管理本級(jí)和下級(jí)資源。比如 deploymentController 就負(fù)責(zé)管理 deployment 資源 和下一級(jí)的 rs 資源。
          • kubelet: 安裝在 node 節(jié)點(diǎn)上,負(fù)責(zé)部署資源

          controller 和 kubelet 都只和 apiserver 通訊。controller 不斷監(jiān)聽本級(jí)資源,然后修改下級(jí)資源的聲明。kubelet 查詢當(dāng)前 node 所應(yīng)部署的資源,然后執(zhí)行清理和部署。

          1、術(shù)語

          • metadata: 每一個(gè)資源都有的元數(shù)據(jù),包括 label、owner、uid 等
          • UID: 每一個(gè)被創(chuàng)建(提交給 apiserver)的資源都有一個(gè)全局唯一的 UUID。
          • label: 每個(gè)資源都要定義的標(biāo)簽
          • selector: 父資源通過 labelSelector 查詢歸其管理的子資源。不允許指定空 selector(全匹配)。
          • owner: 子資源維護(hù)一個(gè) owner UID 的列表 OwnerReferences, 指向其父級(jí)資源。列表中第一個(gè)有效的指針會(huì)被視為生效的父資源。selector 實(shí)際上只是一個(gè) adoption 的機(jī)制, 真實(shí)起作用的父子級(jí)關(guān)系是靠 owner 來維持的, 而且 owner 優(yōu)先級(jí)高于 selector。
          • replicas: 副本數(shù),pod 數(shù)
          • 父/子資源的相關(guān):
            • orphan: 沒有 owner 的資源(需要被 adopt 或 GC)
            • adopt: 將 orphan 納入某個(gè)資源的管理(成為其 owner)
            • match: 父子資源的 label/selector 匹配
            • release: 子資源的 label 不再匹配父資源的 selector,將其釋放
          • RS 相關(guān):
            • saturated: 飽和,意指某個(gè)資源的 replicas 已符合要求
            • surge: rs 的 replicas 不能超過 spec.replicas + surge
            • proportion: 每輪 rolling 時(shí),rs 的變化量(小于 maxSurge)
            • fraction: scale 時(shí) rs 期望的變化量(可能大于 maxSurge)

          三、Controller

          • sample-controller@a40ea2c/controller.go
          • kubernetes@59c0523b/pkg/controller/deployment/deployment_controller.go
          • kubernetes@59c0523b/pkg/controller/controller_ref_manager.go

          控制器,負(fù)責(zé)管理自己所對(duì)應(yīng)的資源(resource),并創(chuàng)建下一級(jí)資源,拿 deployment 來說:

          1. 用戶創(chuàng)建 deployment 資源
          2. deploymentController 監(jiān)聽到 deployment 資源,然后創(chuàng)建 rs 資源
          3. rsController 監(jiān)聽到 rs 資源,然后創(chuàng)建 pod 資源
          4. 調(diào)度器(scheduler)監(jiān)聽到 pod 資源,將其與 node 資源建立關(guān)聯(lián)

          (node 資源是 kubelet 安裝后上報(bào)注冊(cè)的)

          理想中,每一層管理器只管理本級(jí)和子兩層資源。但因?yàn)槊恳粋€(gè)資源都是被上層創(chuàng)建的, 所以實(shí)際上每一層資源都對(duì)下層資源的定義有完全的了解,即有一個(gè)由下至上的強(qiáng)耦合關(guān)系。

          比如 A -> B -> C -> D 這樣的生成鏈,A 當(dāng)然是知道 D 資源的全部定義的, 所以從理論上說,A 是可以去獲取 D 的。但是需要注意的是,如果出現(xiàn)了跨級(jí)的操作,A 也只能只讀的獲取 D,而不要對(duì) D 有任何改動(dòng), 因?yàn)榭缂?jí)修改數(shù)據(jù)的話會(huì)干擾下游的控制器。

          k8s 中所有的控制器都在同一個(gè)進(jìn)程(controller-manager)中啟動(dòng), 然后以 goroutine 的形式啟動(dòng)各個(gè)不同的 controller。所有的 contorller 共享同一個(gè) informer,不過可以注冊(cè)不同的 filter 和 handler, 監(jiān)聽自己負(fù)責(zé)的資源的事件。

          (informer 是對(duì) apiserver 的封裝,是 controller 查詢、訂閱資源消息的組件,后文有介紹)

          注:如果是用戶自定義 controller(CRD)的話,需要以單獨(dú)進(jìn)程的形式啟動(dòng),需要自己另行實(shí)例化一套 informer, 不過相關(guān)代碼在 client-go 這一項(xiàng)目中都做了封裝,編寫起來并不會(huì)很復(fù)雜。

          控制器的核心代碼可以概括為:

          for?{
          ????for?{
          ????????//?從?informer?中取出訂閱的資源消息
          ????????key,?empty?:=?queue.Get()
          ????????if?empty?{
          ????????????break
          ????????}

          ????????defer?queue.Done(key)

          ????????//?處理這一消息:更新子資源的聲明,使其匹配父資源的要求。
          ????????//?所有的 controller 中,這一函數(shù)都被命名為?`syncHandler`。
          ????????syncHandler(key)
          ????}

          ????//?消息隊(duì)列被消費(fèi)殆盡,等待下一輪運(yùn)行
          ????time.sleep(time.Second)
          }
          1. 通過 informer(indexer)監(jiān)聽資源事件,事件的格式是字符串 /
          2. 控制器通過 namespace 和 name 去查詢自己負(fù)責(zé)的資源和下級(jí)資源
          3. 比對(duì)當(dāng)前資源聲明的狀態(tài)和下級(jí)資源可用的狀態(tài)是否匹配,并通過增刪改讓下級(jí)資源匹配上級(jí)聲明。比如 deployments 控制器就查詢 deployment 資源和 rs 資源,并檢驗(yàn)其中的 replicas 副本數(shù)是否匹配。

          controller 內(nèi)包含幾個(gè)核心屬性/方法:

          • informer: sharedIndexer,用于獲取資源的消息,支持注冊(cè) Add/Update/Delete 事件觸發(fā),或者調(diào)用 lister 遍歷。
          • clientset: apiserver 的客戶端,用來對(duì)資源進(jìn)行增刪改。
          • syncHandler: 執(zhí)行核心邏輯代碼(更新子資源的聲明,使其匹配父資源的要求)。

          1、syncHandler

          syncHandler 像是一個(gè)約定,所有的 controller 內(nèi)執(zhí)行核心邏輯的函數(shù)都叫這個(gè)名字。該函數(shù)負(fù)責(zé)處理收到的資源消息,比如更新子資源的聲明,使其匹配父資源的要求。

          以 deploymentController 為例,當(dāng)收到一個(gè)事件消息,syncHandler 被調(diào)用后:

          注:

          • de: 觸發(fā)事件的某個(gè) deployment 資源
          • dc: deploymentController 控制器自己
          • rs: replicaset,deployment 對(duì)應(yīng)的 replicaset 子資源

          注:事件是一個(gè)字符串,形如 namespace/name,代表觸發(fā)事件的資源的名稱以及所在的 namespace。因?yàn)槭录皇莻€(gè)名字,所以 syncHandler 需要自己去把當(dāng)前觸發(fā)的資源及其子資源查詢出來。這里面涉及很多查詢和遍歷,不過這些查詢都不會(huì)真實(shí)的調(diào)用 apiserver,而是在 informer 的內(nèi)存存儲(chǔ)里完成的。

          graph TD

          A1[將 key 解析為 namespace 和 name] --> A2[查詢 de]
          A2 --> A3[查詢關(guān)聯(lián)子資源 rs]
          A3 --> A31{de 是否 paused}
          A31 --> |yes| A32[調(diào)用 dc.sync 部署 rs]
          A31 --> |no| A4{是否設(shè)置了 rollback}
          A4 --> |yes| A41[按照 annotation 設(shè)置執(zhí)行 rollback]
          A4 --> |no| A5[rs 是否匹配 de 聲明]
          A5 --> |no| A32
          A5 --> |yes| A6{de.spec.strategy.type}
          A6 --> |recreate| A61[dc.rolloutRecreate]
          A6 --> |rolling| A62[dc.rolloutRolling]

          查詢關(guān)聯(lián)子資源

          • kubernetes@59c0523b/pkg/controller/deployment/deployment_controller.go:getReplicaSetsForDeployment

          k8s 中,資源間可以有上下級(jí)(父子)關(guān)系。

          理論上 每一個(gè) controller 都負(fù)責(zé)創(chuàng)建當(dāng)前資源和子資源,父資源通過 labelSelector 查詢應(yīng)該匹配的子資源。

          一個(gè) deployment 的定義:

          apiVersion:?apps/v1
          kind:?Deployment
          metadata:
          ??name:?nginx-deployment
          ??labels:
          ????app:?nginx
          spec:
          ??replicas:?3
          ??selector:
          ????matchLabels:
          ??????app:?nginx
          ??template:
          ????metadata:
          ??????labels:
          ????????app:?nginx
          ????spec:
          ??????containers:
          ??????-?name:?nginx
          ????????image:?nginx:1.14.2
          ????????ports:
          ????????-?containerPort:?80

          上文中講到 syncHandler 的時(shí)候,提到需要“查詢關(guān)聯(lián)子資源”。其實(shí)這一步驟很復(fù)雜,不僅僅是查詢,還包含對(duì)現(xiàn)有子資源進(jìn)行同步(修改)的操作。簡而言之,這一步驟實(shí)際上做的是通過對(duì) owner、label 的比對(duì),確認(rèn)并更新當(dāng)前真實(shí)的父子資源關(guān)系。

          對(duì)用戶呈現(xiàn)的資源關(guān)聯(lián)是依靠 label/selector。但實(shí)際上 k8s 內(nèi)部使用的是 owner 指針。(owner 指針是資源 metadata 內(nèi)用來標(biāo)記其父資源的 OwnerReferences)。

          查詢匹配子資源的方法是:

          1. 遍歷 namespace 內(nèi)所有對(duì)應(yīng)類型的子資源 (比如 deployment controller 就會(huì)遍歷所有的 rs)
          2. 匹配校驗(yàn) owner 和 label

          (父是當(dāng)前操作的資源,子是查詢出的子資源)

          還是用 deployment 舉例,比如此時(shí)收到了一個(gè) deployment 事件,需要查詢出該 de 匹配的所有 rs:

          graph LR

          A(遍歷 namespace 內(nèi)所有 rs) --> A1{子.owner == nil}
          A1 --> |false| A2{子.owner == 父.uid}
          A2 --> |false| A21[skip]
          A2 --> |true| A3{labels matched}
          A3 --> |true| A5
          A3 --> |false| A31[release]
          A1 --> |true| A4{labels matched}
          A4 --> |false| A21
          A4 --> |true| A41[adopt]
          A41 --> A5[標(biāo)記為父子]

          如上圖所示,其實(shí)只有兩個(gè) case 下,rs 會(huì)被視為是 de 的子資源:

          1. rs owner 指向 de,且 labels 匹配
          2. rs owner 為空,且 labels 匹配

          注意:如果 rs owner 指向了其他父資源,即使 label 匹配,也不會(huì)被視為當(dāng)前 de 的子資源

          dc.sync

          • kubernetes@59c0523b/pkg/controller/deployment/sync.go:sync

          這是 deployment controller 中執(zhí)行“檢查和子資源,令其匹配父資源聲明”的一步。準(zhǔn)確的說:

          1. dc.sync: 檢查子資源是否符合父資源聲明
          2. dc.scale: 操作更新子資源,使其符合父資源聲明
          graph TD

          A1[查詢 de 下所有舊的 rs] --> A2{當(dāng)前 rs 是否符合 de}
          A2 --> |no| A21[newRS = nil]
          A2 --> |yes| A22[NewRS = 當(dāng)前 rs]
          A22 --> A23[將 de 的 metadata 拷貝給 newRS]
          A23 --> A231[newRS.revision=maxOldRevision+1]
          A231 --> A3[調(diào)用 dc.scale]
          A21 --> A33
          A3 --> A31{是否有 active/latest rs}
          A31 --> |yes| A311[dc.scaleReplicaSet 擴(kuò)縮容]
          A31 --> |no| A32{newRS 是否已飽和}
          A32 --> |yes|A321[把所有 oldRS 清零]
          A32 --> |no|A33{de 是否允許 rolling}
          A33 --> |no|A331[return]
          A33 --> |yes|A34[執(zhí)行滾動(dòng)更新]

          滾動(dòng)更新的流程為:

          if deploymentutil.IsRollingUpdate(deployment) {...} 內(nèi)的大量代碼,實(shí)際做的事情就是按照 deployment 的要求更新 rs 的 replicas 數(shù)。不過每次變更都涉及到對(duì) rs 和 deployment 的 maxSurge 的檢查,所以代碼較為復(fù)雜。)

          1. 計(jì)算所有 RS replicas 總和 allRSsReplicas
          2. 計(jì)算滾動(dòng)升級(jí)過程中最多允許出現(xiàn)的副本數(shù) allowedSizeallowedSize = de.Spec.Replicas + maxSurge
          3. deploymentReplicasToAdd = allowedSize - allRSsReplicas
          4. 遍歷所有當(dāng)前 rs,計(jì)算每一個(gè) rs 的 replicas 變化量(proportion), 計(jì)算的過程中需要做多次檢查,不能溢出 rs 和 deployment 的 maxSurge。
          5. 更新所有 rs 的 replicas,然后調(diào)用 dc.scaleReplicaSet 提交更改。

          四、Object

          ObjectMeta 定義了 k8s 中資源對(duì)象的標(biāo)準(zhǔn)方法。

          雖然 resource 定義里是通過 labelSelector 建立從上到下的關(guān)聯(lián), 但其實(shí)內(nèi)部實(shí)現(xiàn)的引用鏈?zhǔn)菑南碌缴系摹C恳粋€(gè)資源都會(huì)保存一個(gè) Owner UID 的 slice。

          每個(gè)資源的 metadata 中都有一個(gè) ownerReferences 列表,保存了其父資源(遍歷時(shí)遇到的第一個(gè)有效的資源會(huì)被認(rèn)為是其父資源)。

          type?ObjectMeta?struct?{
          ????OwnerReferences?[]OwnerReference?`json:"ownerReferences,omitempty"?patchStrategy:"merge"?patchMergeKey:"uid"?protobuf:"bytes,13,rep,name=ownerReferences"`
          }

          判斷 owner 靠的是比對(duì)資源的 UID

          func?IsControlledBy(obj?Object,?owner?Object)?bool?{
          ?ref?:=?GetControllerOfNoCopy(obj)
          ?if?ref?==?nil?{
          ??return?false
          ?}

          ????//?猜測:UID 是任何資源在 apiserver 注冊(cè)的時(shí)候,由 k8s 生成的 uuid
          ?return?ref.UID?==?owner.GetUID()
          }

          五、Informer

          Informer 也經(jīng)歷了兩代演進(jìn),從最早各管各的 Informer,到后來統(tǒng)一監(jiān)聽,各自 filter 的 sharedInformer。

          所有的 controller 都在一個(gè) controller-manager 進(jìn)程內(nèi),所以完全可以共享同一個(gè) informer, 不同的 controller 注冊(cè)不同的 filter(kind、labelSelector),來訂閱自己需要的消息。

          簡而言之,現(xiàn)在的 sharedIndexer,就是一個(gè)統(tǒng)一的消息訂閱器,而且內(nèi)部還維護(hù)了一個(gè)資源存儲(chǔ),對(duì)外提供可過濾的消息分發(fā)和資源查詢功能。

          sharedIndexer 和 sharedInformer 的區(qū)別就是多了個(gè) threadsafe 的 map 存儲(chǔ),用來存 shared resource object。

          現(xiàn)在的 informer 中由幾個(gè)主要的組件構(gòu)成:

          • reflecter:查詢器,負(fù)責(zé)從 apiserver 定期輪詢資源,更新 informer 的 store。
          • store: informer 內(nèi)部對(duì)資源的存儲(chǔ),用來提供 lister 遍歷等查詢操作。
          • queue:支持 controller 的事件訂閱。

          各個(gè) controller 的訂閱和查詢絕大部分都在 sharedIndexer 的內(nèi)存內(nèi)完成,提高資源利用率和效率。

          一般 controller 的消息來源就通過兩種方式:

          1. lister: controller 注冊(cè)監(jiān)聽特定類型的資源事件,事件格式是字符串,/
          2. handler: controller 通過 informer 的 AddEventHandler 方法注冊(cè) Add/Update/Delete 事件的處理函數(shù)。

          這里有個(gè)值得注意的地方是,資源事件的格式是字符串,形如 /,這其中沒有包含版本信息。

          那么某個(gè)版本的 controller 拿到這個(gè)信息后,并不知道查詢出來的資源是否匹配自己的版本,也許會(huì)查出一個(gè)很舊版本的資源。

          所以 controller 對(duì)于資源必須是向后兼容的,新版本的 controller 必須要能夠處理舊版資源。這樣的話,只需要保證運(yùn)行的是最新版的 controller 就行了。

          1、Queue

          controller 內(nèi)有大量的隊(duì)列,最重要的就是注冊(cè)到 informer 的三個(gè) add/update/delete 隊(duì)列。

          RateLimitingQueue

          實(shí)際使用的是隊(duì)列類型是 RateLimitingQueue,繼承于 Queue。

          Queue

          type?Interface?interface?{
          ????//?Add?增加任務(wù),可能是增加新任務(wù),可能是處理失敗了重新放入
          ????//
          ????//?調(diào)用 Add 時(shí),t 直接插入 dirty。然后會(huì)判斷一下 processing,
          ????//???是否存在于?processing???返回?:?放入?queue
          ????Add(item?interface{})
          ????Len()?int
          ????Get()?(item?interface{},?shutdown?bool)
          ????Done(item?interface{})
          ????ShutDown()
          ????ShuttingDown()?bool
          }


          type?Type?struct?{
          ????//?queue?所有未被處理的任務(wù)
          ????queue?[]t

          ????//?dirty?所有待處理的任務(wù)
          ????//
          ????//?從定義上看和 queue 有點(diǎn)相似,可以理解為 queue 的緩沖區(qū)。
          ????//?比如調(diào)用?Add?時(shí),如果?t?存在于?processing,就只會(huì)插入?dirty,不會(huì)插入?queue,
          ????//?這種情況表明外部程序處理失敗了,所以再次插入了 t。
          ????dirty?set

          ????//?processing?正在被處理的任務(wù)
          ????//
          ????//?一個(gè)正在被處理的 t 應(yīng)該從 queue 移除,然后添加到 processing。
          ????//
          ????//?如果 t 處理失敗需要重新處理,那么這個(gè) t 會(huì)被再次放入 dirty。
          ????//?所以調(diào)用?Done?從?processing?移除?t?的時(shí)候需要同步檢查一下?dirty,
          ????//?如果 t 存在于 dirty,則將其再次放入 queue。
          ????processing?set

          ????cond?*sync.Cond

          ????shuttingDown?bool

          ????metrics?queueMetrics

          ????unfinishedWorkUpdatePeriod?time.Duration
          ????clock??????????????????????clock.Clock
          }

          隊(duì)列傳遞的資源事件是以字符串來表示的,格式形如 namespace/name

          正因?yàn)橘Y源是字符串來表示,這導(dǎo)致了很多問題。其中對(duì)于隊(duì)列的一個(gè)問題就是:沒法為事件設(shè)置狀態(tài),標(biāo)記其是否已完成。為了實(shí)現(xiàn)這個(gè)狀態(tài),queue 中通過 queue、dirty、processing 三個(gè)集合來表示。具體實(shí)現(xiàn)可以參考上面的注釋和代碼。

          另一個(gè)問題就是資源中沒有包含版本信息。

          那么某個(gè)版本的 controller 拿到這個(gè)信息后,并不知道查詢出來的資源是否匹配自己的版本,也許會(huì)查出一個(gè)很舊版本的資源。

          所以 controller 對(duì)于資源必須是向后兼容的,新版本的 controller 必須要能夠處理舊版資源。這樣的話,只需要保證運(yùn)行的是最新版的 controller 就行了。

          六、GC

          • Garbage Collection[2]
          • Using Finalizers to Control Deletion[3]
          • kubernetes@59c0523b/pkg/controller/garbagecollector/garbagecollector.go

          1、Concepts

          我看到 GC 的第一印象是一個(gè)像語言 runtime 里的回收資源的自動(dòng)垃圾收集器。但其實(shí) k8s 里的 GC 的工作相對(duì)比較簡單,更像是只是一個(gè)被動(dòng)的函數(shù)調(diào)用,當(dāng)用戶試圖刪除一個(gè)資源的時(shí)候, 就會(huì)把這個(gè)資源提交給 GC,然后 GC 執(zhí)行一系列既定的刪除流程,一般來說包括:

          1. 刪除子資源
          2. 執(zhí)行刪除前清理工作(finalizer)
          3. 刪除資源

          k8s 的資源間存在上下游依賴,當(dāng)你刪除一個(gè)上游資源時(shí),其下游資源也需要被刪除,這被稱為級(jí)聯(lián)刪除 cascading deletion

          刪除一個(gè)資源有三種策略(propagationPolicy/DeletionPropagation):

          • Foreground(default): Children are deleted before the parent (post-order)
          • Background: Parent is deleted before the children (pre-order)
          • Orphan: 忽略 owner references

          可以在運(yùn)行 kubectl delete --cascade=??? 的時(shí)候指定刪除的策略,默認(rèn)為 foreground

          2、Deletion

          k8s 中,資源的 metadata 中有幾個(gè)對(duì)刪除比較重要的屬性:

          • ownerRerences: 指向父資源的 UID
          • deletionTimestamp: 如果不為空,表明該資源正在被刪除中
          • finalizers: 一個(gè)字符串?dāng)?shù)組,列舉刪除前必須執(zhí)行的操作
          • blockOwnerDeletion: 布爾,當(dāng)前資源是否會(huì)阻塞父資源的刪除流程

          每一個(gè)資源都有 metadata.finalizers,這是一個(gè) []string, 內(nèi)含一些預(yù)定義的字符串,表明了在刪除資源前必須要做的操作。每執(zhí)行完一個(gè)操作,就從 finalizers 中移除這個(gè)字符串。

          無論是什么刪除策略,都需要先把所有的 finalizer 逐一執(zhí)行完,每完成一個(gè),就從 finalizers 中移除一個(gè)。在 finalizers 為空后,才能正式的刪除資源。

          foreground、orphan 刪除就是通過 finalizer 來實(shí)現(xiàn)的。

          const?(
          ????FinalizerOrphanDependents?=?"orphan"
          ????FinalizerDeleteDependents?=?"foregroundDeletion"
          )

          注:有一種讓資源永不刪除的黑魔法,就是為資源注入一個(gè)不存在的 finalizer。因?yàn)?GC 無法找到該 finalizer 匹配的函數(shù)來執(zhí)行,就導(dǎo)致這個(gè) finalizer 始終無法被移除, 而 finalizers 為空清空的資源是不允許被刪除的。

          3、Foreground cascading deletion

          1. 設(shè)置資源的 deletionTimestamp,表明該資源的狀態(tài)為正在刪除中("deletion in progress")。
          2. 設(shè)置資源的 metadata.finalizers"foregroundDeletion"
          3. 刪除所有 ownerReference.blockOwnerDeletion=true 的子資源
          4. 刪除當(dāng)前資源

          每一個(gè)子資源的 owner 列表的元素里,都有一個(gè)屬性 ownerReference.blockOwnerDeletion,這是一個(gè) bool, 表明當(dāng)前資源是否會(huì)阻塞父資源的刪除流程。刪除父資源前,應(yīng)該把所有標(biāo)記為阻塞的子資源都刪光。

          在當(dāng)前資源被刪除以前,該資源都通過 apiserver 持續(xù)可見。

          4、Orphan deletion

          觸發(fā) FinalizerOrphanDependents,將所有子資源的 owner 清空,也就是令其成為 orphan。然后再刪除當(dāng)前資源。

          5、Background cascading deletion

          立刻刪除當(dāng)前資源,然后在后臺(tái)任務(wù)中刪除子資源。

          graph LR

          A1{是否有 finalizers} --> |Yes: pop, execute| A1
          A1 --> |No| A2[刪除自己]
          A2 --> A3{父資源是否在等待刪除}
          A3 --> |No| A4[刪除所有子資源]
          A3 --> |Yes| A31[在刪除隊(duì)列里提交父資源]
          A31 --> A4

          foreground 和 orphan 刪除策略是通過 finalizer 實(shí)現(xiàn)的 因?yàn)檫@兩個(gè)策略有一些刪除前必須要做的事情:

          • foreground finalizer: 將所有的子資源放入刪除事件隊(duì)列
          • orphan finalizer: 將所有的子資源的 owner 設(shè)為空

          而 background 則就是走標(biāo)準(zhǔn)刪除流程:刪自己 -> 刪依賴。

          這個(gè)流程里有一些很有趣(繞)的設(shè)計(jì)。比如 foreground 刪除,finalizer 里把所有的子資源都放入了刪除隊(duì)列, 然后下一步在刪除當(dāng)前資源的時(shí)候,會(huì)發(fā)現(xiàn)子資源依然存在,導(dǎo)致當(dāng)前資源無法刪除。實(shí)際上真正刪除當(dāng)前資源(父資源),實(shí)在刪除最后一個(gè)子資源的時(shí)候,每次都會(huì)去檢查下父資源的狀態(tài)是否是刪除中, 如果是,就把父資源放入刪除隊(duì)列,此時(shí),父資源才會(huì)被真正刪除。

          6、Owner References

          每個(gè)資源的 metadata 中都有一個(gè) ownerReferences 列表,保存了其父資源(遍歷時(shí)遇到的第一個(gè)有效的資源會(huì)被認(rèn)為是其父資源)。

          owner 決定了資源會(huì)如何被刪除。刪除子資源不會(huì)影響到父資源。刪除父資源會(huì)導(dǎo)致子資源被聯(lián)動(dòng)刪除。(默認(rèn) kubectl delete --cascade=foreground

          七、參考資料

          關(guān)于本主題的內(nèi)容,我制作了一個(gè) slides,可用于內(nèi)部分享:https://s3.laisky.com/public/slides/k8s-controller.slides.html#/

          1、如何閱讀源碼

          核心代碼:https://github.com/kubernetes/kubernetes,所有的 controller 代碼都在 pkg/controller/ 中。

          所有的 clientset、informer 都被抽象出來在 https://github.com/kubernetes/client-go 庫中,供各個(gè)組件復(fù)用。

          學(xué)習(xí)用示例項(xiàng)目:https://github.com/kubernetes/sample-controller

          2、參考文章

          • Garbage Collection[4]
          • Using Finalizers to Control Deletion[5]
          • A deep dive into Kubernetes controllers[6]
          • kube-controller-manager[7]

          引用鏈接

          [1]

          A deep dive into Kubernetes controllers: https://app.yinxiang.com/shard/s17/nl/2006464/674c3d83-f011-49b8-9135-413588c22c0f/

          [2]

          Garbage Collection: https://kubernetes.io/docs/concepts/workloads/controllers/garbage-collection/

          [3]

          Using Finalizers to Control Deletion: https://kubernetes.io/blog/2021/05/14/using-finalizers-to-control-deletion/

          [4]

          Garbage Collection: https://kubernetes.io/docs/concepts/workloads/controllers/garbage-collection/

          [5]

          Using Finalizers to Control Deletion: https://kubernetes.io/blog/2021/05/14/using-finalizers-to-control-deletion/

          [6]

          A deep dive into Kubernetes controllers: https://engineering.bitnami.com/articles/a-deep-dive-into-kubernetes-controllers.html

          [7]

          kube-controller-manager: https://kubernetes.io/docs/reference/command-line-tools-reference/kube-controller-manager/

          原文鏈接:https://blog.laisky.com/p/kubernetes-controller/


          你可能還喜歡

          點(diǎn)擊下方圖片即可閱讀

          云原生優(yōu)質(zhì) Podcast 推薦大全,太強(qiáng)了!

          云原生是一種信仰???

          關(guān)注公眾號(hào)

          后臺(tái)回復(fù)?k8s?獲取史上最方便快捷的 Kubernetes 高可用部署工具,只需一條命令,連 ssh 都不需要!



          點(diǎn)擊?"閱讀原文"?獲取更好的閱讀體驗(yàn)!


          發(fā)現(xiàn)朋友圈變“安靜”了嗎?

          瀏覽 54
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  天天干天天日天天干天天日 | 日本动漫操逼一区二区 | 无码乱论视频 | 国产精品久久久久久吹潮 | 怕怕怕视频大全 |