微信小程序本地存储与登录页面处理实例详细讲解
752
2022-09-27
Kubernetes 一文详解StatefulSet 控制器
无状态与有状态
Deployment控制器设计原则:管理的所有Pod一模一样,提供同一个服务,也不考虑在哪台Node运行,可随意扩容和缩容。这种应用称为“无状态”,例如Web服务
在实际的场景中,并不能满足所有应用,尤其是分布式应用,会部署多个实例,这些实例之间往往有依赖关系,例如主从关系、主备关系,这种应用称为“有状态”,例如MySQL主从、Etcd集群
StatefulSet 控制器概述
StatefulSet控制器用于部署有状态应用,满足一些有状态应
用的需求:
• Pod有序的部署、扩容、删除和停止
• Pod分配一个稳定的且唯一的网络标识
• Pod分配一个独享的存储
Deployment数据卷是共享的,当创建3个pod都是用的同一个数据卷,对外提供统一的服务。
StatefulSet 控制器:主机名
稳定的网络标识:使用Headless Service(相比普通Service只是将spec.clusterIP定义为None)来维护Pod网络身份,会为每个Pod分配一个数字编号并且按照编号顺序部署。还需要在StatefulSet添加serviceName: “nginx”字段指定StatefulSet控制器要使用这个Headless Service。
稳定主要体现在主机名和Pod A记录:
• 主机名:
• Pod DNS A记录:
之前的service会自动的帮你填充cluster ip,这里将字段设置为none,不会分配,和deployment不同,deployment都是提供相同的统一的入口。有状态的都是提供独立的访问。
[root@k8s-master ~]# cat service.yaml apiVersion: v1kind: Servicemetadata: name: headless-web namespace: defaultspec: clusterIP: None ports: - port: 80 protocol: TCP targetPort: 80 selector: app: nginx type: ClusterIP[root@k8s-master ~]# kubectl apply -f service.yaml service/headless-web created[root@k8s-master ~]# kubectl get svcNAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGEheadless-web ClusterIP None
可以看到没有为其分配cluster ip
稳定的网络标识怎么体现的,为每个pod分配固定的主机名,并且会创建dns记录
[root@k8s-master ~]# cat statefulset-web.yml apiVersion: apps/v1kind: StatefulSetmetadata: name: webspec: serviceName: "headless-web" replicas: 3 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx ports: - containerPort: 80 name: web[root@k8s-master ~]# kubectl get podNAME READY STATUS RESTARTS AGEnfs-client-provisioner-d565bb89b-8d9hp 1/1 Running 4 26hweb-0 1/1 Running 0 99sweb-1 1/1 Running 0 39sweb-2 1/1 Running 0 22s
这个主机名是固定的,即使pod被删除掉了,重新启动也是这个名称上面体现了稳定的主机名
[root@k8s-master ~]# kubectl exec web-0 -- hostnameweb-0[root@k8s-master ~]# kubectl exec web-1 -- hostnameweb-1[root@k8s-master ~]# kubectl exec web-2 -- hostnameweb-2
可见,对于一个拥有 N 个副本的 StatefulSet 来说,Pod 在部署时按照 {0 …… N-1} 的序号顺序创建的,而删除的时候按照逆序逐个删除,这便是我想说的第一个特性。StatefulSet 创建出来的 Pod 都具有固定的、且确切的主机名。
StatefulSet 控制器:网络标识
可以看到,每个 Pod 都有一个对应的 A 记录。
[root@k8s-master ~]# kubectl run -i -t dns-test --image busybox:1.28.4 /bin/shIf you don't see a command prompt, try pressing enter./ # nslookup headless-web.default.svc.cluster.localServer: 10.96.0.10Address 1: 10.96.0.10 kube-dns.kube-system.svc.cluster.localName: headless-web.default.svc.cluster.localAddress 1: 10.244.169.147 web-2.headless-web.default.svc.cluster.localAddress 2: 10.244.169.146 web-1.headless-web.default.svc.cluster.localAddress 3: 10.244.36.81 web-0.headless-web.default.svc.cluster.local/ # ping web-0.headless-web.default.svc.cluster.localPING web-0.headless-web.default.svc.cluster.local (10.244.36.81): 56 data bytes64 bytes from 10.244.36.81: seq=0 ttl=62 time=1.105 ms64 bytes from 10.244.36.81: seq=1 ttl=62 time=2.990 ms64 bytes from 10.244.36.81: seq=2 ttl=62 time=1.408 ms^C
这里解析出来了三条,任意访问其中的一条可以访问具体的pod,即使pod重建ip发生变化,也能够通过这个记录解析到新的Ip上面
有头服务只会解析出一条记录
上面固定的dns名称和主机名就是网络标识的体现
删除一下这些 Pod,看看会有什么变化:
[root@k8s-master ~]# kubectl get podNAME READY STATUS RESTARTS AGEdns-test 1/1 Running 0 10mnfs-client-provisioner-d565bb89b-8d9hp 1/1 Running 4 26hweb-0 1/1 Running 0 14mweb-1 1/1 Running 0 13mweb-2 1/1 Running 0 13m[root@k8s-master ~]# kubectl delete pod web-0pod "web-0" deleted/ # nslookup headless-web.default.svc.cluster.localServer: 10.96.0.10Address 1: 10.96.0.10 kube-dns.kube-system.svc.cluster.localName: headless-web.default.svc.cluster.localAddress 1: 10.244.36.82 web-0.headless-web.default.svc.cluster.localAddress 2: 10.244.169.147 web-2.headless-web.default.svc.cluster.localAddress 3: 10.244.169.146 web-1.headless-web.default.svc.cluster.local
可以看出,DNS 记录中 Pod 的域名没有发生变化,仅仅 IP 地址发生了更换。因此当 Pod 所在的节点发生故障导致 Pod 飘移到其他节点上,或者 Pod 因故障被删除重建,Pod 的 IP 都会发生变化,但是 Pod 的域名不会有任何变化,这也就意味着服务间可以通过不变的 Pod 域名来保障通信稳定,而不必依赖 Pod IP。
有了spec.serviceName这个字段,保证了 StatefulSet 关联的 Pod 可以有稳定的网络身份标识,即 Pod 的序号、主机名、DNS 记录名称等。
StatefulSet 控制器:独享存储
最后一个我想说的是,对于有状态的服务来说,每个副本都会用到持久化存储,且各自使用的数据是不一样的。
StatefulSet 通过 PersistentVolumeClaim(PVC)可以保证 Pod 的存储卷之间一一对应的绑定关系。同时,删除 StatefulSet 关联的 Pod 时,不会删除其关联的 PVC。
独享存储:StatefulSet的存储卷使用VolumeClaimTemplate创建,称为卷申请模板,当StatefulSet使用VolumeClaimTemplate创建一个PersistentVolume时,同样也会为每个Pod分配并创建一个编号的PVC,每个PVC绑定对应的PV,从而保证每个Pod都拥有独立的存储。
[root@k8s-master ~]# cat statefulset-web.yml apiVersion: apps/v1kind: StatefulSet metadata: name: webspec: serviceName: "headless-web" replicas: 3 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx ports: - containerPort: 80 name: web volumeMounts: - name: mountPath: /usr/share/nginx/html volumeClaimTemplates: - metadata: name: spec: storageClassName: "managed-nfs-storage" accessModes: - ReadWriteOnce resources: requests: storage: 1Gi[root@k8s-master ~]# kubectl apply -f statefulset-web.yml statefulset.apps/web created
volumeClaimTemplates: 这个字段delploy是不支持的,只要state支持,这个是通过动态供给完成的,实际上还是申请pvc pv ,~]# kubectl get pvc,pvNAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGEpersistentvolumeclaim/ Bound pvc-7403fc64-998a-4d94-9bf7-00cde6f4e52d 1Gi RWO managed-nfs-storage 87spersistentvolumeclaim/ Bound pvc-9c10db54-3a82-4374-ad24-b14b59d4819e 1Gi RWO managed-nfs-storage 66spersistentvolumeclaim/ Bound pvc-d8ea2562-6137-404f-bef9-b0c9f700a040 1Gi RWO managed-nfs-storage 44sNAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGEpersistentvolume/pvc-7403fc64-998a-4d94-9bf7-00cde6f4e52d 1Gi RWO Delete Bound default/ managed-nfs-storage 86spersistentvolume/pvc-9c10db54-3a82-4374-ad24-b14b59d4819e 1Gi RWO Delete Bound default/ managed-nfs-storage 66spersistentvolume/pvc-d8ea2562-6137-404f-bef9-b0c9f700a040 1Gi RWO Delete Bound default/ managed-nfs-storage
Pvc和pv一一绑定的,可以看到每个独立的Pod都有独立的pv
[root@reg kubernetes]# pwd/ifs/kubernetes[root@reg kubernetes]# lsdefault-pvc不会被删除,并且删除重建之后还是可以读取之前的数据,当pod被重建之后,k8s还是根据pod编号找对应的pvc进行挂载
如何更新升级 StatefulSet
那么,如果想对一个 StatefulSet 进行升级,该怎么办呢?
在 StatefulSet 中,支持两种更新升级策略,即 RollingUpdate 和 OnDelete。
RollingUpdate策略是默认的更新策略。可以实现 Pod 的滚动升级,跟我们上一节课中 Deployment 介绍的RollingUpdate策略一样。比如我们这个时候做了镜像更新操作,那么整个的升级过程大致如下,先逆序删除所有的 Pod,然后依次用新镜像创建新的 Pod 出来。这里你可以通过kubectl get pod -n demo -w -l app=nginx来动手观察下。
总结
现在我们就总结下 StatefulSet 的特点:
具备固定的网络标记,比如主机名,域名等;支持持久化存储,而且最好能够跟实例一一绑定;可以按照顺序来部署和扩展;可以按照顺序进行终止和删除操作;在进行滚动升级的时候,也会按照一定顺序。
借助 StatefulSet 的这些能力,我们就可以去部署一些有状态服务,比如 MySQL、ZooKeeper、MongoDB 等。你可以跟着这个教程在 Kubernetes 中搭建一个 ZooKeeper 集群。
同时使用 RollingUpdate 更新策略还支持通过 partition 参数来分段更新一个 StatefulSet。所有序号大于或者等于 partition 的Pod 都将被更新。你这里也可以手动更新 StatefulSet 的配置来实验下。
当你把更新策略设置为 OnDelete 时,我们就必须手动先删除 Pod,才能触发新的 Pod 更新。
版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。
发表评论
暂时没有评论,来抢沙发吧~