StatefulSet介紹


一、什么是StatefulSet

StatefulSet(有狀態集,縮寫為sts)常用於部署有狀態的且需要有序啟動的應用程序,比如在進行SpringCloud項目容器化時,Eureka的部署是比較適合用StatefulSet部署方式的,可以給每個Eureka實例創建一個唯一且固定的標識符,並且每個Eureka實例無需配置多余的Service,其余Spring Boot應用可以直接通過Eureka的Headless Service即可進行注冊

Eureka的statefulset的資源名稱是eureka,eureka-0 eureka-1 eureka-2
Service:headless service,沒有ClusterIP	eureka-svc
Eureka-0.eureka-svc.NAMESPACE_NAME  eureka-1.eureka-svc

二、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的角色。
	比如用一個名為redis-ms的StatefulSet部署主從架構的Redis,第一個容器啟動時,它的標識符為redis-ms-0,並且Pod內主機名也為redis-ms-0,此時就可以根據主機名來判斷,當主機名為redis-ms-0的容器作為Redis的主節點,其余從節點,那么Slave連接Master主機配置就可以使用不會更改的Master的Headless Service,此時Redis從節點(Slave)配置文件如下:
	port 6379
	slaveof redis-ms-0.redis-ms.public-service.svc.cluster.local 6379
	tcp-backlog 511
	timeout 0
	tcp-keepalive 0
	...
	其中redis-ms-0.redis-ms.public-service.svc.cluster.local是Redis Master的Headless Service,在同一命名空間下只需要寫redis-ms-0.redis-ms即可,后面的public-service.svc.cluster.local可以省略。

三、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

四、定義一個StatefulSet資源文件

4.1、定義一個簡單的StatefulSet的示例如下:

cat > nginx-sts.yaml << EFO
apiVersion: v1
kind: Service
metadata:
  name: nginx
  labels:
    app: nginx
spec:
  ports:
  - port: 80
    name: web
  clusterIP: None
  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
EFO
# 此示例沒有添加存儲配置,后面的章節會單獨講解存儲相關的知識點

4.2、創建一個StatefulSet

[root@k8s-master01 ~]# kubectl create -f nginx-sts.yaml
service/nginx created
statefulset.apps/web created

# 查看svc信息
[root@k8s-master01 ~]# kubectl get svc
NAME         TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
kubernetes   ClusterIP   10.96.0.1    <none>        443/TCP   42h
nginx        ClusterIP   None         <none>        80/TCP    24s

# 查看pod信息
[root@k8s-master01 ~]# kubectl get po
NAME                        READY   STATUS              RESTARTS   AGE
nginx-66bbc9fdc5-vc2gh      1/1     Running             0          12h
nginx-v2-644cd9ccc7-b99nf   1/1     Running             0          11h
web-0                       1/1     Running             0          113s
web-1                       0/1     ContainerCreating   0          111s

# 查看sts
[root@k8s-master01 ~]# kubectl get sts
NAME   READY   AGE
web    2/2     2m42s

4.3、StatefulSet的擴容

[root@k8s-master01 ~]# kubectl scale --replicas=3 sts web
statefulset.apps/web scaled

# 查看pod、發現名字是固定增長的
[root@k8s-master01 ~]# kubectl get pod
NAME                        READY   STATUS              RESTARTS   AGE
nginx-66bbc9fdc5-vc2gh      1/1     Running             0          12h
nginx-v2-644cd9ccc7-b99nf   1/1     Running             0          12h
web-0                       1/1     Running             0          4m48s
web-1                       1/1     Running             0          4m46s
web-2                       0/1     ContainerCreating   0          28s

4.4、StatefulSet的縮容

[root@k8s-master01 ~]# kubectl scale --replicas=2 sts web 
statefulset.apps/web scaled

# 先刪最后一個
[root@k8s-master01 ~]# kubectl get pod              
NAME                        READY   STATUS        RESTARTS   AGE
busybox                     1/1     Running       0          3m41s
nginx-66bbc9fdc5-vc2gh      1/1     Running       0          12h
nginx-v2-644cd9ccc7-b99nf   1/1     Running       0          12h
web-0                       1/1     Running       0          12m
web-1                       1/1     Running       0          12m
web-2                       0/1     Terminating   0          7m45s

五、StatefulSet更新策略

5.1、On Delete策略

	OnDelete更新策略實現了傳統(1.7版本之前)的行為,它也是默認的更新策略。當我們選擇這個更新策略並修改StatefulSet的.spec.template字段時,StatefulSet控制器不會自動更新Pod,我們必須手動刪除Pod才能使控制器創建新的Pod。

5.2、RollingUpdate策略

	RollingUpdate(滾動更新)更新策略會更新一個StatefulSet中所有的Pod,采用與序號索引相反的順序進行滾動更新
	
	比如Patch一個名稱為web的StatefulSet來執行RollingUpdate更新:
[root@k8s-master01]# kubectl patch statefulset web -p '{"spec":{"updateStrategy":{"type":"RollingUpdate"}}}'
statefulset.apps/web patched

查看更改后的StatefulSet:
[root@k8s-master01 2.2.7]# kubectl get sts web -o yaml | grep -A 1 "updateStrategy"
  updateStrategy:
    type: RollingUpdate
    
然后改變容器的鏡像進行滾動更新:
[root@k8s-master01 2.2.7]# kubectl patch statefulset web --type='json' -p='[{"op": "replace", "path": "/spec/template/spec/containers/0/image", "value":"dotbalo/canary:v1"}]'
statefulset.apps/web patched

	如上所述,StatefulSet里的Pod采用和序號相反的順序更新。在更新下一個Pod前,StatefulSet控制器會終止每一個Pod並等待它們變成Running和Ready狀態。在當前順序變成Running和Ready狀態之前,StatefulSet控制器不會更新下一個Pod,但它仍然會重建任何在更新過程中發生故障的Pod,使用它們當前的版本。已經接收到請求的Pod將會被恢復為更新的版本,沒有收到請求的Pod則會被恢復為之前的版本
	
	在更新過程中可以使用 kubectl rollout status sts/<name> 來查看滾動更新的狀態:
[root@k8s-master01 ~]# kubectl rollout status sts/web

5.3、分段更新(partition)

	StatefulSet可以使用RollingUpdate更新策略的partition參數來分段更新一個StatefulSet。分段更新將會使StatefulSet中其余的所有Pod(序號小於分區)保持當前版本,只更新序號大於等於分區的Pod,利用此特性可以簡單實現金絲雀發布(灰度發布)或者分階段推出新功能等。注:金絲雀發布是指在黑與白之間能夠平滑過渡的一種發布方式。
	# 比如我們定義一個分區"partition":3,可以使用patch直接對StatefulSet進行設置
[root@k8s-master01 ~]# kubectl patch statefulset web -p '{"spec":{"updateStrategy":{"type":"RollingUpdate","rollingUpdate":{"partition":3}}}}'
statefulset.apps/web patched

	# 然后再次patch改變容器的鏡像:
[root@k8s-master01 ~]# kubectl patch statefulset web --type='json' -p='[{"op": "replace", "path": "/spec/template/spec/containers/0/image", "value":"k8s.gcr.io/nginx-slim:0.7"}]'
statefulset.apps/web patched
	# 刪除Pod觸發更新
[root@k8s-master01 ~]# kubectl delete po web-1
pod "web-1" deleted

六、刪除StatefulSet

刪除StatefulSet有兩種方式,即級聯刪除和非級聯刪除。使用非級聯方式刪除StatefulSet時,StatefulSet的Pod不會被刪除;使用級聯刪除時,StatefulSet和它的Pod都會被刪除

6.1、級聯刪除

使用kubectl delete sts xxx刪除StatefulSet時,只需提供--cascade=false參數,就會采用非級聯刪除,此時刪除StatefulSet不會刪除它的Pod

[root@k8s-master01 ~]# kubectl get po 
NAME                        READY   STATUS    RESTARTS   AGE
busybox                     1/1     Running   0          56m
nginx-66bbc9fdc5-vc2gh      1/1     Running   0          13h
nginx-v2-644cd9ccc7-b99nf   1/1     Running   0          13h
web-0                       1/1     Running   0          64m
web-1                       1/1     Running   0          2m54s

# 刪除sts
[root@k8s-master01 ~]# kubectl delete statefulset web --cascade=false
warning: --cascade=false is deprecated (boolean value) and can be replaced with --cascade=orphan.
statefulset.apps "web" deleted

# 可以看到已經刪除了sts,但是pod還在
[root@k8s-master01 ~]# kubectl get sts
No resources found in default namespace.
[root@k8s-master01 ~]# kubectl get pod
NAME                        READY   STATUS    RESTARTS   AGE
busybox                     1/1     Running   0          57m
nginx-66bbc9fdc5-vc2gh      1/1     Running   0          13h
nginx-v2-644cd9ccc7-b99nf   1/1     Running   0          13h
web-0                       1/1     Running   0          65m
web-1                       1/1     Running   0          4m

# 由於此時刪除了StatefulSet,因此單獨刪除Pod時,不會被重建
[root@k8s-master01 ~]# kubectl get pod
NAME                        READY   STATUS    RESTARTS   AGE
busybox                     1/1     Running   0          59m
nginx-66bbc9fdc5-vc2gh      1/1     Running   0          13h
nginx-v2-644cd9ccc7-b99nf   1/1     Running   0          13h
web-0                       1/1     Running   0          68m
web-1                       1/1     Running   0          6m21s
[root@k8s-master01 ~]# kubectl delete pod web-1
pod "web-1" deleted
[root@k8s-master01 ~]# kubectl get po
NAME                        READY   STATUS    RESTARTS   AGE
busybox                     1/1     Running   0          60m
nginx-66bbc9fdc5-vc2gh      1/1     Running   0          13h
nginx-v2-644cd9ccc7-b99nf   1/1     Running   0          13h
web-0                       1/1     Running   0          68m

# 當再次創建此StatefulSet時,web-0會被重新創建,web-1由於已經存在而不會被再次創建,因為最初此StatefulSet的replicas是2,所以web-2會被刪除,如下(忽略AlreadyExists錯誤)
[root@k8s-master01 ~]# kubectl create -f nginx-sts.yaml 
statefulset.apps/web created
Error from server (AlreadyExists): error when creating "nginx-sts.yaml": services "nginx" already exists

[root@k8s-master01 ~]# kubectl get po
NAME                        READY   STATUS    RESTARTS   AGE
busybox                     1/1     Running   1          64m
nginx-66bbc9fdc5-vc2gh      1/1     Running   0          13h
nginx-v2-644cd9ccc7-b99nf   1/1     Running   0          13h
web-0                       1/1     Running   0          72m
web-1                       1/1     Running   0          26s
web-2                       1/1     Running   0          24s

6.2、非級聯刪除

省略--cascade=false參數即為級聯刪除

[root@k8s-master01 ~]# kubectl delete statefulset web
statefulset.apps "web" deleted

也可以使用-f參數直接刪除StatefulSet和Service(此文件將sts和svc寫在了一起)

[root@k8s-master01 ~]# kubectl delete -f nginx-sts.yaml 
service "nginx" deleted
Error from server (NotFound): error when deleting "nginx-sts.yaml": statefulsets.apps "web" not found


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM