K8s GC設計原則

作者: 要沒時間了  來源: 知乎  發布時間: 2019-12-14 23:31  閱讀: 893 次  推薦: 3   原文鏈接   [收藏]  

  Ref

  Warning:設計文檔的對應的 k8s 版本為1.7

Q: What is GC of Kuernetes ?

  GC 是 Garbage Collector 的簡稱。從功能層面上來說,它和編程語言當中的「GC」 基本上是一樣的。它清理 Kubernetes 中「符合特定條件」的 Resource Object。(在 k8s 中,你可以認為萬物皆資源,很多邏輯的操作對象都是 Resource Object。)

Q: What are dependent mechanisms to clear needless resource objects?

  Kubernetes 在不同的 Resource Objects 中維護一定的「從屬關系」。內置的 Resource Objects 一般會默認在一個 Resource Object 和它的創建者之間建立一個「從屬關系」。

  當然,你也可以利用 ObjectMeta.OwnerReferences 自由的去給兩個 Resource Object 建立關系,前提是被建立關系的兩個對象必須在一個 Namespace 下。

 1 // OwnerReference contains enough information to let you identify an owning
 2 // object. Currently, an owning object must be in the same namespace, so there
 3 // is no namespace field.
 4 type OwnerReference struct {
 5     // API version of the referent.
 6     APIVersion string `json:"apiVersion" protobuf:"bytes,5,opt,name=apiVersion"`
 7     // Kind of the referent.
 8     // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds
 9     Kind string `json:"kind" protobuf:"bytes,1,opt,name=kind"`
10     // Name of the referent.
11     // More info: http://kubernetes.io/docs/user-guide/identifiers#names
12     Name string `json:"name" protobuf:"bytes,3,opt,name=name"`
13     // UID of the referent.
14     // More info: http://kubernetes.io/docs/user-guide/identifiers#uids
15     UID types.UID `json:"uid" protobuf:"bytes,4,opt,name=uid,casttype=k8s.io/apimachinery/pkg/types.UID"`
16     // If true, this reference points to the managing controller.
17     // +optional
18     Controller *bool `json:"controller,omitempty" protobuf:"varint,6,opt,name=controller"`
19     // If true, AND if the owner has the "foregroundDeletion" finalizer, then
20     // the owner cannot be deleted from the key-value store until this
21     // reference is removed.
22     // Defaults to false.
23     // To set this field, a user needs "delete" permission of the owner,
24     // otherwise 422 (Unprocessable Entity) will be returned.
25     // +optional
26     BlockOwnerDeletion *bool `json:"blockOwnerDeletion,omitempty" protobuf:"varint,7,opt,name=blockOwnerDeletion"`
27 }

   OwnerReference 一般存在于某一個 Resource Object 信息中的 metadata 部分。

   OwnerReference 中的字段可以唯一的確定 k8s 中的一個 Resource Object。兩個 Object 可以通過這種方式建立一個 owner-dependent 的關系。

  K8s 實現了一種「Cascading deletion」(級聯刪除)的機制,它利用已經建立的「從屬關系」進行資源對象的清理工作。例如,當一個 dependent 資源的 owner 已經被刪除或者不存在的時候,從某種角度就可以判定,這個 dependent 的對象已經是異常(無人管轄)的了,需要進行清理。而 「cascading deletion」則是被 k8s 中的一個 controller 組件實現的: Garbage Collector 

  所以,k8s 是通過 Garbage Collector 和 ownerReference 一起配合實現了「垃圾回收」的功能。

Q: What is the relationship like ?(owner-dependent)

  我們可以通過一個實際的例子來了解這個「從屬關系」:

 1 apiVersion: extensions/v1beta1
 2 kind: ReplicaSet
 3 metadata:
 4   annotations:
 5     deployment.kubernetes.io/desired-replicas: "2"
 6     deployment.kubernetes.io/max-replicas: "3"
 7     deployment.kubernetes.io/revision: "1"
 8   creationTimestamp: 2018-09-07T07:11:52Z
 9   generation: 1
10   labels:
11     app: coffee
12     pod-template-hash: "3866135192"
13   name: coffee-7dbb5795f6
14   namespace: default
15   ownerReferences:
16   - apiVersion: apps/v1
17     blockOwnerDeletion: true
18     controller: true
19     kind: Deployment
20     name: coffee
21     uid: 4b807ee6-b26d-11e8-b891-fa163eebca40
22   resourceVersion: "476159"
23   selfLink: /apis/extensions/v1beta1/namespaces/default/replicasets/coffee-7dbb5795f6
24   uid: 4b81e76c-b26d-11e8-b891-fa163eebca40
25 spec:
26   replicas: 2
27 ....

  上面截取了一個 ReplicaSet Object 中的 metadata 的部分信息。

  我們可以注意到,它的 ownerReferences 字段標識了一個 Deployment Object。我們都清楚的是,ReplicaSet 會創建一系列的 Pod。通過 spec.replicas:2 可以知道,他會創建兩個pod。

1 root@xr-service-mesh-lab:~/istio-1.0.2# kubectl get pods  | grep coffee
2 coffee-7dbb5795f6-6crxz          1/1       Running   0          9d
3 coffee-7dbb5795f6-hv7tr          1/1       Running   0          5d
4 root@xr-service-mesh-lab:~/istio-1.0.2#

  讓我們來觀察其中一個 Pod:

 1 apiVersion: v1
 2 kind: Pod
 3 metadata:
 4   annotations:
 5     cni.projectcalico.org/podIP: 192.168.0.14/32
 6   creationTimestamp: 2018-09-07T07:11:52Z
 7   generateName: coffee-7dbb5795f6-
 8   labels:
 9     app: coffee
10     pod-template-hash: "3866135192"
11   name: coffee-7dbb5795f6-6crxz
12   namespace: default
13   ownerReferences:
14   - apiVersion: apps/v1
15     blockOwnerDeletion: true
16     controller: true
17     kind: ReplicaSet
18     name: coffee-7dbb5795f6
19     uid: 4b81e76c-b26d-11e8-b891-fa163eebca40
20   resourceVersion: "76727"
21   selfLink: /api/v1/namespaces/default/pods/coffee-7dbb5795f6-6crxz
22   uid: 4b863e4d-b26d-11e8-b891-fa163eebca40

  我們可以看出,pod 中的 ownerReferences 所標識的 Object 正式我們上面看到過的 ReplicaSet。最后讓我們來檢查一下 ReplicaSet 所對應的 Deployment 的情況:

 1 apiVersion: extensions/v1beta1
 2 kind: Deployment
 3 metadata:
 4   annotations:
 5     deployment.kubernetes.io/revision: "1"
 6   creationTimestamp: 2018-09-07T07:11:52Z
 7   generation: 1
 8   labels:
 9     app: coffee
10   name: coffee
11   namespace: default
12   resourceVersion: "476161"
13   selfLink: /apis/extensions/v1beta1/namespaces/default/deployments/coffee
14   uid: 4b807ee6-b26d-11e8-b891-fa163eebca40

  對比一下 ReplicaSet Object 中 ownerReference 標識的 Object 可知,這個 Deployment 是 ReplicaSet 的 owner。至此,我們通過觀察三個 Object 中的 ownerReference 的信息,可以建立起如下的「從屬關系」:

  • Deployment(owner)—> ReplicaSet (dependent)
  • ReplicaSet (owner) —> Pod (dependent)

Q: What is the working mechanism of Garbage Collector?

  一個 Garbage Collector 通常由三部分實現:

  • Scanner: 它負責收集目前系統中已存在的 Resource,并且周期性的將這些資源對象放入一個隊列中,等待處理(檢測是否要對某一個Resource Object 進行 GC 操作)
  • Garbage Processor: Garbage Processor 由兩部分組成
    • Dirty Queue: Scanner 會將周期性掃描到的 Resource Object 放入這個隊列中等待處理
    • Worker:worker 負責從這個隊列中取出元素進行處理
      • 檢查 Object 的 metaData 部分,查看 ownerReference 字段是否為空
        • 如果為空,則本次處理結束
        • 如果不為空,檢測 ownerReference 字段內標識的 Owner Resource Object是否存在
          • 存在:則本次處理結束
          • 不存在:刪除這個 Object

  其實,在有了 Scanner 和 Garbage Processor 之后,Garbage Collector 就已經能夠實現「垃圾回收」的功能了。但是有一個明顯的問題:Scanner 的掃描頻率設置多少好呢?太長了,k8s 內部就會積累過多的「廢棄資源」;太短了,尤其是在集群內部資源對象較多的時候,頻繁的拉取信息對 API-Server 也是一個不小的壓力。

  k8s 作為一個分布式的服務編排系統,其內部執行任何一項邏輯或者行為,都依賴一種機制:「事件驅動」。說的簡單點,k8s 中一些看起來「自動」的行為,其實都是由一些神秘的「力量」在驅動著。而這個「力量」就是我們所說的「Event」。任意一個 Resource Object 發生變動的時候(新建,更新,刪除),都會觸發一個 k8s 的事件(Event),這個事件在 k8s 的內部是公開的,也就是說,我們可以在任意一個地方監聽這些事件。

  總的來說,無論是「事件的監聽機制」還是「周期性訪問 API-Server 批量獲取 Resource Object 信息」,其目的都是為了能夠掌握 Resource Object 的最新信息。兩者是各有優勢的:

  1. 批量拉取:一次性拉取所有的 Resource Object,全面
  2. 監聽 Resource 的 Event:實時性強, 且對 API—SERVER 不會造成太大的壓力

  綜上所述,在實現 Garbage Collector 的過程中,k8s 向其添加了一個「增強型」的組件:Propagator

  • Propagator: Propagator 由三個部分構成
    • EventQueue:負責存儲 k8s 中資源對象的事件(Eg:ADD,UPDATE,DELETE)
    • DAG(有向無環圖):負責存儲 k8s 中所有資源對象的「owner-dependent」 關系
    • Worker:從 EventQueue 中,取出資源對象的事件,根據事件的類型會采取以下兩種操作
      • ADD/UPDATE: 將該事件對應的資源對象加入 DAG,且如果該對象有 owner 且 owner 不在 DAG 中,將它同時加入 Garbage Processor 的 Dirty Queue 中
      • DELETE:將該事件對應的資源對象從 DAG 中刪除,并且將其「管轄」的對象(只向下尋找一級,如刪除 Deployment,那么只操作 ReplicaSet )加入 Garbage Processor 的 Dirty Queue 中

  在有了 Propagator 的加入之后,我們完全可以僅在 GC 開始運行的時候,讓 Scanner 掃描一下系統中所有的 Object,然后將這些信息傳遞給 Propagator 和 Dirty Queue。只要 DAG 一建立起來之后,那么 Scanner 其實就沒有再工作的必要了。「事件驅動」的機制提供了一種增量的方式讓 GC 來監控 k8s 集群內部的資源對象變化情況。

Q: How can I delete the owner and reserve dependents ?

  沒錯,需求就是這么奇怪,k8s 還兼容一種情況:刪除 owner,留下 dependents。剩余的 dependents 被稱為是「orphan」

  你想怎么實現?

  如果暫時先不看設計文檔中關于這部分的內容,根據之前對 k8s GC 的了解,讓你來實現這個功能,你會怎么做呢?這里給出一下筆者的想法:

  首先,我們先來根據上面對于 GC 的了解,給出一幅大致架構圖:

 

  在上圖中,我用三種顏色分別標記了三條較為重要的處理過程:

  • 紅色:worker 從 dirtyQueue 中取出資源對象,檢查其是否帶有 owner ,如果沒帶,則不處理。否則檢測其 owner是否存在,存在,則處理下一個資源對象,不存在,刪除這個 object。
  • 綠色: scanner 從 api-server 中掃描存在于 k8s 集群中的資源對象并加入至 dirtyQueue
  • 粉色:propagator.worker 從 eventQueue 中取出相應的事件并且獲得對應的資源對象,根據事件的類型以及相應資源對象所屬 owner 對象的情況來進行判定,是否要進行兩個操作:
    • 從 DAG 中刪除相應節點(多為響應 DELETE 事件的邏輯)
    • 將有級聯關系但是 owner 不存在的對象送入 diryQueue 中

  其中紅色是「數據處理」過程,而綠色和粉色是「數據收集」的過程。在「數據處理」的過程中(即我們上面分析過的 GC 的 Worker 的工作過程),worker 做的較為重要的工作有兩步:

  • 檢查資源對象信息的「ownerReference」字段,判斷其是否處在一個級聯關系中
  • 若資源對象有所屬 owner 且不存在,則刪除這個對象

  此時,回頭看下我們的需求:「owner 刪除,dependents 留下」。如果想在「數據處理」這條鏈路上做些修改達到我們目的的話,唯一可行的辦法就是:在刪除了 dependents 對應的 owner 對象之后,同時刪除 dependents 信息中 「ownerReference」字段和對應的值。這樣一來,在檢測資源對象是否應該被刪除的過程就會因為其沒有「ownerReference」字段而放過它,最終實現了 dependents 對象的“孤立”。

  k8s 是怎么實現的?

  如果你了解 gRPC-intercepter 的工作機制,那么會加快你理解下面的內容

  k8s 在系統內部實現了一種類似「刪除攔截器鏈」的機制:即在刪除某個資源對象的「刪除鏈路」上,執行一個或多個「攔截邏輯」。并且這種「攔截邏輯」可以自主實現,然后像插件一樣注入到這個刪除鏈路上。這種機制在 k8s 當中統稱為: Finalizers 。

   Finalizers 的聲明非常簡單,就是一個 []string 。這個 Slice 的內部填充的是要執行攔截器的名稱。它存在于任何一個資源對象的 Meta 信息中: apimachinery/types.go at master · kubernetes/apimachinery · GitHub

   Finalizers 中的攔截器在其宿主資源對象觸發刪除操作之后順序執行(資源對象的deletionTimestamp不為 nil),每執行完一個,就會從 Finalizers 中移除一個,直到 Finalizers 為空的 Slice,其宿主資源對象才可以被真正的刪除。

  于「刪除 owner 但是不刪除 dependents」 的需求,k8s 則是實現了一個:orphan finalizer。一般情況下,正常利用 GC 級連刪除一個資源對象是不會涉及到 orphan finalizer 的。它執行的是我們之前提到的 GC 的工作邏輯。如果你想啟用這個特性,就需要在刪除資源對象的時候,根據 K8s 版本的不同,將名為 DeleteOption.OrphanDependents 的參數賦值為 True(1.7版本以前)

  或者將 DeleteOption.PropagationPolicy 參數賦值為 metav1.DeletePropagationOrphan :apimachinery/types.go at 9dc1de72c0f3996657ffc88895f89f3844d8cf01 · kubernetes/apimachinery · GitHub

  通過這個參數的注釋也可以看出:如果設置好之后,將會在它的 Finalizers 中加入 orphan finalizer。而加入 orphan finalizer 這部分的邏輯是在 api-server 的 package 中:apiserver/store.go at master · kubernetes/apiserver · GitHub

  加入了 orphan finalizer 之后,在 GC 的 worker 從 dirtyQueue 中取出 owner 資源對象進行處理的時候,就會執行它的邏輯:刪除 dependents 的 OwnerReference 部分: kubernetes/garbagecollector.go at 0972ce1accf859b73abb5a68c0adf4174245d4bf · kubernetes/kubernetes · GitHub。最終,在「保留 dependents」 的邏輯完成之后,orphan finalizer 也會從相應資源對象的 Finalizers 中刪除。

  一個隱含的 Race 問題

  對于 Controller 來說,它會周期性的通過 Selector 來尋找它所創建的資源。

  如果在篩選到了符合自己 label 的 資源,但是發現它的 Meta.OwnerReference 字段中沒有自己相關的信息的時候,就會執行一個Adoption 的操作,也就是將和自己有關的 OwnerReference 信息注入到這個 Pod 的 Meta 部分。這種邏輯雖然看起來是比較「保險」,但是實際上它和 orphan finalizer 的邏輯是有沖突的。前者是對 dependents 增加 OwnerReference 信息, 后者則是刪除它。兩個邏輯在執行的時候,如果不保證「互斥」的話,很可能就會出現一個很嚴重的競爭問題:指定了 orphan finalizer 的 對象,其 dependents 最終也會被刪除。

  借鑒操作系統對于「競爭」問題的處理方式,對 OwnerReference操作的的邏輯(即臨界區),應該被「互斥」機制保護起來。而在 k8s 中,實現這種互斥保護機制的方式也很簡單:Controller 在想執行 Adoption 操作之前,會檢查一下當前資源對象的meta.DeletionTimestamp。如果這個字段的值為非 nil,那么就證明這個資源對象已經在被刪除中了。所以就不會再繼續執行 Adoption 操作。

  但是仔細想一下,這種「互斥」保護機制的實現方式,看起來是借助了一個「鎖變量」(meta.DeletionTimestamp)的幫助。不過,我們并不需要擔心這個字段的「競爭」問題,因為能修改它的操作,只有「刪除」操作,而刪除操作是肯定會發生在 orphan finalizer 執行之前的。也就是說,當 orphan finalizer 執行的時候,這個值早就被設置進去了。 kubernetes/replica_set.go at 7f23a743e8c23ac6489340bbb34fa6f1d392db9d · kubernetes/kubernetes · GitHub

Q: How Kubernetes defines delete operation of resource object?

  K8s 在對資源對象「刪除」操作的定義上,思考了一個較為重要的問題:「刪除」操作真正完成的標志是什么?(達到什么樣的條件才可以通知用戶「刪除」操作成功)。這個問題出現的源頭是在用戶側,當用戶在使用 k8s 提供的資源對象的「刪除」操作時,有個問題會影響到他們:

  1. 「刪除」操作成功多久后才可以在同一個 ns 下創建同名資源對象?

  如果你了解過構建一個 k8s 集群所需要的服務組件,就可以很清楚的知道:k8s 中的資源對象的信息都是存于一個key-value 的數據庫當中的(etcd),且是以名字來做索引的。

  通過命令行 kubectl get xxx 查詢的資源對象的信息都來自于那。而且,當 kubelet 組件刪除掉其所在節點上的一些資源的時候,會調用 API-Server 提供的接口刪除掉key-value 數據庫中相應的記錄。所以,在 k8s 中,給「刪除」操作下了這樣一個定義:

在沒有 orphanFinalizer 參與的前提下,直到被刪除對象及其「管轄」對象的信息在 key-value 數據庫中都被清除,才認為該對象真正的被 GC 回收。即達到了返回給用戶「刪除成功」的標準。

  本質上來說,上述所表示的刪除操作是「同步」的。因為有「級聯關系」(owner-dependent) 關系的存在,刪除一個資源對象往往影響的不是他自己,還有他的 dependents。只有將因它出現的所有資源都刪除,才可以認為這個對象被刪除了。

  若想指定這種同步的刪除模式,需要在兩個不同的位置設置兩個參數:

  1. dependents 對象 meta 信息中 OwnerReference.BlockOwnerDeletion
  2. 在發送刪除對象請求時,設置 DeleteOptions.PropagationPolicy

   OwnerReference.BlockOwnerDeletion 參數大多數情況下在相應的 dependents 對象創建的時候就設置進去了。

  如果想在 dependents 對象創建之后更新這個參數的值,可能需要使用 admission controller  (1.7及以上版本)提供的一些權限相關的功能。

   DeleteOptions.PropagationPolicy 一共有3個候選值:

 1 // DeletionPropagation decides if a deletion will propagate to the dependents of
 2 // the object, and how the garbage collector will handle the propagation.
 3 type DeletionPropagation string
 4 
 5 const (
 6     // Orphans the dependents.
 7     DeletePropagationOrphan DeletionPropagation = "Orphan"
 8     // Deletes the object from the key-value store, the garbage collector will
 9     // delete the dependents in the background.
10     DeletePropagationBackground DeletionPropagation = "Background"
11     // The object exists in the key-value store until the garbage collector
12     // deletes all the dependents whose ownerReference.blockOwnerDeletion=true
13     // from the key-value store.  API sever will put the "foregroundDeletion"
14     // finalizer on the object, and sets its deletionTimestamp.  This policy is
15     // cascading, i.e., the dependents will be deleted with Foreground.
16     DeletePropagationForeground DeletionPropagation = "Foreground"
17 )

  再結合 OwnerReference.BlockOwnerDeletion 參數的注釋

1 // If true, AND if the owner has the "foregroundDeletion" finalizer, then
2     // the owner cannot be deleted from the key-value store until this
3     // reference is removed.
4     // Defaults to false.
5     // To set this field, a user needs "delete" permission of the owner,
6     // otherwise 422 (Unprocessable Entity) will be returned.
7     // +optional
8     BlockOwnerDeletion *bool `json:"blockOwnerDeletion,omitempty" protobuf:"varint,7,opt,name=blockOwnerDeletion"`

  我們可以了解到。同步刪除的開啟方式如下:

  1. DeleteOptions.PropagationPolicy = DeletePropagationForeground
  2. OwnerReference. BlockOwnerDeletion = True

  開啟之后,在刪除身份為 owner 的資源對象的時候,就會先將 denpendents 對象中 OwnerReference.BlockOwnerDeletion 為 true 的資源對象先刪除,然后再刪除 owner 身份的對象。這里的「刪除」就指的是我們前面說過的「真正的刪除」:從 k8s 存儲資源對象信息的 key-value 數據庫中刪除所有與其相關的信息。需要注意的是, OwnerReference.BlockOwnerDeletion 為 false 的dependent 對象不會阻礙 owner 對象的刪除操作。

  Foreground 是 k8s 提供的兩種級聯刪除方式其中之一,另外一種為 Background。通過上面相關的注釋可以看到 Foreground 級聯刪除也是通過 Finalizer 來實現的,查看 Finalizer 相關的定義可知,標準的 Finalizer,一個是 orphan 的,另一個就是Foreground的:

1 // These are internal finalizer values for Kubernetes-like APIs, must be qualified name unless defined here
2 const (
3     FinalizerOrphanDependents string = "orphan"
4     FinalizerDeleteDependents string = "foregroundDeletion"
5 )

  API-Server 的 Delete 函數,在接受到刪除請求的時候,會檢查 DeleteOptions.PropagationPolicy 參數,若其值為 DeletePropagationForeground , API-Server 隨即會對該資源對象進行 Update 操作:

  1. 插入 FinalizerDeleteDependents  Finalizer
  2. 設置 ObjectMeta.DeletionTimestamp  為當前值

  然后,在 GC 處理 owner 對象的 Update 事件的邏輯中,還會給 owner 對象打上一個「正在刪除 dependents」 對象的標簽。之后,我們會將 owner 對象管轄的 dependent 對象和他自己都加入到 dirtyQueue。dirtyQueue 的 worker 在處理 owner 對象的時候,會檢查 owner 對象 「正在刪除 dependents」的標簽是否存在,如果仍有 dependent 對象沒有被刪掉,owner 會被輪詢處理。而 dependent 對象將會被正常刪除。當 dependent 對象相應的刪除事件被 Propagator 感知到后,會將其從 DAG 和其 owner 的 dependents 信息中刪除。幾個循環之后,dependents 機會被刪光,而 owner 對象中的 finalizer 和自身也會隨之被刪掉。

  Background 模式的級聯刪除不會因 dependent 對象而影響 owner 對象的刪除操作。當我們發送給 API-Server 刪除一個 owner 身份的對象的請求之后,這個資源對象會立即被刪除。它「管轄」的 dependent 對象會以「靜默」的方式刪除。

Q: What problems GC handles in k8s?

  通過對 k8s GC 設計文檔的閱讀,可以大致的概括一下:GC 主要是按照用戶的需求來清理系統中「異常」的資源,用戶可以自定義「清理方式」和「清理策略」。不難發現,在 GC 中,到底是保留一個資源還是刪除一個資源都參照了資源之間的「從屬關系」。資源的「從屬關系」可以大致分為幾個形態:

  1. 無從屬關系:這部分資源基本不會被 GC 做處理
  2. 有從屬關系
    1. 不符合用戶預期:刪除異常資源
    2. 符合用戶預期:解綁異常資源之間的級聯關系

  在有從屬關系的資源之間,即使被探測到關系異常,也并不代表一定要將他們都清除。如果有 Orphan Finalizer 的存在,可能某種「異常」正是用戶想要的。所以,這就回到了我們一開始所說到的「清理策略」問題。GC 有一定的默認的清理策略,但是用戶可以通過加入 Finalizer 的形式來修改「清理策略」,從而保持一個「符合用戶期望」的資源之間的從屬關系。

  同時,用戶可以還可以通過參數來制定特定的「清理方式」,如 Foreground 或者 Background。總體上來說,GC 的行為會受到如下幾個因素的影響:

  • 默認:
    • 依據:資源之間默認的從屬關系
    • 行為:刪除級聯關系異常的資源
    • 方式:Foreground 或者 Background
  • 可定制
    • 依據:用戶定義的從屬關系(通過 Finalizer)
    • 行為:刪除級聯關系異常的資源
    • 方式:Foreground 或者 Background

  目前看來,GC 主要是解決了「資源清理」 的問題。那么再抽象一點來看的話,GC 解決的是「資源管理」這個大問題中的一個關于「清理」的小問題。既然說到「資源管理」,那么肯定就不止「清理」一個問題需要處理:

 

  其中,對于資源的創建部分,除了正常的新建操作之外,controller 還有定期執行一個「Adoption」 的操作,用來維護其創建的資源之間那些「本應該建立但是卻斷開的從屬關系」。而對于更新操作來說,controller_manager 需要處理用戶對于資源的擴縮容請求,如將 deployment.replicaset.replicacount 減少或者增大,相應資源對應的 controller 需要對可見資源的數量進行調整。至于「資源超賣」的問題,一定會涉及到 scheduler。因為物理資源是固定的,「超賣」本質上來說就是按照實時的需求,動態的調整服務所在的 Node,以便恰好滿足服務對于資源的需求。

  如果不把資源管理問題討論的范圍局限在 k8s 中的話,那么「審計」和「復用」同樣也是「資源管理」問題中不得不考慮的兩個點。前者可以增加整個系統資源的「可控性」,后者則可以最大限度的提升資源的利用率,從而降低成本。其實「復用」和「超賣」的目的是一樣的,都是想最大限度的利用物理資源。不過這兩個功能筆者暫時還沒有去查看它們是否在 k8s 已經實現。

  總結

  之所以去了解 k8s 的 GC,是因為在將 k8s 集群從1.7版本升級至1.9版本的過程中,因為我錯誤的設置了資源之間的從屬關系,導致該資源被 GC 給回收掉了。問題在1.7版本沒有出現的原因是那時 k8s 還沒有支持對自定義資源(CRD)的級聯刪除。通過對 GC 設計理念的了解,我們可以初步的感受到 k8s 對于「資源管理」這個問題域中「資源清理」這個小問題的解決思路。以此為起點,我們可以順藤摸瓜,去觀察 k8s 對于「資源管理」問題域中的其他難題是如何處理的。后續,我也將會根據設計文檔中的思路,在代碼級別上去了解 GC 的實現細節,從而貢獻出更加詳細的 blog。

3
0
 
標簽:k8s
 
 

文章列表

arrow
arrow
    全站熱搜
    創作者介紹
    創作者 大師兄 的頭像
    大師兄

    IT工程師數位筆記本

    大師兄 發表在 痞客邦 留言(0) 人氣()