今天主要會介紹 StatefulSet 以及比較其與 Deployment 的不同
StatefulSet 是 k8s 叢集用來處理有狀態的應用佈署, 所謂 Stateful applications
舉例來說: 資料庫(MySql, mongoDB), ElasticSearch
這些應用都需要前面章節講到的 PersistentVolume 紀錄應用的狀態,當應用因為問題而重新啟動時, 需要透過儲存在 PersistentVolume 的資料來回復狀態
無狀態應用則不需要紀錄應用的狀態, 每個對應用發出的請求都與狀態無關
因為有狀態的應用與無狀態的應用有所不同, k8s 叢集也使用不同元件來做佈署
無狀態的應用佈署 k8s 叢集使用 Deployment 元件
用來複製佈署過無狀態的 Pod
有狀態的應用佈署 k8s 叢集使用 StatefulSet 元件
也可以用來複製佈署過的 Pod
Deployment 所產生出來的 Pod, Pod Id 是隨機雜驟
當做 scale up 時, 每個 Pod 的 Pod Id 無順序性可以隨意掉換取代
StatefulSet 所產生出來的 Pod, Pod Id 具有一定順序性
當做了 scale up 時, 每個 Pod 的 Pod Id 具有一定順序性, 無法任意掉換順序
舉例來說:
假設有一個 mysql Pod 使用 StatefulSet 做 scale up
為了維持資料一致性
只會允許第一個 Pod 掛載的 Storage 可以做寫入
而第二個 Pod 掛載的 Storage 則慧跟第一個 Pod 的 Storage 做同步, 並且只能讀取
因為兩個 Pod Storage 可以同時寫入會造成資料不一致
除此之外, 每個 mysql Pod 讀取的 Storage 也不是相同的
假設另外有一個 my-app-java Pod 使用 Deployment 做 scale up 由於每個 Pod 都是相同且可以替換
所以只要用一個 Service 來做負載平衡然後掛載多個 my-app 的 Pod 在後面即可
如前述, 因為 StatefulSet 會需要存儲應用狀態
因此最好的方式是設定 PersistentVolume 給 StatefulSet
讓 StatefulSet 可以把狀態相關則資訊存儲再 PersistentVolume 確保狀態不會因為 Pod 或 k8s 叢集不穩定而遺失狀態
而最好的 Storage 方式建議是使用 Remote Storage
因為 Local Storage 基本上會綁定在某一個結點, Pod 如果不是再同一個結點則無法存取的到
對於 Deployment, Pod Identity 是採用 random hash
對於 StatefulSet, Pod Identity 則是有一組固定順序的名稱由以下模式組成
${statefulset name}-${ordinal}
ordinal 是由 0 開始遞增的數列
假設用建立名為 mysql 的 StatefulSet, replicas 設定為 3
則產生出來的 Pod 名稱則依序為 mysql-0, mysql-1, mysql-2
而第一個是 Master DB 可做讀寫, 其他則是 Slave DB 只能做讀取
重要的是, StatefulSet 的 replica 會依序建立 Pod
也就是當 mysql-0 還沒建立好, mysql-1 不會開始建立
相對的, 當刪除 Pod 時, 也是會從後面的序號往前刪除以維持資料狀態的正確性
第1種, 當使用 Service 掛載 Pod 時使用 loadbalancer service
把所有 Pod 掛載到這個 loadbalancer service
Pod 的 endpoint 就是 loadbalancer service name
第2種, 當使用 Service 掛載 Pod 時使用個別掛載
每個 Pod 的 endpoint 就是以下這個模式
${Pod Name}.${governing Service domain}
1 StatefulSet 的 Pod 名稱是可預測的
2 每個 Pod 的 DNS 名稱是固定的
每次當 Pod 重起
IP 會改變, 但是名稱跟 endpoints 不變
當對於有狀態的應用做 Replicas 時
雖然 k8s 叢集有支援
但是仍然需要處理很多事情如下:
. 設定資料複製跟資料同步的機制
. 設定遠端存儲
. 建立管理備份機制