1.1 有狀態應用管理statefulset
StatefulSet(有狀態集,縮寫為sts)常用於部署有狀態的且需要有序啟動的應用程式,比如在進行SpringCloud專案容器化時,Eureka的部署是比較適合用StatefulSet部署方式的,可以給每個Eureka例項建立一個唯一且固定的識別符號,並且每個Eureka例項無需配置多餘的Service,其餘Spring Boot應用可以直接透過Eureka的Headless Service即可進行註冊。
1.1.1 statefulset基本概念
- StatefulSet主要用於管理有狀態應用程式的工作負載API物件。比如在生產環境中,可以部署ElasticSearch叢集、MongoDB叢集或者需要持久化的RabbitMQ叢集、Redis叢集、Kafka叢集和ZooKeeper叢集等。
- 和Deployment類似,一個StatefulSet也同樣管理著基於相同容器規範的Pod。不同的是,StatefulSet為每個Pod維護了一個粘性標識。這些Pod是根據相同的規範建立的,但是不可互換,每個Pod都有一個持久的識別符號,在重新排程時也會保留,一般格式為StatefulSetName-Number。
- 比如定義一個名字是Redis-Sentinel的StatefulSet,指定建立三個Pod,那麼建立出來的Pod名字就為Redis-Sentinel-0、Redis-Sentinel-1、Redis-Sentinel-2。
- 而StatefulSet建立的Pod一般使用Headless Service(無頭服務)進行通訊,和普通的Service的區別在於Headless Service沒有ClusterIP,它使用的是Endpoint進行互相通訊,Headless一般的格式為:
- statefulSetName-{0..N-1}.serviceName.namespace.svc.cluster.local。
說明:
serviceName為Headless Service的名字,建立StatefulSet時,必須指定Headless Service名稱;
0..N-1為Pod所在的序號,從0開始到N-1;
statefulSetName為StatefulSet的名字;
namespace為服務所在的名稱空間;
.cluster.local為Cluster Domain(叢集域)
假如公司某個專案需要在Kubernetes中部署一個主從模式的Redis,此時使用StatefulSet部署就極為合適,因為StatefulSet啟動時,只有當前一個容器完全啟動時,後一個容器才會被排程,並且每個容器的識別符號是固定的,那麼就可以透過識別符號來斷定當前Pod的角色
1.1.2 StatefulSet注意事項
一般StatefulSet用於有以下一個或者多個需求的應用程式:
-
需要穩定的獨一無二的網路識別符號。
-
需要持久化資料。
-
需要有序的、優雅的部署和擴充套件。
-
如果應用程式不需要任何穩定的識別符號或者有序的部署、刪除或者擴充套件,應該使用無狀態的控制器部署應用程式,比如Deployment或者ReplicaSet。需要有序的自動滾動更新。
StatefulSet是Kubernetes 1.9版本之前的beta資源,在1.5版本之前的任何Kubernetes版本都沒有。
Pod所用的儲存必須由PersistentVolume Provisioner(持久化卷配置器)根據請求配置StorageClass,或者由管理員預先配置,當然也可以不配置儲存。
為了確保資料安全,刪除和縮放StatefulSet不會刪除與StatefulSet關聯的卷,可以手動選擇性地刪除PVC和PV)。
StatefulSet目前使用Headless Service(無頭服務)負責Pod的網路身份和通訊,需要提前建立此服務。
刪除一個StatefulSet時,不保證對Pod的終止,要在StatefulSet中實現Pod的有序和正常終止,可以在刪除之前將StatefulSet的副本縮減為0
為什麼要用headless service+statefulSet部署有狀態應用?
Headless Services介紹
Headless Services是一種特殊的service,其spec:clusterIP表示為None,這樣在實際執行時就不會被分配ClusterIP。也被稱為無頭服務。
1、headless Service和普通Service的區別
headless不分配clusterIP
headless service可以透過解析service的DNS,返回所有Pod的地址和域名(statefulSet部署的Pod才有域名)
headless service會為關聯的Pod分配一個域:
service-name.namespace-name.svc.cluster.local
普通的service,只能透過解析service的DNS返回service的ClusterIP
2、statefulSet和Deployment控制器的區別
statefulSet下的Pod有DNS地址,透過解析Pod的DNS可以返回Pod的IP
StatefulSet會為關聯的Pod保持一個不變的Pod Name
statefulset中Pod的hostname格式為
statefulsetname-(pod序號)
而deployment下的Pod沒有具體的域名,想訪問Pod都是透過普通service來負載均衡到後端pod,無法指定訪問具體哪個Pod
3、普通Service解析service的DNS結果
Service的ClusterIP工作原理:一個service可能對應一組endpoints(所有pod的地址+埠),client訪問ClusterIP,透過iptables或者ipvs轉發到Real Server(Pod)。
StatefulSet+headless service會為關聯的每個Pod都分配一個具體的域名:
Pod-Name.service-name.namespace-name.svc.cluster.local
實操部分
1.1.3 定義一個StatefulSet資原始檔
點選檢視程式碼
apiVersion: v1
kind: Service
metadata:
name: nginx
labels:
app: nginx
spec:
ports:
- port: 80
name: web
clusterIP: None #這裡可以有IP,也可以無IP,推薦無IP,也就是 無頭service
selector:
app: nginx
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: web
spec:
serviceName: "nginx"
replicas: 2
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.15.2
ports:
- containerPort: 80
name: web
建立個Busybox演示如何透過無頭service名字來進行網路訪問
透過nslookup來解析web-0.nginx(sts名稱+無頭service名稱),可以得到這個Pod的ip地址:10.244.32.152
進入叢集busybox容器對web-0.nginx進行Ping和wget發現都是通的
1.1.4 縮容擴容StatefulSet
檢視sts lable標籤
透過標籤對指定sts進行監聽
對sts進行擴容操作
可以看到sts啟動的順序是嚴格按照序號來進行啟動的,同理縮容的話會嚴格按照pod的序號倒序進行刪除
1.1.4 StatefulSet更新策略
1. RollingUpdate 更新策略
- 預設更新策略RollingUpdate
點選檢視程式碼
updateStrategy:
rollingUpdate:
partition: 0 #不更新小於 N 的副本
type: RollingUpdate
開啟另一個視窗,觀察Pod更新過程,可以看到他的更新順序是倒序的
2. Ondelete 更新策略 [適用於灰度釋出]
更改更新策略為Ondelete
點選檢視程式碼
修改:
updateStrategy:
rollingUpdate:
partition: 0
type: RollingUpdate
改為:
updateStrategy:
type: OnDelete #修改為OnDelete更新模式並儲存,該更新策略是,刪除時才會進行更新
更新映象版本,並觀察更新過程
只有進行delete pod刪除操作的時候,pod才會被更新