StatefulSet详解
????????RC、Deployment、DaemonSet都是面向无状态的服务,它们所管理的Pod的IP、名字,启停顺序等都是随机的,而StatefulSet是管理所有有状态的服务,比如MySQL、MongoDB集群等。
????????StatefulSet本质上是Deployment的一种变体,在v1.9版本中已成为GA版本,它为了解决有状态服务的问题,它所管理的Pod拥有固定的Pod名称,启停顺序,在StatefulSet中,Pod名字称为网络标识(hostname),还必须要用到共享存储。
????????在Deployment中,与之对应的服务是service,而在StatefulSet中与之对应的headless service,headless service,即无头服务,与service的区别就是它没有Cluster IP,解析它的名称时将返回该Headless Service对应的全部Pod的Endpoint列表。
????????除此之外,StatefulSet在Headless Service的基础上又为StatefulSet控制的每个Pod副本创建了一个DNS域名,
这个域名的格式为:statefulSetName-{0…N-1}.serviceName.namespace.svc.cluster.local
1、statefulSetName为StatefulSet的名字
2、0..N-1为Pod所在的序号,从0开始到N-1
3、serviceName为Headless Service的名字
4、namespace为服务所在的namespace,Headless Servic和StatefulSet必须在相同的namespace
5、.svc.cluster.local为Cluster Domain
创建顺序如下:
1、Volume
2、Persistent Volume
3、Persistent Volume Claim
4、Service
5、StatefulSet
一个完整的StatefulSet由一个Headless Service、一个StatefulSet、和一个volumeClaim Template组成。
#StatefulSet 资源清单
[root@k8s-master mainfests]# vim stateful-demo.yaml
apiVersion: v1
kind: Service
metadata:
name: myapp-svc
labels:
app: myapp-svc
spec:
ports:
- port: 80
name: web
clusterIP: None
selector:
app: myapp-pod
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: myapp
spec:
serviceName: myapp-svc #声明它属于哪个Headless Service.
replicas: 3#副本数
selector:#那个pod 是由自己管理的
matchLabels:
app: myapp-pod #必须匹配 .spec.template.metadata.labels
template:#定义pod模板
metadata:
labels:
app: myapp-pod # 必须配置 .spec.selector.matchLabels
spec:
containers:
- name: myapp
image: ikubernetes/myapp:v1
ports:
- containerPort: 80
name: web
volumeMounts:
- name: myappdata
mountPath: /usr/share/nginx/html
volumeClaimTemplates: #生成PVC模板
- metadata:
name: myappdata
spec:
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 1Gi
创建Headless Service和StatefulSet,并进行解析验证
再打开一个界面 #kubectl get pods -w -lapp=demo-nginx 使用 -w -l 实时查看创建过程
[root@k8s-master-1 test]# kubectl apply -f statefulSet.yaml
service/demo-service created
statefulset.apps/demo-statefulset created
#创建成功之后就可以看到service以及创建的3个pod
[root@k8s-master-1 test]# kubectl get service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
demo-service ClusterIP None <none> 80/TCP 2m24s
[root@k8s-master-1 test]# kubectl get pods
NAME READY STATUS RESTARTS AGE
busybox 1/1 Running 61 9d
demo-statefulset-0 1/1 Running 0 4m13s
demo-statefulset-1 1/1 Running 0 4m12s
demo-statefulset-2 1/1 Running 0 4m10s
#检查状态 发现StatefulSet给他所管理的pod的名字,进行了编号,pod的hostname与Pod的名字一致。
[root@k8s-master-1 test]# kubectl exec demo-statefulset-0 -- sh -c 'hostname'
demo-statefulset-0
[root@k8s-master-1 test]# kubectl exec demo-statefulset-1 -- sh -c 'hostname'
demo-statefulset-1
[root@k8s-master-1 test]# kubectl exec demo-statefulset-2 -- sh -c 'hostname'
demo-statefulset-2
[root@k8s-master-1 test]#
#验证DNS
#进入一个容器,可以看到已经被成功解析
[root@k8s-master-1 test]# kubectl exec -it busybox sh
/ #
/ # nslookup demo-service
Server: 10.0.0.2
Address 1: 10.0.0.2 kube-dns.kube-system.svc.cluster.local
Name: demo-service
Address 1: 10.244.0.72 demo-statefulset-0.demo-service.default.svc.cluster.local
Address 2: 10.244.0.73 demo-statefulset-2.demo-service.default.svc.cluster.local
Address 3: 10.244.1.61 demo-statefulset-1.demo-service.default.svc.cluster.local
#单独解析
/ #
/ # nslookup demo-statefulset-0.demo-service.default.svc.cluster.local
Server: 10.0.0.2
Address 1: 10.0.0.2 kube-dns.kube-system.svc.cluster.local
Name: demo-statefulset-0.demo-service.default.svc.cluster.local
Address 1: 10.244.0.95 demo-statefulset-0.demo-service.default.svc.cluster.local
/ #
/ # nslookup demo-statefulset-1.demo-service.default.svc.cluster.local
Server: 10.0.0.2
Address 1: 10.0.0.2 kube-dns.kube-system.svc.cluster.local
Name: demo-statefulset-1.demo-service.default.svc.cluster.local
Address 1: 10.244.1.77 demo-statefulset-1.demo-service.default.svc.cluster.local
/ #
/ # ping 也是可以ping通的
/ # ping demo-statefulset-0.demo-service.default.svc.cluster.local
PING demo-statefulset-0.demo-service.default.svc.cluster.local (10.244.0.95): 56 data bytes
64 bytes from 10.244.0.95: seq=0 ttl=62 time=0.315 ms
64 bytes from 10.244.0.95: seq=1 ttl=62 time=0.274 ms
64 bytes from 10.244.0.95: seq=2 ttl=62 time=0.267 ms
/ #
/ # exit
[root@k8s-master-1 test]#
[root@k8s-master-1 test]# kubectl get pod -owide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
busybox 1/1 Running 62 9d 10.244.1.57 k8s-node-2 <none> <none>
demo-statefulset-0 1/1 Running 0 23m 10.244.0.72 k8s-node-1 <none> <none>
demo-statefulset-1 1/1 Running 0 23m 10.244.1.61 k8s-node-2 <none> <none>
demo-statefulset-2 1/1 Running 0 23m 10.244.0.73 k8s-node-1 <none> <none>
web-96d5df5c8-sw784 1/1 Running 5 5d1h 10.244.0.69 k8s-node-1 <none> <none>
滚动更新时,把这几个 Pod 删除之后,Kubernetes 会按照原先编号的顺序,创建出了两个新的 Pod。并且,
Kubernetes 依然为它们分配了与原来相同的“网络身份”:demo-statefulset-0 ,demo-statefulset-1 和demo-statefulset-2。
通过这种严格的对应规则,StatefulSet 就保证了 Pod 网络标识的稳定性。
总结:
????????Kubernetes成功的将Pod的拓扑状态,按照Pod的名字+编号的方式固定下来,此外Kubernetes还为每个pod提供了一个固定并且唯一的访问入口,即:这个Pod对应额DNS记录,这些状态,在StatefulSet的整个生命周期里都保持不变,绝不会因为pod的删除或者重新创建而时效。
????????当StatefulSet的控制循环发现pod 的实际状态于“期望状态”不一致时,需要新建或者删除POD进行调谐的时候, 会严格按照pod的编号顺序,逐一完成操作。
????????Kubernetes项目引入了一组叫做 Persistent Volume Clain(PVC)和 Persistent Volume(PV)的API对象,大大降低了用户声明和使用持久化Volume的门槛。
????????PVC :PVC就是一种特殊的Volume,只不过一个PVC具体是什么类型的Volume,要在跟某个PV绑定之后才知道,这些PVC,都以“--”的方式命名并且处于Bound状态,这个StatefulSet创建出来的多有pod,都会声明使用编号的PVC.?
????????statefulSet支持两种更新策略:OnDelete和人rollingUpdate(默认),其中Ondelete表示删除之后才更新,RollingUpdate是滚动更新
updateStrategy:
rollingUpdate: # 如果更新的策略是OnDelete,那么rollingUpdate就失效
partition: 2 # 表示从第2个分区开始更新,<2的pod 不会被更新。默认是0,
type: RollingUpdate /OnDelete # 滚动更新
#扩容语法:kubectl scale sts <statefulsetPodName> --replicas=5
[root@k8s-master-1 test]# kubectl scale sts demo-statefulset --replicas=5
statefulset.apps/demo-statefulset scaled
[root@k8s-master-1 test]#
[root@k8s-master-1 test]#
[root@k8s-master-1 test]#
[root@k8s-master-1 test]# kubectl get pod
NAME READY STATUS RESTARTS AGE
busybox 1/1 Running 5 22h
demo-statefulset-0 1/1 Running 0 109s
demo-statefulset-1 1/1 Running 0 108s
demo-statefulset-2 1/1 Running 0 106s
demo-statefulset-3 1/1 Running 0 4s
demo-statefulset-4 1/1 Running 0 3s
web-96d5df5c8-sw784 1/1 Running 6 6d1h
#缩容
[root@k8s-master-1 test]# kubectl scale sts demo-statefulset --replicas=3
statefulset.apps/demo-statefulset scaled
[root@k8s-master-1 test]#
[root@k8s-master-1 test]#
[root@k8s-master-1 test]# kubectl get pod
NAME READY STATUS RESTARTS AGE
busybox 1/1 Running 5 22h
demo-statefulset-0 1/1 Running 0 5m35s
demo-statefulset-1 1/1 Running 0 5m34s
demo-statefulset-2 1/1 Running 0 5m32s
web-96d5df5c8-sw784 1/1 Running 6 6d1h
#查看标签
[root@k8s-master-1 test]# kubectl get pod --show-labels
#查看详细执行过程
[root@k8s-master-1 ~]# kubectl get pod -w -l app=demo-nginx
[root@k8s-master-1 test]# #级联删除
[root@k8s-master-1 test]# kubectl delete sts demo-statefulset
statefulset.apps "demo-statefulset" deleted
[root@k8s-master-1 test]# #非级联删除
[root@k8s-master-1 test]#
[root@k8s-master-1 test]# kubectl delete sts demo-statefulset --cascade=false
statefulset.apps "demo-statefulset" deleted
[root@k8s-master-1 test]#
[root@k8s-master-1 test]#
[root@k8s-master-1 test]# kubectl get sts
No resources found in default namespace.
[root@k8s-master-1 test]#
[root@k8s-master-1 test]# kubectl get pod
NAME READY STATUS RESTARTS AGE
demo-statefulset-0 1/1 Running 0 118s
demo-statefulset-1 1/1 Running 0 117s
demo-statefulset-2 1/1 Running 0 115s
#此时pod就成了孤儿pod,删除pod时不会被重建,如果不是非级联删除,单独删除pod则回被重新创建。