StatefulSet簡介
有狀態應用副本集
為什么要用statefulset控制器
有狀態和無狀態
無狀態的, 更關注的是群體
有狀態的, 更關注的是個體
有狀態應用集的特點:
- 穩定且需要唯一的網絡標識符;
- 如: Redis集群,
在Redis集群中,它是通過槽位來存儲數據的,假如:第一個節點是01000,第二個節點是10012000,第三個節點2001~3000...等等,這就使得Redis集群中每個節點要通過ID來標識自己,如:
第二個節點宕機了,重建后它必須還叫第二個節點,或者說第二個節點叫R2,它必須還叫R2,這樣在獲取1001~2000槽位的數據時,才能找到數據,否則Redis集群將無法找到這段數據。
- 如: Redis集群,
- 穩定且持久的存儲;
- 可實現持久存儲,新增或減少pod,存儲不會隨之發生變化。
- 要求有序, 平滑的部署和擴展;
- 如 MySQL集群,要先啟動主節點, 若從節點沒有要求,則可一起啟動,若從節點有啟動順序要求,可先啟動第一個從節點,接着第二從節點等;這個過程就是有順序,平滑安全的啟動。
- 要求有序, 平滑的終止和刪除;
- 我們先終止從節點,若從節點是有啟動順序的,那么關閉時,也要按照逆序終止,即啟動時是從S1~S4以此啟動,則關閉時,則是先關閉S4,然后時S3,依次關閉,最后在關閉主節點。
- 有序的滾動更新;
- MySQL在更新時,應該先更新從節點,全部的從節點都更新完了,最后在更新主節點,因為新版本一般可兼容老版本,但是一定要注意,若新版本不兼容老版本就很很麻煩
statefulset的組成:
- headless service 用於定義網絡標識(DNS)
- StatefulSet 控制器,用於定義具體應用
- volumeClaimTemplate 存儲卷申請模板,用於創建PV
簡單測試 使用 StatefulSet
創建基礎的PV
[root@master configmap]# cat ../volume/pv-demo.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv001
labels:
name: pv001
spec:
nfs:
path: /data/volumes/v1
server: 172.27.1.241
accessModes: ["ReadWriteMany", "ReadWriteOnce"]
capacity:
storage: 5Gi
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv002
labels:
name: pv002
spec:
nfs:
path: /data/volumes/v2
server: 172.27.1.241
accessModes: ["ReadWriteOnce"]
capacity:
storage: 5Gi
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv003
labels:
name: pv003
spec:
nfs:
path: /data/volumes/v3
server: 172.27.1.241
accessModes: ["ReadWriteMany", "ReadWriteOnce"]
capacity:
storage: 5Gi
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv004
labels:
name: pv004
spec:
nfs:
path: /data/volumes/v4
server: 172.27.1.241
accessModes: ["ReadWriteMany", "ReadWriteOnce"]
capacity:
storage: 10Gi
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv005
labels:
name: pv005
spec:
nfs:
path: /data/volumes/v5
server: 172.27.1.241
accessModes: ["ReadWriteMany", "ReadWriteOnce"]
capacity:
storage: 10Gi
[root@master volume]# kubectl apply -f pv-demo.yaml
persistentvolume/pv001 created
persistentvolume/pv002 created
persistentvolume/pv003 created
persistentvolume/pv004 created
persistentvolume/pv005 created
[root@master volume]# kubectl get pv -o wide
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE VOLUMEMODE
pv001 5Gi RWO,RWX Retain Available 5s Filesystem
pv002 5Gi RWO Retain Available 5s Filesystem
pv003 5Gi RWO,RWX Retain Available 5s Filesystem
pv004 10Gi RWO,RWX Retain Available 5s Filesystem
pv005 10Gi RWO,RWX Retain Available 5s Filesystem
StatefulSet 清單
[root@master manifests]# cat statefulset-demo.yaml
apiVersion: v1
kind: Service
metadata:
name: myapp-svc
namespace: default
labels:
app: myapp # service 名稱
spec:
ports:
- port: 80
name: web
clusterIP: None # 配置headless service
selector:
app: myapp-pod # 匹配Pod 標簽
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: myapp
spec:
serviceName: myapp # 名稱
replicas: 3 # 三個副本
selector:
matchLabels:
app: myapp-pod # 匹配Pod
template:
metadata:
labels:
app: myapp-pod
spec:
containers:
- name: myapp
image: ikubernetes/myapp:v1
ports:
- containerPort: 80
name: web
volumeMounts:
- name: myappdata
mountPath: /usr/shar/nginx/html
volumeClaimTemplates:
- metadata:
name: myappdata # pvc名稱
spec:
accessModes: ["ReadWriteOnce"] # 權限
resources:
requests:
storage: 5Gi # pv 大小
創建
[root@master manifests]# kubectl apply -f statefulset-demo.yaml
service/myapp-svc unchanged
statefulset.apps/myapp created
[root@master manifests]# kubectl get sts
NAME READY AGE
myapp 3/3 5s
[root@master manifests]# kubectl get pods
NAME READY STATUS RESTARTS AGE
myapp-0 1/1 Running 0 92s
myapp-1 1/1 Running 0 91s
myapp-2 1/1 Running 0 32s
StatefulSet 會自動創建pvc, 然后去綁定對應符合要求的PV
[root@master manifests]# kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
myappdata-myapp-0 Bound pv002 5Gi RWO 2m42s
myappdata-myapp-1 Bound pv003 5Gi RWO,RWX 66s
myappdata-myapp-2 Bound pv001 5Gi RWO,RWX 7s
[root@master manifests]# kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pv001 5Gi RWO,RWX Retain Bound default/myappdata-myapp-2 20m
pv002 5Gi RWO Retain Bound default/myappdata-myapp-0 20m
pv003 5Gi RWO,RWX Retain Bound default/myappdata-myapp-1 20m
pv004 10Gi RWO,RWX Retain Available 20m
pv005 10Gi RWO,RWX Retain Available 20m
statefulset管理pod的啟停順序
- 有序部署:部署StatefulSet時,如果有多個Pod副本,它們會被順序地創建(從0到N-1)並且,在下一個Pod運行之前所有之前的Pod必須都是Running和Ready狀態。
- 有序刪除:當Pod被刪除時,它們被終止的順序是從N-1到0。
- 有序擴展:當對Pod執行擴展操作時,與部署一樣,它前面的Pod必須都處於Running和Ready狀態
statefulset管理策略
-
OrderedReady:上述的啟停順序,默認設置。
spec: podManagementPolicy: OrderedReady
-
Parallel:告訴StatefulSet控制器並行啟動或終止所有Pod,並且在啟動或終止另一個Pod之前不等待前一個Pod變為Running and Ready或完全終止。
spec: podManagementPolicy: Parallel
擴容pod實驗(順序增加)
[root@master manifests]# kubectl scale sts myapp --replicas=5 #擴容到5個pod
[root@master manifests]# kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
myappdata-myapp-0 Bound pv002 5Gi RWO 14m
myappdata-myapp-1 Bound pv003 5Gi RWO,RWX 14m
myappdata-myapp-2 Bound pv001 5Gi RWO,RWX 14m
myappdata-myapp-3 Bound pv004 10Gi RWO,RWX 7s
myappdata-myapp-4 Bound pv005 10i RWO,RWX 7s
縮減pod實驗(逆序減小,從最后的開始縮減)
[root@master manifests]# kubectl scale sts myapp --replicas=2 #縮減到2個pod
[root@master manifests]# kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
myappdata-myapp-0 Bound pv002 5Gi RWO 14m
myappdata-myapp-1 Bound pv003 5Gi RWO,RWX 14m
statefulSet的更新策略:
kubectl explain sts.spec.updateStrategy.rollingUpdate
partition: 這種更新策略的含義是, 若當前statefulSet的副本數為5個,則Pod名為pod-0~pod-4,那么此時定義partition=4, 就意味着我要更新大於等於4的Pod,而只有pod-4的ID 4 是大於等於4的,所以只有pod-4會被更新,其它不會,這就是金絲雀更新。若后期發現pod-4更新后,工作一切正常,那么就可以調整partition=0,這樣只要大於等於0的pod ID都將被更新。
金絲雀更新
修改滾動更新策略,查看效果
kubectl patch sts myapp -p '{"spec":{"updateStrategy":{"rollingUpdate":{"partition":2}}}}'
#修改statefulset的image
kubectl set image sts/myapp myapp=ikubernetes/myapp:v2
#查看已經修改成功了
[root@master statfulset]# kubectl get sts myapp -o wide
NAME READY AGE CONTAINERS IMAGES
myapp 4/4 16h myapp ikubernetes/myapp:v2
因為策略寫的是從第二個容器開始更新
通過命令
kubectl get pod myapp-1 -o yaml
可以看到2
之前的image沒有改變通過命令
kubectl get pod myapp-2 -o yaml
可以看到2
之后的image都已經改變了
#再重新把partition改為0, 則把之前的pod的image都修改生效了
kubectl patch sts myapp -p '{"spec":{"updateStrategy":{"rollingUpdate":{"partition":0}}}}'
[root@master statfulset]# kubectl get pods -l app=myapp-pod -o custom-columns=NAME:metadata.name,IMAGE:spec.containers[0].image
NAME IMAGE
myapp-0 ikubernetes/myapp:v2
myapp-1 ikubernetes/myapp:v2
myapp-2 ikubernetes/myapp:v2
myapp-3 ikubernetes/myapp:v2
暫存更新操作
分區更新操作
將spec.updateStrategy.rollingUpdate.partition設置為Pod副本數量時,即意味着所有Pod資源都不會處於可直接更新的分區內,直到partition小於Pod數時,才會開始更新
此時,即便刪除某Pod,也會按舊版本進行重建,即暫存狀態的更新對所有Pod資源均不產生影響
使用go-template
自定義資源輸出信息
kubectl get pod myapp-1 -o go-template --template='{{.status.podIP}}'
[root@master statfulset]# kubectl get pod myapp-1 -o go-template --template='{{range .spec.containers}}{{.image}}{{end}}'
ikubernetes/myapp:v2
因為這里查看containers的image信息是一個列表信息, 所以要用到range
關於更多的go-template
的使用方法, 可以參考這位老哥寫的博客: https://www.bbsmax.com/A/gAJGgjX3JZ/
訪問測試:pod_name.service.ns_name.svc.cluster.local (myapp-2.myapp.default.svc.cluster.local)