細(xì)述Kubernetes和Docker容器的存儲方式
目前,容器存儲是容器離不開的一個話題,對于無狀態(tài)的Docker容器,容器重啟時容器數(shù)據(jù)會自動清除,一些靜態(tài)的數(shù)據(jù)我們可以通過配置文件或者在容器build時直接寫死。但是對于數(shù)據(jù)庫、日志文件等可以實(shí)時變化的數(shù)據(jù),我們不能夠通過這種方法存取,容器的存儲大多支持Docker或Kubernetes的Volume(數(shù)據(jù)卷),因此我們下文先介紹這兩種Volume的原理。
Docker的容器卷插件
Docker V1.8正式發(fā)布了容器卷插件 (Volume Plugin) 的規(guī)范,允許第三方廠商的數(shù)據(jù)卷在Docker引擎中提供數(shù)據(jù)服務(wù),使得外置存儲可以超過容器的生命周期而獨(dú)立存在。這意味著各種存儲設(shè)備只要滿足接口API的標(biāo)準(zhǔn),就可以接入Docker容器的運(yùn)行平臺中。Volume Plugin的接口規(guī)范定義了5中操作,如下表所示:
這個規(guī)范定義非常簡潔,現(xiàn)有的各種存儲可以通過簡單的驅(qū)動程序封裝,從而實(shí)現(xiàn)和Docker容器的對接。可以說,驅(qū)動程序?qū)崿F(xiàn)了和容器引擎的北向接口,底層則調(diào)用后端存儲的功能完成數(shù)據(jù)存取等任務(wù)。還有不少存儲方案實(shí)現(xiàn)了額外的高端功能,如容器數(shù)據(jù)卷遷移等,這部分功能不在Docker的卷插件規(guī)范當(dāng)中,可通過存儲自身的管理工具來使用。目前已經(jīng)實(shí)現(xiàn)的Docker Volume Plugin中,后端存儲包括常見的NFS, CIFS, GlusterFS和塊設(shè)備等。
Kubernetes的容器卷
Kubernetes是開源的容器集群管理平臺,可以自動化部署、擴(kuò)展和運(yùn)維容器應(yīng)用。Kubernetes的調(diào)度單位稱作“Pod”(豆莢),每個Pod代表一個應(yīng)用,包含一個或多個容器。Pod可部署在集群的任意節(jié)點(diǎn)中,存儲設(shè)備可以通過數(shù)據(jù)卷(Volume)提供給Pod的容器使用。Kubernetes底層支持Docker的容器運(yùn)行引擎,為了不綁定在特定的容器技術(shù)上,Kubernetes沒有使用Docker的Volume機(jī)制,而是重新制定了自己的通用數(shù)據(jù)卷插件規(guī)范,以配合不同的容器運(yùn)行時來使用(如Docker和rkt)。
數(shù)據(jù)卷一般可以貫穿Pod的整個生命周期,當(dāng)Pod被平臺刪除的時候,在不同的數(shù)據(jù)卷實(shí)現(xiàn)中,數(shù)據(jù)可能會被保留或移除。如果數(shù)據(jù)被保留的話,其他Pod可以重新把該卷的數(shù)據(jù)加載使用。數(shù)據(jù)卷分為共享和非共享兩種類型,其中非共享型只能被某個節(jié)點(diǎn)掛載使用(如iSCSI,AWS EBS等網(wǎng)絡(luò)塊設(shè)備),共享型則可以讓不同節(jié)點(diǎn)上的多個Pod同時使用(如NFS,GlusterFS,CephFS等網(wǎng)絡(luò)文件系統(tǒng),以及可支持多方讀寫的塊設(shè)備)。對有狀態(tài)的應(yīng)用來說,共享型的卷存儲能夠很方便地支持容器在集群各節(jié)點(diǎn)之間的遷移。
Kubernetes的數(shù)據(jù)卷可把外部預(yù)創(chuàng)建的數(shù)據(jù)卷接入Pod里面,在這個過程中,Pod無法對數(shù)據(jù)卷配置參數(shù)(如卷大小,IOPS等),因?yàn)檫@些參數(shù)是由提供數(shù)據(jù)卷的存儲預(yù)先設(shè)定的,這有點(diǎn)象傳統(tǒng)存儲先劃分?jǐn)?shù)據(jù)卷,再供給應(yīng)用掛載使用。為了給容器提供更細(xì)粒度的卷管理,Kubernetes增加了持久化卷PV(Persistent Volume)的功能,把外置存儲作為資源池,由平臺管理并提供給整個集群使用。每個PV具有一些可被平臺感知的存儲能力,如卷容量(storage size),讀寫訪問模式(access mode)等。當(dāng)Pod需要存儲時,可以向平臺請求所需要存儲資源,該請求稱作PVC (Persistent Volume Claim)。PVC內(nèi)容包括訪問模式、容量大小等信息。平臺根據(jù)請求的資源屬性(如卷大小等)匹配合適的資源并分配給Pod,并把數(shù)據(jù)卷掛載到Pod所在的主機(jī)中供Pod使用(如下圖所示)。
Kubernetes的Persistent Volume功能還在不斷發(fā)展中,目前PV僅支持存儲容量(storage size)的能力(capacity),今后還可能支持IOPS,吞吐量等存儲能力,以便配置更豐富的存儲策略。Kubernetes的卷管理架構(gòu)使得存儲可用標(biāo)準(zhǔn)的接入方式,并且通過接口暴露存儲設(shè)備所支持的能力,從而在容器任務(wù)調(diào)度等方面實(shí)現(xiàn)了自動化管理。
Flocker
為了給容器應(yīng)用提供文件卷存儲,比較簡單的方式是在重用傳統(tǒng)存儲的基礎(chǔ)上,加上適配容器規(guī)范的相應(yīng)接口。使用這種方式的容器存儲很多,如適配Docker的GlusterFS, NFS, CIFS的卷插件。下文介紹的Flocker也是這種模式的開源容器卷管理器,它提供了在集群中管理和編排容器數(shù)據(jù)卷的方案,并依靠后端的共享塊存儲提供數(shù)據(jù)卷跨主機(jī)的能力。
如上圖所示,F(xiàn)locker由控制服務(wù)作為總控制器,對外提供REST API接口,負(fù)責(zé)維持和更新系統(tǒng)的狀態(tài)。Flocker Agent安裝在集群的每個節(jié)點(diǎn)上,負(fù)責(zé)確保每個節(jié)點(diǎn)上的本地狀態(tài)符合系統(tǒng)期待的狀態(tài),如果發(fā)現(xiàn)本地狀態(tài)和期待狀態(tài)不符,F(xiàn)locker Agent將采取必要的糾正措施,使得節(jié)點(diǎn)上的數(shù)據(jù)卷與集群系統(tǒng)的配置實(shí)現(xiàn)最終一致性(eventual consistency)。Flocker Plugin也部署在每個節(jié)點(diǎn)上,主要以插件形式與Docker、Kubernetes等容器平臺的集成,不僅讓容器可以使用Flocker提供的數(shù)據(jù)卷,還能夠支持容器的遷移。
例如,在Kubernetes中,當(dāng)Pod所在的主機(jī)失效之后,Kubernetes會把Pod重新調(diào)度(遷移)到另一臺主機(jī)上,相應(yīng)地,F(xiàn)locker把Pod在原主機(jī)上的數(shù)據(jù)卷釋放出來,并且在新主機(jī)中重新掛載給該P(yáng)od。這樣,有狀態(tài)容器在遷移主機(jī)的時候,其數(shù)據(jù)卷也能夠跟隨著容器一起移動。
Flocker后端可采用各種常見的網(wǎng)絡(luò)塊設(shè)備,包括AWS EBS,OpenStack Cinder,EMC、DELL、NetApp、VMware VSAN/vVOL等,這些塊設(shè)備配上驅(qū)動程序,即可由Flocker生成數(shù)據(jù)卷(文件目錄形式),掛接到任意的主機(jī)上,再通過卷插件的接口,把數(shù)據(jù)卷提供給容器應(yīng)用。
Portworx
Portworx開發(fā)了容器感知的軟件定義存儲系統(tǒng),稱為CDS (Container-Defined Storage)。在Portworx的CDS存儲中,采用的是計(jì)算和存儲融合的架構(gòu),把集群中所有節(jié)點(diǎn)的本地存儲聚合成大的資源池,使得每個節(jié)點(diǎn)既提供計(jì)算能力,也提供本地磁盤作為存儲,這樣運(yùn)行在節(jié)點(diǎn)中的容器可從本地直接訪問數(shù)據(jù)。
任何存儲都要保證數(shù)據(jù)的完整性和可靠性,由于Portworx采用分布式存儲架構(gòu),與Ceph、VMware Virtual SAN等類似,需要在多節(jié)點(diǎn)之間進(jìn)行數(shù)據(jù)復(fù)制。如上圖所示,當(dāng)數(shù)據(jù)在本地寫入的時候,根據(jù)存儲設(shè)定的參數(shù),可以把數(shù)據(jù)復(fù)制到其他若干個節(jié)點(diǎn)中,從而在集群中存有多個數(shù)據(jù)副本,確保了數(shù)據(jù)的可用性和可靠性。如果某個節(jié)點(diǎn)出現(xiàn)故障或進(jìn)行下線維護(hù),該節(jié)點(diǎn)上的容器可以被上層的調(diào)度器重新調(diào)度到其他節(jié)點(diǎn)上。因?yàn)閿?shù)據(jù)已經(jīng)復(fù)制到了多個節(jié)點(diǎn),容器在新節(jié)點(diǎn)上可直接使用本地?cái)?shù)據(jù),提高了數(shù)據(jù)訪問的效率(如下圖所示)。
Portworx還設(shè)計(jì)了面向容器卷的存儲策略,在創(chuàng)建數(shù)據(jù)卷的時候可以動態(tài)設(shè)置,這些策略如下所示:
通過設(shè)置上述存儲屬性的配置,容器卷的QoS等需求可以動態(tài)滿足,與傳統(tǒng)的SAN等塊存儲有很重要的區(qū)別:這些策略是以容器卷的粒度進(jìn)行配置的,能夠很好地符合容器應(yīng)用的需求,所以稱為容器定義的存儲(Container Defined Storage),是為容器應(yīng)用量身定制的軟件定義存儲。目前,Portworx在架構(gòu)上實(shí)現(xiàn)了軟件定義存儲的控制平面和數(shù)據(jù)平面。盡管許多功能還在不斷完善之中,但是我們還是可以看出下一代面向容器的軟件定義存儲的雛形。