明天一点基础K8S---K8S中的statefulset
### statefulSet
#### 1、背景
```
# 之前学习的deployment控制器,他所管理的pod一模一样,提供同一服务,不用考虑在哪台node运行,可以随意扩容缩容。我们把这类应用称作“无状态应用”,例如nginx web服务。
# 但是在实际场景中,对于一些分布式应用,比如mysql三节点集群,会部署3个实例,每个实例并不完全一样,有master和slave之分。并且这些实例之间往往有一定的依赖关系(主从、主备等),这类应用称作“有状态应用”,例如mysql主从,etcd集群。
```
```
statefulset有5部分需要学习:
1. 如何创建 StatefulSet
2. StatefulSet 怎样管理它的 Pod
3. 如何删除 StatefulSet
4. 如何对 StatefulSet 进行扩容/缩容
5. 如何更新一个 StatefulSet 的 Pod
```
#### 2、创建statufulSet
```shell
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: test-statefulset
spec:
#updateStrategy: OnDelete or RollingUpdate # 升级策略
#podManagementPolicy: OrderedReady or Parallel # POD管理策略,用于扩容或者缩容时
replicas: 2 # 副本数
selector:
matchLabels: # 此处的label与container的label对应
func: statefulset
serviceName: test-statefulset # service需要先于statefulset创建
volumeClaimTemplates: # 存储卷申请模版,此处采用pvc,后段是storageClass动态创建PV。
- apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pvc-storageclass
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 100Mi
storageClassName: from-nfs
template: # POD模版
metadata:
labels:
func: statefulset
spec:
containers:
- name: nginx
image: nginx
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
volumeMounts:
- mountPath: /mnt
name: pvc-storageclass
```
```shell
[root@master-worker-node-1 statefulset]# kubectl apply -f statefulset.yaml
statefulset.apps/test-statefulset created
# statefulset状态正常
[root@master-worker-node-1 statefulset]# kubectl get statefulset -o wide
NAME READY AGE CONTAINERS IMAGES
test-statefulset 2/2 100s nginx nginx
# 存储申请模版中制定了PVC,检查PVC可以正常创建,PVC数量与statefulset中制定的replicas数量一致。PVC的名称组成:存储模版名称+statefulset名称+序号
[root@master-worker-node-1 statefulset]# kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
pvc-storageclass-test-statefulset-0 Bound pvc-07190644-f15a-4389-888e-1cf234633c39 100Mi RWX from-nfs 7m42s
pvc-storageclass-test-statefulset-1 Bound pvc-9714aa04-e8af-42a3-8fb8-12b05ff02039 100Mi RWX from-nfs 6m55s
# storageClass自动创建的PV
[root@master-worker-node-1 statefulset]# kubectl get pv -o wide
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE VOLUMEMODE
pvc-07190644-f15a-4389-888e-1cf234633c39 100Mi RWX Delete Bound default/pvc-storageclass-test-statefulset-0 from-nfs 5m37s Filesystem
pvc-9714aa04-e8af-42a3-8fb8-12b05ff02039 100Mi RWX Delete Bound default/pvc-storageclass-test-statefulset-1 from-nfs 4m49s Filesystem
# POD运行正常,POD的序号是有序的。且POD的名称不能随意修改。
[root@master-worker-node-1 ~]# kubectl get pods -o wide -w
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nfs-provisioner-9f9fc45fd-l4f6l 1/1 Running 2 (33h ago) 2d9h 10.244.31.26 only-worker-node-3 <none> <none>
test-statefulset-0 0/1 Pending 0 0s <none> <none> <none> <none>
test-statefulset-0 0/1 Pending 0 0s <none> only-worker-node-3 <none> <none>
test-statefulset-0 0/1 ContainerCreating 0 0s <none> only-worker-node-3 <none> <none>
test-statefulset-0 0/1 ContainerCreating 0 2s <none> only-worker-node-3 <none> <none>
test-statefulset-0 1/1 Running 0 4s 10.244.31.25 only-worker-node-3 <none> <none>
test-statefulset-1 0/1 Pending 0 0s <none> <none> <none> <none>
test-statefulset-1 0/1 Pending 0 0s <none> only-worker-node-4 <none> <none>
test-statefulset-1 0/1 ContainerCreating 0 0s <none> only-worker-node-4 <none> <none>
test-statefulset-1 0/1 ContainerCreating 0 1s <none> only-worker-node-4 <none> <none>
test-statefulset-1 1/1 Running 0 3s 10.244.54.11 only-worker-node-4 <none> <none>
# 甚至POD内的hostname也是有指定了的,hostname与pod name相同。
[root@master-worker-node-1 statefulset]# for i in {0,1};do kubectl exec -it test-statefulset-$i -- hostname; done
test-statefulset-0
test-statefulset-1
# statefulset中的service需要为headless service,下文将进行解释。
[root@master-worker-node-1 statefulset]# kubectl get service -o wide
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
headless-service ClusterIP None <none> 1880/TCP 70s func=statefulset
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 30d <none>
test-statefulset NodePort 10.111.212.91 <none> 80:30080/TCP 23h func=statefulset
```
#### 3、statefulset的组成
```
1、headless service
2、volumeClaimTemplate: 卷神器模版
3、statefulset: 功能控制POD数量
```
#### 4、headless service的功能和作用
```
对于deployment部署的资源,将服务端口通过普通service暴露出来。即使deployment管理的pod重建,但是其label一样,仍然可以被service管理。那按理statefulset也可以这样实现呢?
按照statefulset定义,通过statefulset定义的资源具有顺序并且具有稳定的身份标识。在其他控制器中,可以通过解析service的DNS返回service的cluster IP。而通过headless service暴露statefulset服务,不仅可以通过service的DNS解析出所有pod的DNS和IP,并且每个POD都有自己固定的域名。
```
```
[root@master-worker-node-1 statefulset]# kubectl run -i -t --image busybox:1.28 test --restart=Never --rm
If you don't see a command prompt, try pressing enter.
/ # nslookup headless-service.default.svc.cluster.local
Server: 10.96.0.10
Address 1: 10.96.0.10 kube-dns.kube-system.svc.cluster.local
Name: headless-service.default.svc.cluster.local
Address 1: 10.244.31.25 test-statefulset-0.test-statefulset.default.svc.cluster.local
Address 2: 10.244.54.11 test-statefulset-1.test-statefulset.default.svc.cluster.local
/ # nslookup test-statefulset-0.test-statefulset
Server: 10.96.0.10
Address 1: 10.96.0.10 kube-dns.kube-system.svc.cluster.local
Name: test-statefulset-0.test-statefulset
Address 1: 10.244.31.25 test-statefulset-0.test-statefulset.default.svc.cluster.local
/ # nslookup test-statefulset-1.test-statefulset
Server: 10.96.0.10
Address 1: 10.96.0.10 kube-dns.kube-system.svc.cluster.local
Name: test-statefulset-1.test-statefulset
Address 1: 10.244.54.11 test-statefulset-1.test-statefulset.default.svc.cluster.local
```
#### 5、volumeClaimTemplate功能和作用
```
对比deployment的yaml文件,volume定义是在deployment.spec.template.spec.volumes中指明。即使replicas是多副本,但仍只有一个卷,即所有POD公用一个volume。
而statefulset常用于搭建有状态服务集群,例如mysql主从,etcd集群等。每个pod都需要独立的存储,此时就需要卷申请模版,为每个POD申请一个volume。
```
#### 6、Statefulset的扩容、缩容和更新
##### 6.1 扩容
```shell
# 命令一
[root@master-worker-node-1 statefulset]# kubectl scale statefulset test-statefulset --replicas=3
statefulset.apps/test-statefulset scaled
[root@master-worker-node-1 statefulset]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nfs-provisioner-9f9fc45fd-l4f6l 1/1 Running 2 (34h ago) 2d10h 10.244.31.26 only-worker-node-3 <none> <none>
test-statefulset-0 1/1 Running 0 4m41s 10.244.31.27 only-worker-node-3 <none> <none>
test-statefulset-1 1/1 Running 0 40m 10.244.54.11 only-worker-node-4 <none> <none>
test-statefulset-2 1/1 Running 0 2m15s 10.244.31.29 only-worker-node-3 <none> <none>
# 命令二
kubectl edit statefulset test-statefulset
# 命令三
[root@master-worker-node-1 statefulset]# kubectl patch statefulset test-statefulset -p '{"spec":{"replicas":4}}'
statefulset.apps/test-statefulset patched
```
##### 6.2 缩容
```shell
# 缩容是将pod序号大的删除,而不是deployment随机删除。
[root@master-worker-node-1 statefulset]# kubectl edit statefulset test-statefulset
statefulset.apps/test-statefulset edited
[root@master-worker-node-1 statefulset]# kubectl get statefulset test-statefulset -o yaml | grep replicas:
replicas: 2
replicas: 2
[root@master-worker-node-1 statefulset]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nfs-provisioner-9f9fc45fd-l4f6l 1/1 Running 2 (34h ago) 2d10h 10.244.31.26 only-worker-node-3 <none> <none>
test-statefulset-0 1/1 Running 0 31m 10.244.31.27 only-worker-node-3 <none> <none>
test-statefulset-1 1/1 Running 0 67m 10.244.54.11 only-worker-node-4 <none> <none>
```
##### 6.3 更新
```
kubectl patch statefulset .....
```
#### 小结
`1、statefulset常用管理有状态应用,其管理的POD有顺序区别。statefulset-0\1\2`
`2、创建statefulset时,需要提前准备好headless service,headless service不仅给service提供了DNS解析,也为statefulset的每个POD提供了DNS解析`
`3、statefulset中每个POD的数量都会靠volumeClaimTemplate申请独立的卷,数据目录为独享`