kubernetes云原生纪元:StatefulSet 状态守护者
kubernetes云原生纪元:StatefulSet状态守护者文章目录kubernetes云原生纪元:StatefulSet状态守护者介绍实践验证顺序性验证持久存储区分总结介绍之前我们使用的编排对象,都是Deployment,但是 Deployment并不能胜任所有的编排工作。之前的服务都是无状态、 pod无差别、没有顺序性。但是实际场景并不是所有应用都具备这样的条件。特别...
kubernetes云原生纪元:StatefulSet 状态守护者
介绍
之前我们使用的编排对象,都是Deployment ,但是 Deployment并不能胜任所有的编排工作。之前的服务都是无状态
、 pod无差别
、没有顺序性
。
但是实际场景并不是所有应用都具备这样的条件。特别是分布式应用,他们多个实例存在一些关系,比如主从关系
zk、etcd集群、redis主从…都有这样的特征。
对应这种多实例不对等的应用,kubernetes专门设计一种编排对象StatefulSet。
StatefulSet抽象了两种有状态的场景,主要解决两个问题。
第一种:
多个 pod之间的顺序性
,比如按一定顺序去启动,每个实例有自己的变化,再比如实例之间互相访问,互相通信,都可以根据顺序性特征去解决。
第二种:
持久存储区分
,对应持久存储区分
之前我们讲过在Deployment配置好持久存储区分的PVC,多个Pod之间就可以共享同一个目录了,一个Pod写入了文件,多个Pod都可以看到 。对于持久存储的区分
是让Pod 之间对应同一个目录是保持私有的,每个pod 都有自己的数据,当然这种只针对共享存储的,如果没有共享存储的需求,天然他们就是区分开的。就不需要考虑这样的问题了。
不管你是mysql主从、redis主备、zookeeper集群、etcd集群都是依靠StatefulSet这两种特性实现的。
实践
验证顺序性
我们来看一个Service 定义,跟其他区别就是clusterIP: None
,他是一个headlessService,它不会有Service的VIP,可以通过DNS的名字访问,返回的多个POD的IP列表。
headless-service.yaml
apiVersion: v1
kind: Service
metadata:
name: springboot-web-svc
spec:
ports:
- port: 80
targetPort: 8080
protocol: TCP
clusterIP: None
selector:
app: springboot-web
我们来看statefulSet 的配置,跟我们常用的Deployment区别不是很大,主要是 serviceName: springboot-web-svc
,这个就是告诉StatefulSet用哪个headlessService去保证每个POD的解析
🔨 statefulset.yaml
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: springboot-web
spec:
serviceName: springboot-web-svc # 通过Service名字指定headlessService
replicas: 2 # 两个实例用于测试
selector:
matchLabels:
app: springboot-web
template:
metadata:
labels:
app: springboot-web
spec:
containers:
- name: springboot-web
image: hub.zhang.com/kubernetes/spring-boot-demo:v1
ports:
- containerPort: 8080
livenessProbe:
tcpSocket:
port: 8080
initialDelaySeconds: 20
periodSeconds: 10
failureThreshold: 3
successThreshold: 1
timeoutSeconds: 5
readinessProbe:
httpGet: # 注意健康检查
path: /hello?name=test
port: 8080
scheme: HTTP
initialDelaySeconds: 20
periodSeconds: 10
failureThreshold: 1
successThreshold: 1
timeoutSeconds: 5
把上面的headless-service
和statefulset
都创建
[root@master-001 ~]# kubectl apply -f headless-service.yaml
service/springboot-web-svc created
[root@master-001 ~]# kubectl apply -f statefulset.yaml
statefulset.apps/springboot-web created
监控查看下,先启动springboot-web-0 在启动的springboot-web-1
[root@master-001 ~]# kubectl get pod -l app=springboot-web -w
NAME READY STATUS RESTARTS AGE
springboot-web-0 1/1 Running 0 118s
springboot-web-1 1/1 Running 0 94s
Pod 命令规则
名字的区分springboot-web-0拆解开springboot-web是来自于StatefulSet的名字,-0,-1是按实例数来排序的,比如有三个实例那里就是-0-1-2,
启动顺序是先启动-0,启动成功才会创建启动-1的
我们可以进入到springboot-web-0 和springboot-web-1容器里面会发现他们的hostname 跟他们的POD名字一样
我可以进入springboot-web-1容器通过名字ping springboot-web-0是否通
ping 的时候必须pod名后面要加headlessService的名字也就是
springboot-web-svc
[root@node-002 ~]# docker exec -it f2 sh
/ # hostname
springboot-web-1
/ # ping springboot-web-0.springboot-web-svc
PING springboot-web-0.springboot-web-svc (192.168.143.204): 56 data bytes
64 bytes from 192.168.143.204: seq=0 ttl=63 time=0.283 ms
64 bytes from 192.168.143.204: seq=1 ttl=63 time=0.109 ms
dns默认搜索范围参考search default.svc.cluster.local svc.cluster.local cluster.local localdomain,我们在 default命名空间下就不需要加命名空间
/ # vi /etc/resolv.conf
nameserver 10.96.0.10
search default.svc.cluster.local svc.cluster.local cluster.local localdomain
options ndots:5
我们在任何时候都可以通过名字加编号访问任何一个实例
验证持久存储区分
持久存储区分
的前提是要有共享存储的服务,也就是说必须要有存储后端和PV PVC
先删除上面的我们在测试,这个与上面唯一的区别就是 volumeClaimTemplates
创建PV的模版,为什么它这里不先指定一个PVC的名字呢,那样不就是共享的了嘛。但是我们先这里是存储区分开不符合我们当前的需求
volumeClaimTemplates
创建PV的模版,下面的定义业余PVC非常相似
🤠 statefulset-volume.yaml
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: springboot-web
spec:
serviceName: springboot-web-svc
replicas: 2
selector:
matchLabels:
app: springboot-web
template:
metadata:
labels:
app: springboot-web
spec:
containers:
- name: springboot-web
image: hub.mooc.com/kubernetes/springboot-web:v1
ports:
- containerPort: 8080
livenessProbe:
tcpSocket:
port: 8080
initialDelaySeconds: 20
periodSeconds: 10
failureThreshold: 3
successThreshold: 1
timeoutSeconds: 5
readinessProbe:
httpGet:
path: /hello?name=test
port: 8080
scheme: HTTP
initialDelaySeconds: 20
periodSeconds: 10
failureThreshold: 1
successThreshold: 1
timeoutSeconds: 5
volumeMounts:
- name: data
mountPath: /mooc-data
volumeClaimTemplates: # 唯一区别 volumeClaimTemplates创建PV的模版
- metadata:
name: data
spec: # 跟PVC的配置非常相似
accessModes:
- ReadWriteOnce #读写权限
storageClassName: glusterfs-storage-class # storageClass名字
resources:
requests:
storage: 1Gi # 使用大小
创建一下
[root@master-001 ~]# kubectl apply -f statefulset-volume.yaml
然后快速查看下PVC,可以看到已经有两个PVC了
再看下PV,也有两个PV
这就代表他们的存储是分开的了,不会共享自己只能访问自己的
⛵️ 测试存储的区分
我们来到spring-boot-1 的容器里面再对应数据卷挂载目录写一个hello文件
然后来到spring-boot-0 容器查看对应的数据卷挂载目录,很显然没有,这就符合存储区分的需求了
同理在spring-boot-0 创建一个文件也不会在spring-boot-1有,每个人都访问自己的文件空间,文件不会共享
🥕 测试文件持久性
我们把这个两个容器删除,然后重新创建
[root@master-001 ~]# kubectl delete -f statefulset-volume.yaml
[root@master-001 ~]# kubectl apply -f statefulset-volume.yaml
监控一下创建的状态-w
我再进入spring-boot-1 的容器,进入数据卷挂载目录查看一下我们测试存储区分创建的文件还在吗?,很显然它在,证明文件是有持久化的。
最后测试一个我们删除statefulset也就是statefulset-volume.yaml,看是否PV和PVC是否也被删除。
并没有删除PV和PVC,他只会自定生成PVC 并不会自动删除,如果确实不需要我们可以手动清除🆑掉。
![image-20200202113101736](https://gitee.com/zhangchengji/kubeSource/raw/master/image/image-20200202113101736.png)
总结
Statefulset 管理POD,他不像deployment,它下面每个实例都是独立的个体有自己的编号有自己的hostname,并且kubernetes 通过 headless-service为这些有编号的pod生成同样DNS 的记录,只要POD名字不变DNS记录也不会变,可能变的只是PODIP,所以不能通过POD访问它。
如果POD对存储有持久性并且有独占的需要,就需要用到volumeClaimTemplates
他会为每个POD自动生成一个PVC,保证每个POD都有自己独立的volume。
真实场景中用到肯定比现在复杂的多个,即用到顺序性也用到存储区分。关于Statefulset就说这么多。
更多推荐
所有评论(0)