前言
在K8S運(yùn)行的服務(wù),從簡(jiǎn)單到復(fù)雜可以分成三類:無(wú)狀態(tài)服務(wù)、普通有狀態(tài)服務(wù)和有狀態(tài)集群服務(wù)。下面分別來(lái)看K8S是如何運(yùn)行這三類服務(wù)的。
- 無(wú)狀態(tài)服務(wù)
K8S使用RC(或更新的Replica Set)來(lái)保證一個(gè)服務(wù)的實(shí)例數(shù)量,如果說(shuō)某個(gè)Pod實(shí)例由于某種原因Crash了,RC會(huì)立刻用這個(gè)Pod的模版新啟一個(gè)Pod來(lái)替代它,由于是無(wú)狀態(tài)的服務(wù),新啟的Pod與原來(lái)健康狀態(tài)下的Pod一模一樣。在Pod被重建后它的IP地址可能發(fā)生變化,為了對(duì)外提供一個(gè)穩(wěn)定的訪問(wèn)接口,K8S引入了Service的概念重點(diǎn)內(nèi)容。一個(gè)Service后面可以掛多個(gè)Pod,實(shí)現(xiàn)服務(wù)的高可用。 - 普通有狀態(tài)服務(wù)
和無(wú)狀態(tài)服務(wù)相比,它多了狀態(tài)保存的需求。Kubernetes提供了以Volume和Persistent Volume為基礎(chǔ)的存儲(chǔ)系統(tǒng),可以實(shí)現(xiàn)服務(wù)的狀態(tài)保存。 - 有狀態(tài)集群服務(wù)(StatefulSet)
與普通有狀態(tài)服務(wù)相比,它多了集群管理的需求。K8S為此開發(fā)了一套以Pet Set為核心的全新特性,方便了有狀態(tài)集群服務(wù)在K8S上的部署和管理。具體來(lái)說(shuō)是通過(guò)Init Container來(lái)做集群的初始化工作.用 Headless Service 來(lái)維持集群成員的穩(wěn)定關(guān)系,用動(dòng)態(tài)存儲(chǔ)供給來(lái)方便集群擴(kuò)容,最后用Pet Set來(lái)綜合管理整個(gè)集群。要運(yùn)行有狀態(tài)集群服務(wù)要解決的問(wèn)題有兩個(gè),一個(gè)是狀態(tài)保存,另個(gè)是集群管理。 我們先來(lái)看如何解決第一個(gè)問(wèn)題:狀態(tài)保存.Kubernetes 有一套以Volume插件為基礎(chǔ)的存儲(chǔ)系統(tǒng),通過(guò)這套存儲(chǔ)系統(tǒng)可以實(shí)現(xiàn)應(yīng)用和服務(wù)的狀態(tài)保存。
K8S存儲(chǔ)系統(tǒng)
K8S的存儲(chǔ)系統(tǒng)從基礎(chǔ)到高級(jí)又大致分為三個(gè)層次:普通Volume,Persistent Volume 和動(dòng)態(tài)存儲(chǔ)供應(yīng)(dynamic provisioning)。
普通Volume
單節(jié)點(diǎn)Volume
單節(jié)點(diǎn)Volume是最簡(jiǎn)單的普通Volume,它和Docker的存儲(chǔ)卷類似,使用的是Pod所在K8S節(jié)點(diǎn)的本地目錄。具體有兩種,一種是 emptyDir,是一個(gè)匿名的空目錄,由Kubernetes在創(chuàng)建Pod時(shí)創(chuàng)建,刪除Pod時(shí)刪除。另外一種是 hostPath,與emptyDir的區(qū)別是,它在Pod之外獨(dú)立存在,由用戶指定路徑名。這類和節(jié)點(diǎn)綁定的存儲(chǔ)卷在Pod遷移到其它節(jié)點(diǎn)后數(shù)據(jù)就會(huì)丟失,所以只能用于存儲(chǔ)臨時(shí)數(shù)據(jù)或用于在同一個(gè)Pod里的容器之間共享數(shù)據(jù)。
跨節(jié)點(diǎn)存儲(chǔ)卷
這種存儲(chǔ)卷不和某個(gè)具體的K8S節(jié)點(diǎn)綁定,而是獨(dú)立于K8S節(jié)點(diǎn)存在的,整個(gè)存儲(chǔ)集群和K8S集群是兩個(gè)集群,相互獨(dú)立。
跨節(jié)點(diǎn)的存儲(chǔ)卷在Kubernetes上用的比較多,如果已有的存儲(chǔ)不能滿足要求,還可以開發(fā)自己的Volume插件,只需要實(shí)現(xiàn)Volume.go 里定義的接口。如果你是一個(gè)存儲(chǔ)廠商,想要自己的存儲(chǔ)支持Kubernetes 上運(yùn)行的容器,就可以去開發(fā)一個(gè)自己的Volume插件。普通volume目前支持的各種存儲(chǔ)插件及情況如下:

persistent volume 和普通Volume的區(qū)別
普通Volume和使用它的Pod之間是一種靜態(tài)綁定關(guān)系,在定義Pod的文件里,同時(shí)定義了它使用的Volume。Volume 是Pod的附屬品,我們無(wú)法單獨(dú)創(chuàng)建一個(gè)Volume,因?yàn)樗皇且粋€(gè)獨(dú)立的K8S資源對(duì)象。
而Persistent Volume 簡(jiǎn)稱PV是一個(gè)K8S資源對(duì)象,所以我們可以單獨(dú)創(chuàng)建一個(gè)PV。它不和Pod直接發(fā)生關(guān)系,而是通過(guò)Persistent Volume Claim,簡(jiǎn)稱PVC來(lái)實(shí)現(xiàn)動(dòng)態(tài)綁定。Pod定義里指定的是PVC,然后PVC會(huì)根據(jù)Pod的要求去自動(dòng)綁定合適的PV給Pod使用。
綁定的概念
用戶根據(jù)所需存儲(chǔ)空間大小和訪問(wèn)模式創(chuàng)建(或在動(dòng)態(tài)部署中已創(chuàng)建)一個(gè) PersistentVolumeClaim。Kubernetes的Master節(jié)點(diǎn)循環(huán)監(jiān)控新產(chǎn)生的PVC,找到與之匹配的PV(如果有的話),并把他們綁定在一起。動(dòng)態(tài)配置時(shí),循環(huán)會(huì)一直將PV與這個(gè)PVC綁定,直到PV完全匹配PVC。避免PVC請(qǐng)求和得到的PV不一致。綁定一旦形成,PersistentVolumeClaim綁定就是獨(dú)有的,不管是使用何種模式綁定的。
如果找不到匹配的volume,用戶請(qǐng)求會(huì)一直保持未綁定狀態(tài)。在匹配的volume可用之后,用戶請(qǐng)求將會(huì)被綁定。比如,一個(gè)配置了許多50Gi PV的集群不會(huì)匹配到一個(gè)要求100Gi的PVC。 只有在100Gi PV被加到集群之后,這個(gè)PVC才可以被綁定。
PV的訪問(wèn)模式
- ReadWriteOnce:是最基本的方式,可讀可寫,但只支持被單個(gè)Pod掛載。
- ReadOnlyMany:可以以只讀的方式被多個(gè)Pod掛載。
- ReadWriteMany:這種存儲(chǔ)可以以讀寫的方式被多個(gè)Pod共享。
不是每一種存儲(chǔ)都支持這三種方式,像共享方式,目前支持的還比較少,比較常用的是NFS。在PVC綁定PV時(shí)通常根據(jù)兩個(gè)條件來(lái)綁定,一個(gè)是存儲(chǔ)的大小,另一個(gè)就是訪問(wèn)模式。在CLI下,訪問(wèn)方式被簡(jiǎn)寫為:
- RWO – ReadWriteOnce
- ROX – ReadOnlyMany
- RWX – ReadWriteMany
需要注意的是即使同時(shí)支持幾種不同的模式,但綁定時(shí)只能選擇其中的一種。

PV的使用過(guò)程
剛才提到說(shuō)PV與普通Volume的區(qū)別是動(dòng)態(tài)綁定,我們來(lái)看一下這個(gè)過(guò)程是怎樣的。

這是PV的生命周期,首先是Provision,即創(chuàng)建PV。
一個(gè)PV創(chuàng)建完后狀態(tài)會(huì)變成Available,等待被PVC綁定。一旦被PVC邦定,PV的狀態(tài)會(huì)變成Bound,就可以被定義了相應(yīng)PVC的Pod使用。Pod使用完后會(huì)釋放PV,PV的狀態(tài)變成Released。變成Released的PV會(huì)根據(jù)定義的回收策略做相應(yīng)的回收工作。有三種回收策略,Retain、Delete 和 Recycle。
- Retain就是保留現(xiàn)場(chǎng),K8S什么也不做,等待用戶手動(dòng)去處理PV里的數(shù)據(jù),處理完后,再手動(dòng)刪除PV。
- Delete 策略,K8S會(huì)自動(dòng)刪除該P(yáng)V及里面的數(shù)據(jù)。
- Recycle方式,K8S會(huì)將PV里的數(shù)據(jù)刪除,然后把PV的狀態(tài)變成Available,又可以被新的PVC綁定使用。
在使用過(guò)程中卷又有以下四種狀態(tài)
- Available –閑置狀態(tài),沒(méi)有被綁定到PVC
- Bound – 綁定到PVC
- Released – PVC被刪掉,資源沒(méi)有被在利用
- Failed – 自動(dòng)回收失敗
動(dòng)態(tài)存儲(chǔ)供應(yīng)(Storage class)
創(chuàng)建PV有兩種方式,靜態(tài)和動(dòng)態(tài)。
靜態(tài),是管理員手動(dòng)創(chuàng)建一堆PV,組成一個(gè)PV池,供PVC來(lái)綁定。
動(dòng)態(tài),是指在現(xiàn)有PV不滿足PVC的請(qǐng)求時(shí),可以使用存儲(chǔ)分類(StorageClass),描述具體過(guò)程為:PV先創(chuàng)建分類,PVC請(qǐng)求已創(chuàng)建的某個(gè)類(StorageClass)的資源,這樣就達(dá)到動(dòng)態(tài)配置的效果。即通過(guò)一個(gè)叫 Storage Class的對(duì)象由存儲(chǔ)系統(tǒng)根據(jù)PVC的要求自動(dòng)創(chuàng)建。
使用StorageClass的好處
在實(shí)際使用場(chǎng)景里,PV的創(chuàng)建和使用通常不是同一個(gè)人。這里有一個(gè)典型的應(yīng)用場(chǎng)景:管理員創(chuàng)建一個(gè)PV池,開發(fā)人員創(chuàng)建Pod和PVC,PVC里定義了Pod所需存儲(chǔ)的大小和訪問(wèn)模式,然后PVC會(huì)到PV池里自動(dòng)匹配最合適的PV給Pod使用。
除了由存儲(chǔ)系統(tǒng)動(dòng)態(tài)創(chuàng)建,節(jié)省了管理員的時(shí)間,還有一個(gè)好處是可以封裝不同類型的存儲(chǔ)供PVC選用。在StorageClass出現(xiàn)以前,PVC綁定一個(gè)PV只能根據(jù)兩個(gè)條件,一個(gè)是存儲(chǔ)的大小,另一個(gè)是訪問(wèn)模式。在StorageClass出現(xiàn)后,等于增加了一個(gè)綁定維度。
比如這里就有兩個(gè)StorageClass,它們都是用谷歌的存儲(chǔ)系統(tǒng),但是一個(gè)使用的是普通磁盤,我們把這個(gè)StorageClass命名為slow。另一個(gè)使用的是SSD,我們把它命名為fast。

在PVC里除了常規(guī)的大小、訪問(wèn)模式的要求外,還通過(guò)annotation指定了Storage Class的名字為fast,這樣這個(gè)PVC就會(huì)綁定一個(gè)SSD,而不會(huì)綁定一個(gè)普通的磁盤。

缺省行為
所有的 PVC 都可以在不使用 StorageClass 注解的情況下,直接使用某個(gè)動(dòng)態(tài)存儲(chǔ)。把一個(gè)StorageClass 對(duì)象標(biāo)記為 “default” 就可以了。StorageClass 用注解storageclass.beta.kubernetes.io/is-default-class 就可以成為缺省存儲(chǔ)。
有了缺省的 StorageClass,用戶創(chuàng)建 PVC 就不用 storage-class 的注解了,1.4 中新加入的DefaultStorageClass 準(zhǔn)入控制器會(huì)自動(dòng)把這個(gè)標(biāo)注指向缺省存儲(chǔ)類。
到這里Kubernetes的整個(gè)存儲(chǔ)系統(tǒng)就都介紹完了。總結(jié)一下,兩種存儲(chǔ)卷:普通Volume 和Persistent Volume。普通Volume在定義Pod的時(shí)候直接定義,Persistent Volume通過(guò)Persistent Volume Claim來(lái)動(dòng)態(tài)綁定。PV可以手動(dòng)創(chuàng)建,也可以通過(guò)StorageClass來(lái)動(dòng)態(tài)創(chuàng)建。
來(lái)源
文章整理自 csdn