Kubernetes 有狀態集群服務部署與管理
在容器化時代,除了無狀態的容器服務,比如Web服務器,用戶也越來越多地使用容器部署有狀態的應用,比如MySQL、Redis、Cassandra等。這些Pets(運行有狀態服務的容器,需要特殊處理)就帶來了新的需求,包括更長的生命周期,配置依賴,有狀態的故障轉移等。
本次分享將深入介紹Kubernetes如何滿足有狀態集群服務對容器編排系統提出的新需求,包括如何使用Kubernetes的動態存儲請求與分配機制來實現服務狀態的持久化存儲,以及與高效部署和運行有狀態集群服務相關的Kubernetes新特性,如Init Container、PetSet (StatefulSet)等。最后通過一個MySQL集群實例詳解在Kubernetes中如何輕松部署一個高可用的有狀態集群服務并實現自動化管理。
大綱:
- Kubernetes簡介和運行有狀態集群服務的挑戰
- Kubernetes 存儲系統
- Kubernetes 有狀態集群服務相關特性
- 實戰:在Kubernetes上部署和管理MySQL集群
正文:
在容器化時代,除了無狀態的容器服務,比如Web服務器,用戶也越來越多地使用容器部署有狀態的應用,這就對容器編排系統提出了新的需求。
我今天要和大家分享的主題就是如何在目前主流的容器云平臺Kubernetes 上部署和管理有狀態集群服務。
這次分享的關鍵詞有兩個: 一個是Kubernetes, 另一個是有狀態集群服務。
我們會在第一部分了解一下什么是 Kubernetes,以及運行有狀態集群服務面臨的一些挑戰。
接下來的兩部分我們會重點介紹 Kubernetes 是如何應對這些挑戰,以及通過哪些特性來解決有狀態集群服務所特有的一些問題。
最后一部分是實戰,通過一個MySQL集群的例子來展示如何在Kubernetes上輕松地部署和管理一個有狀態集群服務。
首先來看什么是Kubernetes?
簡單一句話來說,Kubernetes是一個運行和管理容器的平臺。它在Docker、rkt等容器運行時之上,實現了容器的集群化和高可用。
Kubernetes簡稱K8S, 來自Google,支持多種云計算環境,并且100% 開源,是云原生計算基金會的一部分,用Go語言開發的。
這里是Kubernetes的一些基本概念。
其中最核心的一個概念是Pod,它是Kubernetes對容器進行的封裝,是Kubernetes管理的最小單位。
Pod通過Deployment來部署,Deployment會創建一個Replica Set 來保證Pod的個數始終是一個指定的值 。
Pod一般不直接對外提供服務,而是通過Service對外提供一個穩定的訪問接口,一個Service后面可以掛多個Pod實例 。
Service是如何找到它匹配的Pod呢?靠的是Label。Label是聯系各個K8S資源的紐帶。Replica Set 和它管理的Pod之間也是通過 Label 來關聯的。
如果Pod里的容器運行的是有狀態服務,如數據庫與緩存等,還需要掛載存儲卷,用于存儲服務狀態。
講完原理,我們來看一個實例。
這是一個在K8S集群里運行的容器化應用案例,這個應用有自己的Web 客戶端,同時還從推ter采集數據,處理完后存儲到自己的DB。
可以看到容器里跑的服務有兩類,無狀態和有狀態。像Web服務器,流處理器等無狀態服務出現問題后,直接殺掉,新建一個,管理起來非常簡單。
但是對有狀態服務,像數據庫,它要求有更長的生命周期。在一個集群的情況下,集群成員之間如何能保持穩定的成員關系?這都對容器編排系統提出了新的挑戰。
那么K8S是如何應對這些挑戰的呢?
K8S運行的服務,從簡單到復雜可以分成三類:無狀態服務、普通有狀態服務和有狀態集群服務。下面分別來看K8S是如何運行這三類服務的。
首先無狀態服務,K8S使用RC(或更新的Replica Set)來保證一個服務的實例數量。通過Service來對外提供一個穩定的訪問接口。
然后是普通有狀態服務,它多了狀態保存的需求。Kubernetes提供了以Volume和Persistent Volume為基礎的存儲系統,可以實現服務的狀態保存。
最后是有狀態集群服務,它又多了集群管理的需求。K8S為此開發了一套以Pet Set為核心的全新特性,方便了有狀態集群服務在K8S上的部署和管理。
下面我們首先來看Kubernetes如何滿足“狀態保存”的需求。
K8S的存儲系統大致分為三個層次:普通Volume,Persistent Volume 和動態存儲供應。
對普通Volume,最簡單的一種是“單節點存儲卷”。它和Docker的存儲卷類似,使用的是Pod所在K8S節點的本地目錄。
具體有兩種,一種是 emptyDir,是一個匿名的空目錄,由Kubernetes在創建Pod時創建,刪除Pod時刪除。
另外一種是 hostPath,與emptyDir的區別是,它在Pod之外獨立存在,由用戶指定路徑名。
這類和節點綁定的存儲卷在Pod遷移到其它節點后數據就會丟失,所以只能用于存儲臨時數據或用于在同一個Pod里的容器之間共享數據。
普通Volume的第二種類型是“跨節點存儲卷”。這種存儲卷不和某個具體的K8S節點綁定,而是獨立于K8S節點存在的 。
跨節點存儲卷由于可以在任何一個Kubernetes 節點上都能夠被訪問到,比較靈活,所以應用比較廣泛。
Kubernetes上的Volume是通過插件方式來實現的,所以可擴展性很強。
目前來說幾乎所有主流的存儲在Kubernetes上都有相應的插件來支持。如果已有的存儲不能滿足要求,還可以開發自己的volume插件 。
K8S存儲系統的第二種存儲方式叫persistent volume。它和普通volume的區別是什么呢?
普通Volume和使用它的Pod之間是一種靜態綁定關系,我們無法單獨創建一個普通volume,因為它不是一個獨立的K8S資源對象。
而Persistent Volume 簡稱PV是一個K8S資源對象,所以我們可以單獨創建。它不和Pod直接發生關系,而是通過Persistent Volume Claim,簡稱PVC來實現動態綁定。
接下來我們看一下這個動態綁定過程是怎樣的?
這是PV的生命周期,首先是Provision,即創建PV,這里創建PV有兩種方式,靜態和動態。
所謂靜態,是管理員手動創建一堆PV,組成一個PV池,供PVC來綁定。動態方式是通過一個叫 storage class的對象由存儲系統根據PVC的要求自動創建。
一個PV創建完后狀態會變成Available,等待被PVC綁定。一旦被PVC邦定,PV的狀態會變成Bound,就可以被相應的Pod使用。Pod使用完后會釋放PV,PV的狀態變成Released。
變成Released的PV會根據定義的回收策略做相應的回收工作。有三種回收策略,Retain、Delete 和 Recycle。
Retain就是保留現場,K8S什么也不做。Delete 策略,K8S會自動刪除該PV及里面的數據。Recycle方式,K8S會將PV里的數據刪除,然后把PV的狀態變成Available,又可以被新的PVC綁定使用。
剛才提到PV的供給有兩種方式,靜態和動態。其中動態方式是通過StorageClass來完成的,這是一種新的存儲供應方式。
使用StorageClass有什么好處呢?除了由存儲系統動態創建,節省了管理員的時間,還有一個好處是可以封裝不同類型的存儲供PVC選用。
比如這里就有兩個StorageClass,它們都是用谷歌的存儲系統,但是一個使用的是普通磁盤,名字為slow。另一個使用的是SSD,名字為fast。
在PVC里通過annotation指定了storage class的名字為fast,這樣這個PVC就會綁定一個SSD,而不會綁定一個普通的磁盤。
好,到這里Kubernetes的整個存儲系統就都介紹完了。
下面進入Kubernetes與有狀態集群服務相關的兩個新特性。Init Container 和 Pet Set。
什么是Init Container?
從名字來看就是做初始化工作的容器。可以有一個或多個,這些 Init Container 按照定義的順序依次執行,只有所有的Init Container 執行完后,主容器才啟動。
由于一個Pod里的存儲卷是共享的,所以 Init Container 里產生的數據可以被主容器使用到。
這是Init Container的一個使用樣例。
這個例子創建一個Pod,這個Pod里跑的是一個nginx容器,Pod里有一個叫workdir的存儲卷,訪問nginx容器服務的時候,就會顯示這個存儲卷里的index.html 文件。
而這個index.html 文件就是通過一個 busybox的初始化容器獲得的。
介紹完Init Container,千呼萬喚始出來,該今天的主角Pet Set出場了。
什么是Pet Set?顧名思義是Pet的集合,那什么是Pet呢?它是一種需要特殊照顧的Pod。它有狀態、有身份、當然也比普通的Pod要復雜一些。
具體來說,一個Pet有三個特征
一是有穩定的存儲,這是通過我們前面介紹的PV/PVC 來實現的。
二是穩定的網絡身份,這是通過一種叫 Headless Service 的特殊Service來實現的。 和普通Service相比,Headless Service沒有Cluster IP,用于為一個集群內部的每個成員提供一個唯一的DNS名字,用于集群內部成員之間 通信 。
Pet的第三個特征是序號命名規則。 比如 Pet Set 的名字叫 mysql,那么第一個啟起來的Pet就叫mysql-0,第二個叫mysql-1,如此下去。
當一個Pet down 掉后,新創建的Pet 會被賦予跟原來Pet一樣的名字,通過這個名字就能匹配到原來的存儲,實現狀態保存。
好,與有狀態服集群服務相關的K8S特性就介紹到這里。
理論講完了,下面進入實戰,以Galera MySQL集群為例子,介紹如何在 Kubernetes如何上部署和管理一個有狀態集群服務。
首先大致了解一下Galera MySQL。
它不是那種主從式的集群,而是多Master集群,通過 Galera Replication 把多個MySQL實例關聯起來組成一個集群。由Galera Replication 負責節點間的數據同步。
用戶訪問時可以連接到任何一個節點進行讀寫操作。每次寫入的數據會被Galera Replication同步到整個集群,才算寫入成功。
節點之間沒有數據延遲,在某個節點失效后,直接退出集群即可,無需失效轉移。
對Galera MySQL集群有了基本了解后,我們來看看如何在Kubernetes上部署和運行它。這是整體結構圖:
左邊的Headless Service用于為每個MySQL Pet實例提供一個DNS名字,右邊的PV池為MySQL提供存儲 。
這里有兩個初始化容器,第一個用于安裝需要的文件,第二個做MySQL的初始化工作 。
一個Pet Set里有多個Pet,每個Pet對應MySQL集群里的一個節點。通過Pet Set可以管理整個MySQL集群。
這是部署MySQL集群具體的YAML文件。
右邊是一個Headless Service,名字是galera。
左邊是Pet Set,它用到了右邊的Headless service。Replicas的數目為3,會創建3個Pet。
在 Pet Set 的annotation里定義了兩個初始化容器。
Install容器安裝的文件可以被bootstrap容器使用到;同時bootstrap容器生成的MySQL配置文件會放到config存儲卷里,供后面的MySQL 容器使用。
這是主容器 Galera MySQL 的定義:
除了常規的3306端口外,它還暴露了其它一些端口,用于集群內部的數據同步和狀態轉移等操作。
這里MySQL啟動參數里用到的文件,是在初始化容器里生成的,通過共享存儲卷傳遞過來。
最后是數據存儲卷的定義。
這里定義了三個存儲卷,其中config、workdir就是簡單的本地目錄,而 datadir是一個PVC,它可以去綁定PV來存儲MySQL數據庫的數據 。
所以部署一個集群總共就需要兩個YAML文件就可以了,一個Headless Service,一個 Pet Set。其中Pet Set里定義了初始化容器和存儲卷。
用上面的方式部署完MySQL集群后,后面的運維工作是比較簡單的。
假如某個集群節點由于某種原因Crash掉了,Kubernetes 會自動創建一個新的Pet來替代,實現自動恢復。
如果要擴容或縮容,也是一條命令、指定一下這個Pet Set 的Replicas的數目就行了。
如果要升級,只需要修改Pet Set 定義里 podTemplate 的image值,然后把老的Pet刪除,新創建的Pet,就是最新版本的了。
對于在Kubernetes上部署有狀態集群服務,我們補充兩點:
第一點是在最新發布的 Kubernetes 1.5 里 PetSet 重新命名為StatefulSet。所以根據你使用的K8S版本不同,可能看到的名字也不一樣。
第二點是簡單介紹一下時速云提供的有狀態集群服務:數據庫與緩存 。
如上圖所示,這項服務最大程度的簡化了有狀態集群服務的創建工作,用戶不再需要了解我們前面介紹的所有技術術語,只需要指定一下副本數目,存儲的大小就可以了。
最后以下面這張圖做為今天分享內容的總結。
有狀態集群服務的兩個需求,一個是存儲需求。另一個是集群需求 。
對存儲需求,Kubernetes的解決方案是Volume、Persistent Volume 。對PV,除了手動創建PV池外,還可以通過Storage Class來讓存儲系統自動創建。
對集群需求,Kubernetes的解決方案是Pet Set。Pet Set 又通過Init Container來做集群初始化,通過Headless Service來為集群成員提供穩定 的網絡身份。
最后我們以MySQL集群為例,說明了如何在Kubernetes上部署和運行一個有狀態集群服務。
目前有狀態集群服務在Kubernetes上的部署還不是正式版,但完全可用。如果您的項目中有容器化的需求,可以嘗試。
今天的分享到此結束,謝謝大家!
Q: 前面提到init container,k8s里pod初始化是基于gcr的pause,這個初始化鏡像是自定義的嗎?
A:init container 和 gcr的pause 是不同的概念,一個是初始化容器(運行完就結束),一個是基礎容器(一直運行)
Q: 北京Q1:你介紹的k8s存儲技術都是比較新的,能否適應企業生產大規模使用,有沒有什么性能和穩定性問題?
A: 性能和穩定性上我們也在不斷嘗試,先使用起來看看效果,目前創建過幾百個集群,暫時沒有碰到太多穩定性問題。
Q:能否提供一下k8s部署mysql的文檔,以供交流[呲牙]
A:這個在后面的整理文檔里會有部署樣例提供。
Q:請問是時速云mysql集群的存儲是用什么?cephfs 還是glusterfs,或者其他
A:目前出于效率考慮,主要是分布式塊存儲,沒有用glusterfs這些
Q:存儲系統如何動態創建StorageClass,如果 Headless Service沒有Cluster IP,服務如何調用?
A:K8S 通過StorageClass 讓存儲系統動態創建PV,不是動態創建StorageClass。Headless Service 用于集群內部通信,外部調用,再建普通Service,二者并存。
Q: 我想問個k8s比較基礎的問題哈,是關于service type的,有三種,第一種clusterIP我不是很明白,不是k8s默認所有pod之間是互通的么,那還需要這個clusterIP干啥呢。比如我兩個pod,一個跑redis,一個跑web, 那web那個pod肯定是可以訪問到redis的呀,為啥還需要為redis create 一個service呢
A:Pod重建或遷移后IP可能變,用Service可以提供一個穩定的訪問接口。
Q:有狀態集群還有其他的實現方式嗎?
A: 在容器云里比較好的方式是用PetSet,當然也能自己做,相當于自己實現PetSet的一些功能。
Q:同步到整個集群才算寫入成功,是不是意味著不適合高負載的項目使用?有可能增加其它策略供選擇嗎?
A:由于采用多主方式,對外只寫入一個,內部擴散同步可以并行,而且每個節點都能對外提供服務,相當于增加了服務帶寬,所以性能不是問題。
杭州Q:您好,你們是采用什么分布式存儲的,io性能如何?好像一些開源分布式的存儲寫io的性能普遍比較低,能撐得住一些io高性能的應用嗎?
A: 性能上要等到支持host 模式后,才能滿足一些IO要求比較高的場景
Q:時速云的mysql集群是RDS嗎
A:目標就是基于容器的 RDS 服務
來自:http://dockone.io/article/2016