新聞中心
StatefulSet是k8s中有狀態(tài)應(yīng)用管理的標(biāo)準(zhǔn)實(shí)現(xiàn),今天就一起來(lái)了解下其背后設(shè)計(jì)的場(chǎng)景與原理,從而了解其適用范圍與場(chǎng)景。

豐順ssl適用于網(wǎng)站、小程序/APP、API接口等需要進(jìn)行數(shù)據(jù)傳輸應(yīng)用場(chǎng)景,ssl證書(shū)未來(lái)市場(chǎng)廣闊!成為創(chuàng)新互聯(lián)的ssl證書(shū)銷售渠道,可以享受市場(chǎng)價(jià)格4-6折優(yōu)惠!如果有意向歡迎電話聯(lián)系或者加微信:028-86922220(備注:SSL證書(shū)合作)期待與您的合作!
1. 基礎(chǔ)概念
首先介紹有狀態(tài)應(yīng)用里面的需要考慮的一些基礎(chǔ)的事情,然后在下一章我們?cè)偃タ磗tatefulSet的關(guān)鍵實(shí)現(xiàn)。
1.1 有狀態(tài)與無(wú)狀態(tài)
在日常開(kāi)發(fā)的應(yīng)用中,通??梢苑譃閮纱箢悾河袪顟B(tài)與無(wú)狀態(tài),比如web服務(wù)通常都是無(wú)狀態(tài)的,web應(yīng)用數(shù)據(jù)主要來(lái)自后端存儲(chǔ)、緩存等中間件,而本身并不保存數(shù); 而諸如redis、es等其數(shù)據(jù)也是應(yīng)用自身的一部分,由此可以看出有狀態(tài)應(yīng)用本身會(huì)包含兩部分:應(yīng)用與數(shù)據(jù)。
1.2 一致性與數(shù)據(jù)
一致性是分布式系統(tǒng)中很常見(jiàn)的問(wèn)題,上面提到有狀態(tài)應(yīng)用包含數(shù)據(jù)部分,那數(shù)據(jù)和一致性是不是一個(gè)東西呢?答案是并不一定,在諸如zookeeper等應(yīng)用中,會(huì)通過(guò)zab協(xié)議保證數(shù)據(jù)寫(xiě)入到集群中的大多數(shù)節(jié)點(diǎn), 而在諸如kafka之類的應(yīng)用其一致性設(shè)計(jì)要求相對(duì)較低,由此可以看出有狀態(tài)應(yīng)用數(shù)據(jù)的一致性,更多的是由對(duì)應(yīng)場(chǎng)景的系統(tǒng)設(shè)計(jì)而決定。
1.3 身份標(biāo)識(shí)
在一些應(yīng)用中身份標(biāo)識(shí)是系統(tǒng)本身組成的一部分,比如zookeeper其通過(guò)server的id來(lái)影響最終的zab協(xié)議的選舉,在kafka中分區(qū)的分配時(shí)也是按照對(duì)應(yīng)的id來(lái)分配的。
1.4 單調(diào)有序更新
通常分布式系統(tǒng)中都至少要保證分區(qū)容忍性,以防止部分節(jié)點(diǎn)故障導(dǎo)致整個(gè)系統(tǒng)不可用,在k8s中的statefulset中的 Pod的管理策略則是保證盡可能安全的逐個(gè)Pod更新,而不是并行啟動(dòng)或停止所有的Pod。
1.5 擴(kuò)縮容與故障轉(zhuǎn)移
在k8s中水平方向上的擴(kuò)容和縮容都非常簡(jiǎn)單,刪除和添加一個(gè)Pod的事情,但是對(duì)于有狀態(tài)應(yīng)用,其實(shí)就不知這些,比如擴(kuò)容后的數(shù)據(jù)如何做平衡,節(jié)點(diǎn)失敗后的故障轉(zhuǎn)移怎么做,這些都是要一個(gè)有狀態(tài)應(yīng)用需要自己考慮的事情。
2. 核心實(shí)現(xiàn)
StatefulSet的實(shí)現(xiàn)機(jī)制整體流程相對(duì)簡(jiǎn)明,接下來(lái)按照Pod管理、狀態(tài)計(jì)算、狀態(tài)管理、更新策略這幾部分來(lái)依次講解。
2.1 Pod的release與adopt
statefulSet中的pod的名字都是按照一定規(guī)律來(lái)進(jìn)行設(shè)置的, 名字本身也有含義, k8s在進(jìn)行statefulset更新的時(shí)候,首先會(huì)過(guò)濾屬于當(dāng)前statefulset的pod,并做如下操作
K8s中控制器與Pod的關(guān)聯(lián)主要通過(guò)兩個(gè)部分:controllerRef和label, statefulset在進(jìn)行Pod過(guò)濾的時(shí)候,如果發(fā)現(xiàn)對(duì)應(yīng)的pod的controllerRef都是當(dāng)前的statefulset但是其label或者名字并不匹配,則就會(huì)嘗試release對(duì)應(yīng)的Pod。
反之如果發(fā)現(xiàn)對(duì)應(yīng)Pod的label和名字都匹配,但是controllerRef并不是當(dāng)前的statefulSet就會(huì)更新對(duì)應(yīng)的controllerRef為當(dāng)前的statefulset, 這個(gè)操作被稱為adopt。
通過(guò)該流程可以確保當(dāng)前statefulset關(guān)聯(lián)的Pod要么與當(dāng)前的對(duì)象關(guān)聯(lián),要么我就釋放你,這樣可以維護(hù)Pod的一致性,即時(shí)有人修改了對(duì)應(yīng)的Pod則也會(huì)調(diào)整成最終一致性。
2.2 副本分類
在經(jīng)過(guò)第一步的Pod狀態(tài)的修正之后,statefulset會(huì)遍歷所有屬于自己的Pod,同時(shí)將Pod分為兩個(gè)大類:有效副本和無(wú)效副本(condemned),前面提到過(guò)Pod的名字也是有序的即有N個(gè)副本的Pod則名字依次是{0...N-1}, 這里區(qū)分有效和無(wú)效也是依據(jù)對(duì)應(yīng)的索引順序,如果超過(guò)當(dāng)前的副本即為無(wú)效副本。
2.3 單調(diào)更新
單調(diào)更新主要是指的當(dāng)對(duì)應(yīng)的Pod管理策略不是并行管理的時(shí)候,只要當(dāng)前Replicas(有效副本)中任一一個(gè)Pod發(fā)生創(chuàng)建、終止、未就緒的時(shí)候,都會(huì)等待對(duì)應(yīng)的Pod就緒,即你要想更新一個(gè)statefulset的Pod的時(shí)候,對(duì)應(yīng)的Pod必須已經(jīng)RunningAndReady。
- func allowsBurst(set *apps.StatefulSet) bool {
- return set.Spec.PodManagementPolicy == apps.ParallelPodManagement
- }
2.4 基于計(jì)數(shù)器的滾動(dòng)更新
滾動(dòng)更新的實(shí)現(xiàn)相對(duì)隱晦一點(diǎn),其主要是通過(guò)控制副本計(jì)數(shù)來(lái)實(shí)現(xiàn),首先倒序檢查對(duì)應(yīng)的Pod的版本是否是很新版本,如果發(fā)現(xiàn)不是,則直接刪除對(duì)應(yīng)的Pod,同時(shí)將currentReplica計(jì)數(shù)減一,這樣在檢查對(duì)應(yīng)的Pod的時(shí)候,就會(huì)發(fā)現(xiàn)對(duì)應(yīng)的Pod的不存在,就需要為對(duì)應(yīng)的Pod生成新的Pod信息,此時(shí)就會(huì)使用比較新的副本去更新。
- func newVersionedStatefulSetPod(currentSet, updateSet *apps.StatefulSet, currentRevision, updateRevision string, ordinal int) *v1.Pod {
- // 如果發(fā)現(xiàn)當(dāng)前的Pod的索引小于當(dāng)?shù)母北居?jì)數(shù),則表明當(dāng)前Pod還沒(méi)更新到,但實(shí)際上可能因?yàn)閯e的原因
- // 需要重新生成Pod模板,此時(shí)仍然使用舊的副本配置
- if currentSet.Spec.UpdateStrategy.Type == apps.RollingUpdateStatefulSetStrategyType &&
- (currentSet.Spec.UpdateStrategy.RollingUpdate == nil && ordinal < int(currentSet.Status.CurrentReplicas)) ||
- (currentSet.Spec.UpdateStrategy.RollingUpdate != nil && ordinal < int(*currentSet.Spec.UpdateStrategy.RollingUpdate.Partition)) {
- pod := newStatefulSetPod(currentSet, ordinal)
- setPodRevision(pod, currentRevision)
- return pod
- }
- // 使用新的配置生成新的Pod配置
- pod := newStatefulSetPod(updateSet, ordinal)
- setPodRevision(pod, updateRevision)
- return pod
- }
2.5 無(wú)效副本的清理
無(wú)效副本的清理應(yīng)該主要是發(fā)生在對(duì)應(yīng)的statefulset縮容的時(shí)候,如果發(fā)現(xiàn)對(duì)應(yīng)的副本已經(jīng)被遺棄,就會(huì)直接刪除,此處默認(rèn)也需要遵循單調(diào)性原則,即每次都只更新一個(gè)副本。
2.6 基于刪除的單調(diào)性更新
- if getPodRevision(replicas[target]) != updateRevision.Name && !isTerminating(replicas[target]) {
- klog.V(2).Infof("StatefulSet %s/%s terminating Pod %s for update",
- set.Namespace,
- set.Name,
- replicas[target].Name)
- err := ssc.podControl.DeleteStatefulPod(set, replicas[target])
- status.CurrentReplicas--
- return &status, err
- }
Pod的版本檢測(cè)位于對(duì)應(yīng)一致性同步的最后,當(dāng)代碼走到當(dāng)前位置,則證明當(dāng)前的statefulSet在滿足單調(diào)性的情況下,有效副本里面的所有Pod都是RunningAndReady狀態(tài)了,此時(shí)就開(kāi)始倒序進(jìn)行版本檢查,如果發(fā)現(xiàn)版本不一致,就根據(jù)當(dāng)前的partition的數(shù)量來(lái)決定允許并行更新的數(shù)量,在這里刪除后,就會(huì)觸發(fā)對(duì)應(yīng)的事件,從而觸發(fā)下一個(gè)調(diào)度事件,觸發(fā)下一輪一致性檢查。
2.7 OnDelete策略
- if set.Spec.UpdateStrategy.Type == apps.OnDeleteStatefulSetStrategyType {
- return &status, nil
- }
StatefulSet的更新策略除了RollingUpdate還有一種即OnDelete即必須人工刪除對(duì)應(yīng)的 Pod來(lái)觸發(fā)一致性檢查,所以針對(duì)那些如果想只更新指定索引的statefulset可以嘗試該策略,每次只刪除對(duì)應(yīng)的索引,這樣只有指定的索引會(huì)更新為很新的版本。
2.8 狀態(tài)存儲(chǔ)
狀態(tài)存儲(chǔ)其實(shí)就是我們常說(shuō)的PVC,在Pod創(chuàng)建和更新的時(shí)候,如果發(fā)現(xiàn)對(duì)應(yīng)的PVC的不存在則就會(huì)根據(jù)statefulset里面的配置創(chuàng)建對(duì)應(yīng)的PVC,并更新對(duì)應(yīng)Pod的配置。
3. 有狀態(tài)應(yīng)用總結(jié)
從核心實(shí)現(xiàn)分析中可以看出來(lái),有狀態(tài)應(yīng)用的實(shí)現(xiàn),實(shí)際上核心是基于一致性狀態(tài)、單調(diào)更新、持久化存儲(chǔ)的組合,通過(guò)一致性狀態(tài)、單調(diào)性更新,保證期望副本的數(shù)量的Pod處于RunningAndReady的狀態(tài)并且保證有序性,同時(shí)通過(guò)持久化存儲(chǔ)來(lái)進(jìn)行數(shù)據(jù)的保存。
有序的重要性,在分布式系統(tǒng)中比較常見(jiàn)的兩個(gè)設(shè)計(jì)就是分區(qū)和副本,其中副本主要是為了保證可用性,而分區(qū)主要是進(jìn)行數(shù)據(jù)的平均分布,二者通常都是根據(jù)當(dāng)前集群中的節(jié)點(diǎn)來(lái)進(jìn)行分配的,如果我們節(jié)點(diǎn)短暫的離線升級(jí),數(shù)據(jù)保存在對(duì)應(yīng)的PVC中,在恢復(fù)后可以很快的進(jìn)行節(jié)點(diǎn)的信息的恢復(fù)并重新加入集群,所以后面如果開(kāi)發(fā)這種類似的分布式應(yīng)用的時(shí)候,可以將底層的恢復(fù)和管理交給k8s,數(shù)據(jù)保存在PVC中,則應(yīng)用更多的只需要關(guān)注系統(tǒng)的集群管理和數(shù)據(jù)分布問(wèn)題即,這也是云原生帶來(lái)的改變。
今天就到這里,好久沒(méi)更新了,讀源碼的過(guò)程不易,歡迎幫轉(zhuǎn)發(fā)分享交流,一起進(jìn)步。
文章標(biāo)題:圖解kubernetes控制器StatefulSet核心實(shí)現(xiàn)原理
標(biāo)題來(lái)源:http://www.fisionsoft.com.cn/article/dhgohge.html


咨詢
建站咨詢
