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

          OpenKruise:解放 DaemonSet 運(yùn)維之路

          共 8075字,需瀏覽 17分鐘

           ·

          2020-11-06 03:30

          作者?| 王思宇(酒祝)


          前言


          OpenKruise 是阿里云開(kāi)源的大規(guī)模應(yīng)用自動(dòng)化管理引擎,在功能上對(duì)標(biāo)了 Kubernetes 原生的 Deployment/StatefulSet 等控制器,但 OpenKruise 提供了更多的增強(qiáng)功能,如:優(yōu)雅原地升級(jí)、發(fā)布優(yōu)先級(jí)/打散策略、多可用區(qū) workload 抽象管理、統(tǒng)一 sidecar 容器注入管理等,都是經(jīng)歷了阿里巴巴超大規(guī)模應(yīng)用場(chǎng)景打磨出的核心能力。這些 feature 幫助我們應(yīng)對(duì)更加多樣化的部署環(huán)境和需求、為集群維護(hù)者和應(yīng)用開(kāi)發(fā)者帶來(lái)更加靈活的部署發(fā)布組合策略。

          OpenKruise 地址:https://github.com/openkruise/kruise

          目前在阿里巴巴內(nèi)部云原生環(huán)境中,應(yīng)用全部統(tǒng)一使用 OpenKruise 的能力做 Pod 部署、發(fā)布管理,而不少業(yè)界公司和阿里云上的客戶(hù)由于 K8s 原生 Deployment 等負(fù)載不能完全滿(mǎn)足需求,也轉(zhuǎn)而采用 OpenKruise 作為應(yīng)用部署載體。我們希望 OpenKruise 讓每一位 Kubernetes 開(kāi)發(fā)者和阿里云上的用戶(hù)都能便捷地使用上阿里巴巴內(nèi)部云原生應(yīng)用所統(tǒng)一使用的部署發(fā)布能力!

          背景


          如何在 Kubernetes 集群中部署節(jié)點(diǎn)組件呢?相信大家對(duì) DaemonSet 并不陌生,它能夠幫助我們將定義好的 Pod 部署到所有符合條件的 Node 上,這大大減輕了過(guò)去我們維護(hù)節(jié)點(diǎn)上各類(lèi)守護(hù)進(jìn)程的痛苦。

          在阿里巴巴內(nèi)部的云原生環(huán)境中,存在不少網(wǎng)絡(luò)、存儲(chǔ)、GPU、監(jiān)控等等相關(guān)的節(jié)點(diǎn)組件都是通過(guò) DaemonSet 部署管理的。但是隨著近兩年 Kubernetes 集群規(guī)模越來(lái)越大,所有核心業(yè)務(wù)逐漸全量上云原生之后,我們?cè)桨l(fā)感受到原生 DaemonSet 很難滿(mǎn)足大規(guī)模、高可用的復(fù)雜場(chǎng)景需求。

          大家可以理解為原生的 DaemonSet 確實(shí)解決了 0 -> 1 的問(wèn)題,避免了直接管理 Node 上各類(lèi)軟件包和守護(hù)進(jìn)程的難題,能做到用一致化的 Pod 來(lái)部署節(jié)點(diǎn)組件。但是在部署之后呢?我們面臨的是 1 -> N 的不斷迭代升級(jí)的問(wèn)題了,而在升級(jí)能力方面,原生 DaemonSet 做的實(shí)在有些敷衍了事的感覺(jué)。

          apiVersion: apps/v1kind: DaemonSetspec:  updateStrategy:    type: RollingUpdate    rollingUpdate:      maxUnavailable: 2  # ...

          apiVersion: apps/v1kind: DaemonSetspec:  updateStrategy:    type: OnDelete  # ...

          以上是原生 DaemonSet 支持的兩種升級(jí)方式。相信多數(shù)人使用 DaemonSet 基本都是默認(rèn)的 RollingUpdate 滾動(dòng)升級(jí),這本身是沒(méi)問(wèn)題的,問(wèn)題就在于滾動(dòng)升級(jí)時(shí)只支持了 maxUnavailable 一個(gè)策略,這就讓我們很難接受了。目前阿里巴巴內(nèi)的 Kubernetes 不少已經(jīng)做到單集群上萬(wàn)節(jié)點(diǎn),這些節(jié)點(diǎn)可能有不同的機(jī)型、拓?fù)洹⒑诵某潭?、?nèi)核版本等等,而 DaemonSet 升級(jí)也覆蓋到這上萬(wàn)節(jié)點(diǎn)上的 daemon Pod、涉及所有節(jié)點(diǎn)上的應(yīng)用 Pod。

          面對(duì)如此復(fù)雜和規(guī)?;沫h(huán)境,原生 DaemonSet 沒(méi)有灰度、沒(méi)有分批、沒(méi)有暫停、沒(méi)有優(yōu)先級(jí),僅僅用一個(gè) maxUnavailable 策略顯然是無(wú)法滿(mǎn)足的。要知道 daemon Pod 即使配置了 readinessProbe 往往也只能檢查容器內(nèi)進(jìn)程是否啟動(dòng)運(yùn)行,而對(duì)于進(jìn)程的運(yùn)行情況很難考量。

          因此,即使 DaemonSet 發(fā)布了一個(gè)代碼有 bug 的版本,只要進(jìn)程能正常啟動(dòng)則 maxUnavailable 策略就無(wú)法保護(hù),DaemonSet 會(huì)一直發(fā)布下去;如果升級(jí)開(kāi)始了一段時(shí)間后才發(fā)現(xiàn)問(wèn)題,那此時(shí)很可能故障范圍就已經(jīng)覆蓋到整個(gè)集群了。

          為了避免這個(gè)問(wèn)題,我們?cè)?jīng)一度改為使用 OnDelete 策略、在發(fā)布平臺(tái)上控制發(fā)布順序和分批,但終態(tài)上我們還是希望將 workload 的能力下沉歸還到 workload,形成閉環(huán),避免將完整的能力分散到多個(gè)模塊。因此隨著 OpenKruise 的成熟和在阿里內(nèi)外的鋪開(kāi),我們總結(jié)了內(nèi)部對(duì) DaemonSet 的通用化發(fā)布需求、將其沉淀到 OpenKruise 中,稱(chēng)之為 Advanced DaemonSet。


          目前阿里巴巴和螞蟻集團(tuán)內(nèi)部的大部分 DaemonSet 都已經(jīng)統(tǒng)一到 Advanced DaemonSet 部署管理,并且隨著 OpenKruise v0.6.0 版本的推出之后,外部一些公司如位于以色列的 Bringg 都已經(jīng)開(kāi)始對(duì)接使用。

          能力解析


          Advanced DaemonSet 中主要增加的 API 字段如下:

          const (+    // StandardRollingUpdateType replace the old daemons by new ones using rolling update i.e replace them on each node one after the other.+    // this is the default type for RollingUpdate.+    StandardRollingUpdateType RollingUpdateType = "Standard"
          + // SurgingRollingUpdateType replaces the old daemons by new ones using rolling update i.e replace them on each node one+ // after the other, creating the new pod and then killing the old one.+ SurgingRollingUpdateType RollingUpdateType = "Surging")
          // Spec to control the desired behavior of daemon set rolling update.type RollingUpdateDaemonSet struct {+ // Type is to specify which kind of rollingUpdate.+ Type RollingUpdateType `json:"rollingUpdateType,omitempty" protobuf:"bytes,1,opt,name=rollingUpdateType"`
          // ... MaxUnavailable *intstr.IntOrString `json:"maxUnavailable,omitempty" protobuf:"bytes,2,opt,name=maxUnavailable"`
          + // A label query over nodes that are managed by the daemon set RollingUpdate.+ // Must match in order to be controlled.+ // It must match the node's labels.+ Selector *metav1.LabelSelector `json:"selector,omitempty" protobuf:"bytes,3,opt,name=selector"`
          + // The number of DaemonSet pods remained to be old version.+ // Default value is 0.+ // Maximum value is status.DesiredNumberScheduled, which means no pod will be updated.+ // +optional+ Partition *int32 `json:"partition,omitempty" protobuf:"varint,4,opt,name=partition"`
          + // Indicates that the daemon set is paused and will not be processed by the+ // daemon set controller.+ // +optional+ Paused *bool `json:"paused,omitempty" protobuf:"varint,5,opt,name=paused"`
          + // Only when type=SurgingRollingUpdateType, it works.+ // The maximum number of DaemonSet pods that can be scheduled above the desired number of pods+ // during the update. Value can be an absolute number (ex: 5) or a percentage of the total number+ // of DaemonSet pods at the start of the update (ex: 10%). The absolute number is calculated from+ // the percentage by rounding up. This cannot be 0. The default value is 1. Example: when this is+ // set to 30%, at most 30% of the total number of nodes that should be running the daemon pod+ // (i.e. status.desiredNumberScheduled) can have 2 pods running at any given time. The update+ // starts by starting replacements for at most 30% of those DaemonSet pods. Once the new pods are+ // available it then stops the existing pods before proceeding onto other DaemonSet pods, thus+ // ensuring that at most 130% of the desired final number of DaemonSet pods are running at all+ // times during the update.+ // +optional+ MaxSurge *intstr.IntOrString `json:"maxSurge,omitempty" protobuf:"bytes,7,opt,name=maxSurge"`}
          type DaemonSetSpec struct { // ...
          + // BurstReplicas is a rate limiter for booting pods on a lot of pods.+ // The default value is 250+ BurstReplicas *intstr.IntOrString `json:"burstReplicas,omitempty" protobuf:"bytes,5,opt,name=burstReplicas"`}

          1. 按節(jié)點(diǎn)灰度


          在一個(gè)大規(guī)模 Kubernetes 集群中往往存在很多種差異化的節(jié)點(diǎn)類(lèi)型,比如機(jī)型、拓?fù)?、核心程度、?nèi)核版本等,因此在 DaemonSet 發(fā)布的時(shí)候我們支持根據(jù) Node 的標(biāo)簽來(lái)匹配發(fā)布哪些 Node 上的 Pod。

          apiVersion: apps.kruise.io/v1alpha1kind: DaemonSetspec:  # ...  updateStrategy:    type: RollingUpdate    rollingUpdate:      selector:        matchLabels:          nodeType: canary

          比如上述配置了滾動(dòng)升級(jí)下的 selector 策略,則 DaemonSet 只會(huì)在符合 selector 條件的 Node 上把 Pod 做滾動(dòng)升級(jí)。如果 selector 改變,則 DaemonSet 會(huì)按照新的 selector 做升級(jí),對(duì)已經(jīng)是最新版本的 Pod 不會(huì)做變動(dòng)。

          因此,用戶(hù)可以通過(guò)多次修改 selector,來(lái)實(shí)現(xiàn)不同類(lèi)型 Node 的前后發(fā)布順序。這個(gè)優(yōu)先順序可以是特定一批用于灰度的非核心節(jié)點(diǎn),也可以是一些邏輯資源池等。

          2. 按數(shù)量灰度


          如果說(shuō)你不關(guān)心節(jié)點(diǎn)類(lèi)型,Advanced DaemonSet 同樣提供了按數(shù)量灰度的能力:

          apiVersion: apps.kruise.io/v1alpha1kind: DaemonSetspec:  # ...  updateStrategy:    type: RollingUpdate    rollingUpdate:      partition: 100

          這里的 partition 和 OpenKruise 中其他 CloneSet、Advanced StatefulSet 類(lèi)似,都表示了維持舊版本的數(shù)量,也就是說(shuō) Kruise 控制器會(huì)選擇 status.DesiredNumberScheduled - partition 數(shù)量的 Pod 滾動(dòng)升級(jí)為新版本。

          比如當(dāng)前集群中 DaemonSet 部署的節(jié)點(diǎn)數(shù)量是 120 個(gè),當(dāng)滾動(dòng)升級(jí)時(shí)如果設(shè)置了 partition 為 100,則 DaemonSet 只會(huì)選擇 20 個(gè) Pod 滾動(dòng)到新版本。只有當(dāng)用戶(hù)再次下調(diào) partition,DaemonSet 才會(huì)繼續(xù)按要求數(shù)量來(lái)繼續(xù)升級(jí)。

          3. 多維度灰度


          上述兩種灰度策略相信都不難理解,那么如果同時(shí)配置了按節(jié)點(diǎn)和按數(shù)量?jī)煞N灰度策略,會(huì)怎么樣呢?

          apiVersion: apps.kruise.io/v1alpha1kind: DaemonSetspec:  # ...  updateStrategy:    type: RollingUpdate    rollingUpdate:      maxUnavailable: 5      partition: 100      selector:        matchLabels:          nodeType: canary

          想搞清楚這個(gè)問(wèn)題,其實(shí)看懂 Advanced DaemonSet 的發(fā)布策略計(jì)算邏輯就很好理解了,有興趣的同學(xué)可以跳去看一下:https://github.com/openkruise/kruise/blob/master/pkg/controller/daemonset/update.go#L459

          參考上面這個(gè) YAML,如果用戶(hù)同時(shí)配置了 partition 和 selector,那么控制器在發(fā)布的時(shí)候會(huì)先按照 selector 匹配符合條件的 Node,再按照 partition 計(jì)算其中能夠發(fā)布的數(shù)量。當(dāng)然,如果你還配置了原生 DaemonSet 就支持的 maxUnavailable,那么最后還會(huì)按照 unavailable 的數(shù)量再次限制實(shí)際能滾動(dòng)升級(jí)的數(shù)量。

          簡(jiǎn)單來(lái)說(shuō),最終真正執(zhí)行滾動(dòng)升級(jí)的 Pod,一定是要同時(shí)滿(mǎn)足所有配置的灰度策略。

          4. 熱升級(jí)


          標(biāo)準(zhǔn)的 DaemonSet 滾動(dòng)升級(jí)過(guò)程,是通過(guò)先刪除舊 Pod、再創(chuàng)建新 Pod 的方式來(lái)做的。在絕大部分場(chǎng)景下這樣的方式都是可以滿(mǎn)足的,然而如果這個(gè) daemon Pod 的作用還需要對(duì)外提供服務(wù),那么滾動(dòng)的時(shí)候可能對(duì)應(yīng) Node 上的服務(wù)就不可用了。

          為了提供高可用能力,我們對(duì) DaemonSet 也提供了 surging 發(fā)布策略。(回顧一下原生 Deployment 或者 OpenKruise 的 CloneSet,在這些面向無(wú)狀態(tài)服務(wù)的 workload 中如果配置了 maxSurging,則發(fā)布時(shí)會(huì)先多擴(kuò)出來(lái) maxSurging 數(shù)量的 Pod,再逐漸刪掉舊版本的 Pod。)

          apiVersion: apps.kruise.io/v1alpha1kind: DaemonSetspec:  # ...  updateStrategy:    rollingUpdate:      type: Surging  # defaults to Standard      maxSurge: 30%

          首先,在滾動(dòng)升級(jí)中配置 type: Surging,這個(gè)類(lèi)型默認(rèn)是 Standard -- 也就是先刪再擴(kuò),而一旦設(shè)置為 Surging 則變?yōu)橄葦U(kuò)再縮。也就是在滾動(dòng)升級(jí)時(shí),DaemonSet 會(huì)先在要發(fā)布的 Node 上新建一個(gè) Pod,等這個(gè)新版本 Pod 變?yōu)?ready 之后再把舊版本 Pod 刪除掉。

          另外在流式的策略上,maxUnavailable 是用于 Standard 類(lèi)型的,對(duì)應(yīng)了在滾動(dòng)升級(jí)時(shí)最多在多少個(gè) Node 上刪除 Pod。而 maxSurge 策略是用于 Surging 類(lèi)型的,對(duì)應(yīng)了在滾動(dòng)升級(jí)時(shí)最多在多少個(gè) Node 上多擴(kuò)出一個(gè) Pod。

          5. 發(fā)布暫停


          此外,Advanced DaemonSet 還支持了 paused 一鍵暫停發(fā)布。這個(gè)比較好理解,就不細(xì)表述了。

          apiVersion: apps.kruise.io/v1alpha1kind: DaemonSetspec:  # ...  updateStrategy:    rollingUpdate:      paused: true

          總結(jié)


          總的來(lái)看,OpenKruise 在原生 DaemonSet 基礎(chǔ)上增加了一系列面向生產(chǎn)場(chǎng)景的發(fā)布策略,讓 DaemonSet 的升級(jí)過(guò)程更加安全、可控、自動(dòng)化。


          后續(xù) OpenKruise 還會(huì)持續(xù)在應(yīng)用部署/發(fā)布能力上做出更深的優(yōu)化,我們也歡迎每一位云原生愛(ài)好者來(lái)共同參與 OpenKruise 的建設(shè)。與其他一些開(kāi)源項(xiàng)目不同,OpenKruise 并不是阿里內(nèi)部代碼的復(fù)刻;恰恰相反,OpenKruise Github 倉(cāng)庫(kù)是阿里內(nèi)部代碼庫(kù)的 upstream。因此,每一行你貢獻(xiàn)的代碼,都將運(yùn)行在阿里內(nèi)部的所有 Kubernetes 集群中、都將共同支撐了阿里巴巴全球頂尖規(guī)模的云原生應(yīng)用場(chǎng)景!

          瀏覽 48
          點(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>
                  亚洲青娱乐精品91 | 俺来也俺也去成人女优 | 国产日比视频 | 西西4444www无码大胆 | 国产一级内射视频 |