10.2 了解Statefulset

10.2 了解Statefulset

可以創(chuàng)建一個(gè)Statefulset資源替代ReplicaSet來運(yùn)行這類pod。它是專門定制的一類應(yīng)用,這類應(yīng)用中每一個(gè)實(shí)例都是不可替代的個(gè)體,都擁有穩(wěn)定的名字和狀態(tài)。

10.2.1 對比Statefulset和ReplicaSet

要很好地理解Statefulset的用途,最好先與ReplicaSet或ReplicationControllers對比一下。首先拿一個(gè)通用的類比來解釋它們。

通過寵物與牛的類比來理解有狀態(tài)

你可能已經(jīng)聽說過寵物與牛的類比。如果沒有,先簡單介紹一下??梢园盐覀兊膽?yīng)用看作寵物或牛。

注意 Statefulset最初被稱為PetSet,這個(gè)名字來源于寵物與牛的類比。

我們傾向于把應(yīng)用看作寵物,給每個(gè)實(shí)例起一個(gè)名字,細(xì)心照顧每個(gè)實(shí)例。但是也許把它們看成牛更為合適,并不需要對單獨(dú)的實(shí)例有太多關(guān)心。這樣就可以非常方便地替換掉不健康的實(shí)例,就跟農(nóng)場主替換掉一頭生病的牛一樣。

對于無狀態(tài)的應(yīng)用實(shí)例來說,行為非常像農(nóng)場里的牛。一個(gè)實(shí)例掛掉后并沒什么影響,可以創(chuàng)建一個(gè)新實(shí)例,而讓用戶完全無感知。

另一方面,有狀態(tài)的應(yīng)用的一個(gè)實(shí)例更像一個(gè)寵物。若一只寵物死掉,不能買到一只完全一樣的,而不讓用戶感知到。若要替換掉這只寵物,需要找到一只行為舉止與之完全一致的寵物。對應(yīng)用來說,意味著新的實(shí)例需要擁有跟舊的案例完全一致的狀態(tài)和標(biāo)識。

Statefulset與ReplicaSet或ReplicationController的對比

RelicaSet或ReplicationController管理的pod副本比較像牛,這是因?yàn)樗鼈兌际菬o狀態(tài)的,任何時(shí)候它們都可以被一個(gè)全新的pod替換。然而有狀態(tài)的pod需要不同的方法,當(dāng)一個(gè)有狀態(tài)的pod掛掉后(或者它所在的節(jié)點(diǎn)故障),這個(gè)pod實(shí)例需要在別的節(jié)點(diǎn)上重建,但是新的實(shí)例必須與被替換的實(shí)例擁有相同的名稱、網(wǎng)絡(luò)標(biāo)識和狀態(tài)。這就是StatefulSet如何管理pod的。

Statefulset保證了pod在重新調(diào)度后保留它們的標(biāo)識和狀態(tài)。它讓你方便地?cái)U(kuò)容、縮容。與ReplicaSet類似,Statefulset也會(huì)指定期望的副本個(gè)數(shù),它決定了在同一時(shí)間內(nèi)運(yùn)行的寵物的數(shù)量。與ReplicaSet類似,pod也是依據(jù)Statefulset的pod模板創(chuàng)建的(想象一下曲奇餅干模板)。與ReplicaSet不同的是,Statefulset創(chuàng)建的pod副本并不是完全一樣的。每個(gè)pod都可以擁有一組獨(dú)立的數(shù)據(jù)卷(持久化狀態(tài))而有所區(qū)別。另外“寵物”pod的名字都是規(guī)律的(固定的),而不是每個(gè)新pod都隨機(jī)獲取一個(gè)名字。

10.2.2 提供穩(wěn)定的網(wǎng)絡(luò)標(biāo)識

一個(gè)Statefulset創(chuàng)建的每個(gè)pod都有一個(gè)從零開始的順序索引,這個(gè)會(huì)體現(xiàn)在pod的名稱和主機(jī)名上,同樣還會(huì)體現(xiàn)在pod對應(yīng)的固定存儲(chǔ)上。這些pod的名稱則是可預(yù)知的,因?yàn)樗怯蒘tatefulset的名稱加該實(shí)例的順序索引值組成的。不同于pod隨機(jī)生成一個(gè)名稱,這樣有規(guī)則的pod名稱是很方便管理的,如圖10.5所示。

[圖片上傳失敗...(image-bf81d6-1627605883814)]

圖10.5 與ReplicaSet不同,由Statefulset創(chuàng)建的pod擁有規(guī)則的名稱(和主機(jī)名)

控制服務(wù)介紹

讓pod擁有可預(yù)知的名稱和主機(jī)名并不是全部,與普通的pod不一樣的是,有狀態(tài)的pod有時(shí)候需要通過其主機(jī)名來定位,而無狀態(tài)的pod則不需要,因?yàn)槊總€(gè)無狀態(tài)的pod都是一樣的,在需要的時(shí)候隨便選擇一個(gè)即可。但對于有狀態(tài)的pod來說,因?yàn)樗鼈兌际潜舜瞬煌模ū热鐡碛胁煌臓顟B(tài)),通常希望操作的是其中特定的一個(gè)。

基于以上原因,一個(gè)Statefulset通常要求你創(chuàng)建一個(gè)用來記錄每個(gè)pod網(wǎng)絡(luò)標(biāo)記的headless Service。通過這個(gè)Service,每個(gè)pod將擁有獨(dú)立的DNS記錄,這樣集群里它的伙伴或者客戶端可以通過主機(jī)名方便地找到它。比如說,一個(gè)屬于default命名空間,名為foo的控制服務(wù),它的一個(gè)pod名稱為A-0,那么可以通過下面的完整域名來訪問它:a-0.foo.default.svc.cluster.local。而在ReplicaSet中這樣是行不通的。

另外,也可以通過DNS服務(wù),查找域名foo.default.svc.cluster.local對應(yīng)的所有SRV記錄,獲取一個(gè)Statefulset中所有pod的名稱。我們將在10.4節(jié)中介紹SRV記錄,解釋如何通過它來發(fā)現(xiàn)一個(gè)Statefulset中的所有成員。

替換消失的寵物

當(dāng)一個(gè)Statefulset管理的一個(gè)pod實(shí)例消失后(pod所在節(jié)點(diǎn)發(fā)生故障,或有人手動(dòng)刪除pod),Statefulset會(huì)保證重啟一個(gè)新的pod實(shí)例替換它,這與ReplicaSet類似。但與ReplicaSet不同的是,新的pod會(huì)擁有與之前pod完全一致的名稱和主機(jī)名(ReplicaSet和Statefulset的差異如圖10.6所示)。

img

image

圖10.6 Statefulset使用標(biāo)識完全一致的新的pod替換,ReplicaSet則是使用一個(gè)不相干的新的pod替換

如你之前了解的那樣,pod運(yùn)行在哪個(gè)節(jié)點(diǎn)上并不重要,新的pod并不一定會(huì)調(diào)度到相同的節(jié)點(diǎn)上。對于有狀態(tài)的pod來說也是這樣,即使新的pod被調(diào)度到一個(gè)不同的節(jié)點(diǎn),也同樣可以通過主機(jī)名來訪問。

擴(kuò)縮容Statefulset

擴(kuò)容一個(gè)Statefulset會(huì)使用下一個(gè)還沒用到的順序索引值創(chuàng)建一個(gè)新的pod實(shí)例。比如,要把一個(gè)Statefulset從兩個(gè)實(shí)例擴(kuò)容到三個(gè)實(shí)例,那么新實(shí)例的索引值就會(huì)是2(現(xiàn)有實(shí)例使用的索引值為0和1)。

當(dāng)縮容一個(gè)Statefulset時(shí),比較好的是很明確哪個(gè)pod將要被刪除。作為對比,ReplicaSet的縮容操作則不同,不知道哪個(gè)實(shí)例會(huì)被刪除,也不能指定先刪除哪個(gè)實(shí)例(也許這個(gè)功能會(huì)在將來實(shí)現(xiàn))??s容一個(gè)Statefulset將會(huì)最先刪除最高索引值的實(shí)例(如圖10.7所示),所以縮容的結(jié)果是可預(yù)知的。

[圖片上傳失敗...(image-d8c3f0-1627605883814)]image

圖10.7 縮容一個(gè)Statefulset將會(huì)最先刪除最高索引值的實(shí)例

因?yàn)镾tatefulset縮容任何時(shí)候只會(huì)操作一個(gè)pod實(shí)例,所以有狀態(tài)應(yīng)用的縮容不會(huì)很迅速。舉例來說,一個(gè)分布式存儲(chǔ)應(yīng)用若同時(shí)下線多個(gè)節(jié)點(diǎn),則可能導(dǎo)致其數(shù)據(jù)丟失。比如說一個(gè)數(shù)據(jù)項(xiàng)副本數(shù)設(shè)置為2的數(shù)據(jù)存儲(chǔ)應(yīng)用,若同時(shí)有兩個(gè)節(jié)點(diǎn)下線,一份數(shù)據(jù)記錄就會(huì)丟失,如果它正好保存在這兩個(gè)節(jié)點(diǎn)上。若縮容是線性的,則分布式存儲(chǔ)應(yīng)用就有時(shí)間把丟失的副本復(fù)制到其他節(jié)點(diǎn),保證數(shù)據(jù)不會(huì)丟失。

基于以上原因,Statefulset在有實(shí)例不健康的情況下是不允許做縮容操作的。若一個(gè)實(shí)例是不健康的,而這時(shí)再縮容一個(gè)實(shí)例的話,也就意味著你實(shí)際上同時(shí)失去了兩個(gè)集群成員。

10.2.3 為每個(gè)有狀態(tài)實(shí)例提供穩(wěn)定的專屬存儲(chǔ)

你已經(jīng)知道了Statefulset如何保證一個(gè)有狀態(tài)的pod擁有穩(wěn)定的標(biāo)識,那存儲(chǔ)呢?一個(gè)有狀態(tài)的pod需要擁有自己的存儲(chǔ),即使該有狀態(tài)的pod被重新調(diào)度(新的pod與之前pod的標(biāo)識完全一致),新的實(shí)例也必須掛載著相同的存儲(chǔ)。那Statefulset是如何做到這一點(diǎn)的呢?

很明顯,有狀態(tài)的pod的存儲(chǔ)必須是持久的,并且與pod解耦。在第6章中學(xué)習(xí)了持久卷和持久卷聲明,通過在pod中關(guān)聯(lián)一個(gè)持久卷聲明的名稱,就可以為pod提供持久化存儲(chǔ)。因?yàn)槌志镁砺暶髋c持久卷是一對一的關(guān)系,所以每個(gè)Statefulset的pod都需要關(guān)聯(lián)到不同的持久卷聲明,與獨(dú)自的持久卷相對應(yīng)。因?yàn)樗械膒od實(shí)例都是依據(jù)一個(gè)相同的pod模板創(chuàng)建的,那它們是如何關(guān)聯(lián)到不同的持久卷是的呢?并且由誰來創(chuàng)建這些持久卷是呢?當(dāng)然你肯定不想手在動(dòng)創(chuàng)建Statefulset之前,依據(jù)pod的個(gè)數(shù)創(chuàng)建相同數(shù)量的持久卷量。當(dāng)然不用這么做!

在pod模板中添加卷聲明模板

像Statefulset創(chuàng)建pod一樣,Statefulset也需要?jiǎng)?chuàng)建持久卷聲明。所以一個(gè)Statefulset可以擁有一個(gè)或多個(gè)卷聲明模板,這些持久卷聲明會(huì)在創(chuàng)建pod前創(chuàng)建出來,綁定到一個(gè)pod實(shí)例上(如圖10.8所示)。

img

image

圖10.8 一個(gè)Statefulset創(chuàng)建pod和持久卷聲明

聲明的持久卷既可以通過administrator用戶預(yù)先創(chuàng)建出來,也可以如第6章所述,由持久卷的動(dòng)態(tài)供應(yīng)機(jī)制實(shí)時(shí)創(chuàng)建出來。

持久卷的創(chuàng)建和刪除

擴(kuò)容StatefulSet增加一個(gè)副本數(shù)時(shí),會(huì)創(chuàng)建兩個(gè)或更多的API對象(一個(gè)pod和與之關(guān)聯(lián)的一個(gè)或多個(gè)持久卷聲明)。但是對縮容來說,則只會(huì)刪除一個(gè)pod,而遺留下之前創(chuàng)建的聲明。當(dāng)你知道一個(gè)聲明被刪除會(huì)發(fā)生什么的話,你就明白為什么這么做了。當(dāng)一個(gè)聲明被刪除后,與之綁定的持久卷就會(huì)被回收或刪除,則其上面的數(shù)據(jù)就會(huì)丟失。

因?yàn)橛袪顟B(tài)的pod是用來運(yùn)行有狀態(tài)應(yīng)用的,所以其在數(shù)據(jù)卷上存儲(chǔ)的數(shù)據(jù)非常重要,在Statefulset縮容時(shí)刪除這個(gè)聲明將是災(zāi)難性的,特別是對于Statefulset來說,縮容就像減少其replicas數(shù)值一樣簡單?;谶@個(gè)原因,當(dāng)你需要釋放特定的持久卷時(shí),需要手動(dòng)刪除對應(yīng)的持久卷聲明。

重新掛載持久卷聲明到相同pod的新實(shí)例上

因?yàn)榭s容Statefulset時(shí)會(huì)保留持久卷聲明,所以在隨后的擴(kuò)容操作中,新的pod實(shí)例會(huì)使用綁定在持久卷上的相同聲明和其上的數(shù)據(jù)(如圖10.9所示)。當(dāng)你因?yàn)檎`操作而縮容一個(gè)Statefulset后,可以做一次擴(kuò)容來彌補(bǔ)自己的過失,新的pod實(shí)例會(huì)運(yùn)行到與之前完全一致的狀態(tài)(名字也是一樣的)。

img

image

圖10.9 Statefulset縮容時(shí)不刪除持久卷聲明,擴(kuò)容時(shí)會(huì)重新掛載上

10.2.4 Statefulset的保障

如之前描述的,Statefulset的行為與ReplicaSet是不一樣的。Statefulset不僅擁有穩(wěn)定的標(biāo)記和獨(dú)立的存儲(chǔ),它的pod還有其他的一些保障。

穩(wěn)定標(biāo)識和獨(dú)立存儲(chǔ)的影響

通常來說,無狀態(tài)的pod是可以替代的,而有狀態(tài)的pod則不行。我們之前已經(jīng)描述了一個(gè)有狀態(tài)的pod總是會(huì)被一個(gè)完全一致的pod替換(兩者有相同的名稱、主機(jī)名和存儲(chǔ)等)。這個(gè)替換發(fā)生在Kubernetes發(fā)現(xiàn)舊的pod不存在時(shí)(例如手動(dòng)刪除這個(gè)pod)。

那么當(dāng)Kubernetes不能確定一個(gè)pod的狀態(tài)時(shí)呢?如果它創(chuàng)建一個(gè)完全一致的pod,那系統(tǒng)中就會(huì)有兩個(gè)完全一致的pod在同時(shí)運(yùn)行。這兩個(gè)pod會(huì)綁定到相同的存儲(chǔ),所以這兩個(gè)相同標(biāo)記的進(jìn)程會(huì)同時(shí)寫相同的文件。對于ReplicaSet的pod來說,這不是問題,因?yàn)閼?yīng)用本來就是設(shè)計(jì)為在相同的文件上工作的。并且我們知道ReplicaSet會(huì)以一個(gè)隨機(jī)的標(biāo)識來創(chuàng)建pod,所以不可能存在兩個(gè)相同標(biāo)識的進(jìn)程同時(shí)運(yùn)行。

介紹Statefulset的at-most-one的語義

Kubernetes必須保證兩個(gè)擁有相同標(biāo)記和綁定相同持久卷聲明的有狀態(tài)的pod實(shí)例不會(huì)同時(shí)運(yùn)行。一個(gè)Statefulset必須保證有狀態(tài)的pod實(shí)例的at-most-one語義。

也就是說一個(gè)Statefulset必須在準(zhǔn)確確認(rèn)一個(gè)pod不再運(yùn)行后,才會(huì)去創(chuàng)建它的替換pod。這對如何處理節(jié)點(diǎn)故障有很大的影響,我們會(huì)在本章后面詳細(xì)介紹。在我們做這些之前,需要先創(chuàng)建一個(gè)Statefulset,看看它是如何工作的。在這個(gè)過程中,你會(huì)學(xué)到更多的知識。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容