<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>

          Karmada 如何跨集群實(shí)現(xiàn)完整的自定義資源分發(fā)能力?

          共 13288字,需瀏覽 27分鐘

           ·

          2022-11-24 22:07

          ?

          本文轉(zhuǎn)自徐信釗的博客,原文:https://xinzhao.me/posts/guide-to-karmada-resource-interpreter-webhook/,版權(quán)歸原作者所有。歡迎投稿,投稿請?zhí)砑游⑿藕糜眩?strong style="color: rgb(50, 108, 229);">cloud-native-yang

          Karmada 介紹

          在開始講 Resource Interpreter Webhook 之前需要對 Karmada 的基礎(chǔ)架構(gòu)以及如何分發(fā)應(yīng)用等有一定的了解,但那一部分在之前的博客中已經(jīng)提到過了,所以這篇文章就不再贅述了,如果需要的話可以移步到 Kubernetes 多集群項(xiàng)目介紹[1]了解。

          一個例子:創(chuàng)建一個 nginx 應(yīng)用

          讓我們先從一個最簡單的例子開始,在 Karmada 中創(chuàng)建并分發(fā)一個 nginx 應(yīng)用;首先是準(zhǔn)備 nginx 的資源模板,這個就是原生的 K8s Deployment,不需要任何改變:

          apiVersion: apps/v1
          kind: Deployment
          metadata:
            name: nginx
            labels:
              app: nginx
          spec:
            replicas: 2
            selector:
              matchLabels:
                app: nginx
            template:
              metadata:
                labels:
                  app: nginx
              spec:
                containers:
                - image: nginx
                  name: nginx

          再準(zhǔn)備一個 PropagationPolicy,用來控制 nginx 分發(fā)到哪些集群:

          apiVersion: policy.karmada.io/v1alpha1
          kind: PropagationPolicy
          metadata:
            name: nginx-propagation
          spec:
            resourceSelectors:
              - apiVersion: apps/v1
                kind: Deployment
                name: nginx
            placement:
              clusterAffinity:
                clusterNames:
                  - member1
                  - member2

          這里我們就直接將它分發(fā)到 member1member2 集群。

          member1member2 集群分別有一個副本數(shù)為 2 的 nginx Deployment,所以該資源一共存在 4 個 Pod。

          上面的例子非常簡單,直接在 member 集群根據(jù)模板原封不動創(chuàng)建 Deployment 就行了,但是大家知道 Karmada 是支持一些更高級的副本數(shù)調(diào)度策略的,比如下面這個例子:

          replicaScheduling:
            replicaDivisionPreference: Weighted
            replicaSchedulingType: Divided
            weightPreference:
              staticWeightList:
                - targetCluster:
                    clusterNames:
                      - member1
                  weight: 1
                - targetCluster:
                    clusterNames:
                      - member2
                  weight: 1

          應(yīng)用了該規(guī)則之后,會涉及到針對每個集群上資源副本數(shù)的動態(tài)調(diào)整,之后 Karmada 在 member 集群創(chuàng)建 Deployment 的時候就需要增加一個修改副本數(shù)的步驟。

          針對 Deployment 這類 K8s 核心資源,因?yàn)槠浣Y(jié)構(gòu)是確定的,我們可以直接編寫修改其副本數(shù)的代碼,但是如果我有一個功能類似 Deployment 的 CRD 呢?我也需要副本數(shù)調(diào)度,Karmada 能正確地修改它的副本數(shù)嗎?答案是否定的,也正因此,Karmada 引入了一個新的特性來使其能深度支持自定義資源(CRD)。

          Resource Interpreter Webhook

          為了解決上面提到的問題,Karmada 引入了 Resource Interpreter Webhook,通過干預(yù)從 ResourceTemplateResourceBindingWorkResource 的這幾個階段來實(shí)現(xiàn)完整的自定義資源分發(fā)能力:

          從一個階段到另一個都會經(jīng)過我們預(yù)定義的一個或多個接口,我們會在這些步驟中實(shí)現(xiàn)修改副本數(shù)等操作;用戶需要增加一個單獨(dú)的實(shí)現(xiàn)了對應(yīng)接口的 webhook server,Karmada 會在執(zhí)行到相應(yīng)步驟時通過配置去調(diào)用該 server 來完成操作。

          下面我們將選四個具有代表性的 hook 點(diǎn)來逐一介紹,接下來都使用以下 CRD 作為示例:

          // Workload is a simple Deployment.
          type Workload struct {
           metav1.TypeMeta   `json:",inline"`
           metav1.ObjectMeta `json:"metadata,omitempty"`

           // Spec represents the specification of the desired behavior.
           // +required
           Spec WorkloadSpec `json:"spec"`

           // Status represents most recently observed status of the Workload.
           // +optional
           Status WorkloadStatus `json:"status,omitempty"`
          }

          // WorkloadSpec is the specification of the desired behavior of the Workload.
          type WorkloadSpec struct {
           // Number of desired pods. This is a pointer to distinguish between explicit
           // zero and not specified. Defaults to 1.
           // +optional
           Replicas *int32 `json:"replicas,omitempty"`

           // Template describes the pods that will be created.
           Template corev1.PodTemplateSpec `json:"template" protobuf:"bytes,3,opt,name=template"`

           // Paused indicates that the deployment is paused.
           // Note: both user and controllers might set this field.
           // +optional
           Paused bool `json:"paused,omitempty"`
          }

          // WorkloadStatus represents most recently observed status of the Workload.
          type WorkloadStatus struct {
           // ReadyReplicas represents the total number of ready pods targeted by this Workload.
           // +optional
           ReadyReplicas int32 `json:"readyReplicas,omitempty"`
          }

          它和 Deployment 很像,我們用來演示 Karmada 如何支持這類資源來進(jìn)行副本數(shù)調(diào)度等高級特性。

          InterpretReplica

          該 hook 點(diǎn)發(fā)生在從 ResourceTemplateResourceBinding 這個過程中,針對有 replica 功能的資源對象,比如類似 Deployment 的自定義資源,實(shí)現(xiàn)該接口來告訴 Karmada 對應(yīng)資源的副本數(shù)。

          apiVersion: workload.example.io/v1alpha1
          kind: Workload
          metadata:
            name: nginx
            labels:
              app: nginx
          spec:
            replicas: 3
            template:
              metadata:
                labels:
                  app: nginx
              spec:
                containers:
                  - image: nginx
                    name: nginx

          針對我們示例的 Workload 資源,實(shí)現(xiàn)方式也非常簡單,直接在 webhook server 中返回副本數(shù)的值即可:

          func (e *workloadInterpreter) responseWithExploreReplica(workload *workloadv1alpha1.Workload) interpreter.Response {
           res := interpreter.Succeeded("")
           res.Replicas = workload.Spec.Replicas
           return res
          }
          ?

          注:所有的示例均來自 Karmada 官方文檔,可以通過文章最后的 參考鏈接[2] 來查看完整的示例和代碼。

          ReviseReplica

          該 hook 點(diǎn)發(fā)生在從 ResourceBindingWork 這個過程中,針對有 replica 功能的資源對象,需要按照 Karmada 發(fā)送的 request 來修改對象的副本數(shù)。Karmada  會通過調(diào)度策略把每個集群需要的副本數(shù)計算好,你需要做的只是把最后計算好的值賦給你的 CR 對象(因?yàn)?Karmada 并不知道該 CRD  的結(jié)構(gòu)):

          func (e *workloadInterpreter) responseWithExploreReviseReplica(workload *workloadv1alpha1.Workload, req interpreter.Request) interpreter.Response {
           wantedWorkload := workload.DeepCopy()
           wantedWorkload.Spec.Replicas = req.DesiredReplicas
           marshaledBytes, err := json.Marshal(wantedWorkload)
           if err != nil {
            return interpreter.Errored(http.StatusInternalServerError, err)
           }
           return interpreter.PatchResponseFromRaw(req.Object.Raw, marshaledBytes)
          }

          核心代碼也只有賦值那一行。

          Workload 實(shí)現(xiàn)副本數(shù)調(diào)度

          回到我們最初的那個問題,在了解了 InterpretReplicaReviseReplica 兩個 hook 點(diǎn)之后,就能夠?qū)崿F(xiàn)自定義資源按副本數(shù)調(diào)度了,實(shí)現(xiàn) InterpretReplica hook 點(diǎn)以告知 Karmada 該資源的副本總數(shù),實(shí)現(xiàn) ReviseReplica hook 點(diǎn)來修改對象的副本數(shù),再配置一個 PropagationPolicy 就可以了,配置方法和 Deployment 等資源一樣:

          apiVersion: policy.karmada.io/v1alpha1
          kind: PropagationPolicy
          metadata:
            name: nginx-workload-propagation
          spec:
            resourceSelectors:
              - apiVersion: workload.example.io/v1alpha1
                kind: Workload
                name: nginx
            placement:
              clusterAffinity:
                clusterNames:
                  - member1
                  - member2
              replicaScheduling:
                replicaDivisionPreference: Weighted
                replicaSchedulingType: Divided
                weightPreference:
                  staticWeightList:
                    - targetCluster:
                        clusterNames:
                          - member1
                      weight: 2
                    - targetCluster:
                        clusterNames:
                          - member2
                      weight: 1

          效果如下:

          Retain

          該 hook 點(diǎn)發(fā)生在從 WorkResource 這個過程中,針對 spec 內(nèi)容會在 member 集群單獨(dú)更新的情況,可以通過該 hook 告知 Karmada 保留某些字段的內(nèi)容。

          apiVersion: workload.example.io/v1alpha1
          kind: Workload
          metadata:
            name: nginx
            labels:
              app: nginx
          spec:
            replicas: 3
            paused: false

          paused 為例,該字段的功能是暫停 workload,member 集群的 controller 會單獨(dú)更新該字段,Retain hook 就是為了能更好地和 member 集群的 controller 協(xié)作,可以通過該 hook 來告知 Karmada 哪些字段是需要不用更新、需要保留的。

          func (e *workloadInterpreter) responseWithExploreRetaining(desiredWorkload *workloadv1alpha1.Workload, req interpreter.Request) interpreter.Response {
           if req.ObservedObject == nil {
            err := fmt.Errorf("nil observedObject in exploreReview with operation type: %s", req.Operation)
            return interpreter.Errored(http.StatusBadRequest, err)
           }
           observerWorkload := &workloadv1alpha1.Workload{}
           err := e.decoder.DecodeRaw(*req.ObservedObject, observerWorkload)
           if err != nil {
            return interpreter.Errored(http.StatusBadRequest, err)
           }

           // Suppose we want to retain the `.spec.paused` field of the actual observed workload object in member cluster,
           // and prevent from being overwritten by karmada controller-plane.
           wantedWorkload := desiredWorkload.DeepCopy()
           wantedWorkload.Spec.Paused = observerWorkload.Spec.Paused
           marshaledBytes, err := json.Marshal(wantedWorkload)
           if err != nil {
            return interpreter.Errored(http.StatusInternalServerError, err)
           }
           return interpreter.PatchResponseFromRaw(req.Object.Raw, marshaledBytes)
          }

          核心代碼只有一行,更新 wantedWorkloadPaused 字段為之前版本的內(nèi)容。

          AggregateStatus

          該 hook 點(diǎn)發(fā)生在從 ResourceBindingResourceTemplate 這個過程中,針對需要將 status 信息聚合到 Resource Template 的資源類型,可通過實(shí)現(xiàn)該接口來更新 Resource Template 的 status 信息。

          Karmada 會將各個集群 Resouce 的狀態(tài)信息統(tǒng)一收集到 ResourceBinding 中:

          AggregateStatus hook 需要做的事情就是將 ResourceBindingstatus 信息更新到 Resource Template 中:

          func (e *workloadInterpreter) responseWithExploreAggregateStatus(workload *workloadv1alpha1.Workload, req interpreter.Request) interpreter.Response {
           wantedWorkload := workload.DeepCopy()
           var readyReplicas int32
           for _, item := range req.AggregatedStatus {
            if item.Status == nil {
             continue
            }
            status := &workloadv1alpha1.WorkloadStatus{}
            if err := json.Unmarshal(item.Status.Raw, status); err != nil {
             return interpreter.Errored(http.StatusInternalServerError, err)
            }
            readyReplicas += status.ReadyReplicas
           }
           wantedWorkload.Status.ReadyReplicas = readyReplicas
           marshaledBytes, err := json.Marshal(wantedWorkload)
           if err != nil {
            return interpreter.Errored(http.StatusInternalServerError, err)
           }
           return interpreter.PatchResponseFromRaw(req.Object.Raw, marshaledBytes)
          }

          邏輯也非常簡單,根據(jù) ResourceBinding 中的 status 信息來計算(聚合)出該資源總的 status 信息再更新到 Resource Template 中;效果和 Deployment 類似,可以直接查詢到該資源在所有集群匯總后的狀態(tài)信息:

          參考鏈接

          • Resource Interpreter Webhook[3]
          • custom resource interpreter example[4]

          引用鏈接

          [1]

          Kubernetes 多集群項(xiàng)目介紹: https://xinzhao.me/posts/kubernetes-multi-cluster-projects/#karmada

          [2]

          參考鏈接: https://xinzhao.me/posts/guide-to-karmada-resource-interpreter-webhook/#參考鏈接

          [3]

          Resource Interpreter Webhook: https://github.com/karmada-io/karmada/tree/master/docs/proposals/resource-interpreter-webhook

          [4]

          custom resource interpreter example: https://github.com/karmada-io/karmada/tree/master/examples#resource-interpreter




          你可能還喜歡

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

          Redis on K8s 編排部署講解與實(shí)戰(zhàn)操作

          2022-11-16

          Cilium 未來數(shù)據(jù)平面:支撐 100Gbit/s k8s 集群

          2022-11-14

          Prometheus 官方記錄片(中英雙語),帶你了解 Prometheus 的前世今生

          2022-11-11

          GraalVM 加持 Java 容器化,速度起飛!

          2022-11-09


          云原生是一種信仰 ??


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


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

          瀏覽 75
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          <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>
                  天堂网最新网址 | 黄色成人视频在线免费看 | 97电影院肏逼 | 中文字幕无码电影 | 搞黄视频网站无码动漫 |