k8s-StatefulSet
1、StatefulSet介绍 RC、Deployment、DaemonSet都是面向无状态的服务,它们所管理的Pod的IP、名字,启停顺序等都是随机的, 而StatefulSet是什么?顾名思义,有状态的集合,管理所有有状态的服务,比如MySQL、Bmongo复制集 ,redis cluster,rabbitmq cluster集群等。 StatefulSet本质上是Deployment的一种变体,在v1.9版本中已成为GA版本,它为了解决有状态服务的问题,它所管理的Pod拥有固定的Pod名称,启停顺序, 在StatefulSet中,Pod名字称为网络标识(hostname),还必须要用到共享存储。 在Deployment中,与之对应的服务是service,而在StatefulSet中与之对应的headless service,即无头服务,与service的区别就是它没有Cluster IP, 解析它的名称时将返回该Headless Service对应的全部Pod的Endpoint列表。 除此之外,StatefulSet在Headless Service的基础上又为StatefulSet控制的每个Pod副本创建了一个DNS域名,这个域名的格式为: $(podname).(headless server name) FQDN:$(podname).(headless server name).namespace.svc.cluster.local Headless Service:用来定义Pod网络标识( DNS domain)。 volumeClaimTemplates: 存储卷申请模板,创建PVC,指定pvc名称大小,将自动创建pvc,且pvc必须由存储类供应。 StatefulSet:定义具体应用,有多少个Pod副本,并为每个Pod定义了一个域名。 StatefulSet 特点: 给每个pod分配固定且唯一的网络标识符 给每个pod分配固定且持久化的外部存储 对pod进行有序的部署和扩展 对pod进有序的删除和终止 对pod进有序的自动滚动更新 2、特点 Pod一致性:包含次序(启动、停止次序)、网络一致性。此一致性与Pod相关,与被调度到哪个node节点无关; 稳定的次序:对于N个副本的StatefulSet,每个Pod都在[0,N)的范围内分配一个数字序号,且是唯一的; 稳定的网络:Pod的hostname模式为( s t a t e f u l s e t 名 称 ) − (statefulset名称)-(statefulset名称)−(序号); 稳定的存储:通过VolumeClaimTemplate为每个Pod创建一个PV。删除、减少副本,不会删除相关的卷。 3、组成部分 Headless Service:用来定义Pod网络标识( DNS domain); volumeClaimTemplates :存储卷申请模板,创建PVC,指定pvc名称大小,将自动创建pvc,且pvc必须由存储类供应; StatefulSet :定义具体应用,名为Nginx,有三个Pod副本,并为每个Pod定义了一个域名部署statefulset。 为什么需要 headless service 无头服务? 在用Deployment时,每一个Pod名称是没有顺序的,是随机字符串,因此是Pod名称是无序的,但是在statefulset中要求必须是有序 ,每一个pod不能被随意取代, pod重建后pod名称还是一样的。而pod IP是变化的,所以是以Pod名称来识别。pod名称是pod唯一性的标识符,必须持久稳定有效。这时候要用到无头服务,它可以给每个Pod一个唯一的名称 。 为什么需要volumeClaimTemplate? 对于有状态的副本集都会用到持久存储,对于分布式系统来讲,它的最大特点是数据是不一样的,所以各个节点不能使用同一存储卷,每个节点有自已的专用存储, 但是如果在Deployment中的Pod template里定义的存储卷,是所有副本集共用一个存储卷,数据是相同的,因为是基于模板来的 ,而statefulset中每个Pod都要自已的专有存储卷, 所以statefulset的存储卷就不能再用Pod模板来创建了,于是statefulSet使用volumeClaimTemplate,称为卷申请模板,它会为每个Pod生成不同的pvc,并绑定pv,从而实现各pod有专用存储。 这就是为什么要用volumeClaimTemplate的原因。 4、StatefulSet详解 kubectl explain sts.spec :主要字段解释 replicas :副本数 selector:那个pod是由自己管理的 serviceName:必须关联到一个无头服务商 template:定义pod模板(其中定义关联那个存储卷) volumeClaimTemplates :生成PVC 在创建StatefulSet之前需要准备的东西,值得注意的是创建顺序非常关键,创建顺序如下: 1、Volume (多种类型,比如nfs、glusterfs、ceph )。 2、Persistent Volume 量的 3、Persistent Volume Claim(自动创建) 4、headless Service 5、StatefulSet 资源删除顺序 删除对应的pod、svc、statefulset、pv、pvc statefulset的启停顺序 有序部署:部署StatefulSet时,如果有多个Pod副本,它们会被顺序地创建(从0到N-1)并且,在下一个Pod运行之前所有之前的Pod必须都是Running和Ready状态。 有序删除:当Pod被删除时,它们被终止的顺序是从N-1到0。 有序扩展:当对Pod执行扩展操作时,与部署一样,它前面的Pod必须都处于Running和Ready状态。 实例:基于PVC+StatefulSet实现的MySQL主从架构 https://www.cnblogs.com/Yuanbangchen/p/17309336.html
1.安装nfs服务器,基于PV作为后端存储 [root@localhost7B ]# cat /etc/exports /data/k8sdata *(rw,no_root_squash) [root@localhost7B magedu]# mkdir /data/k8sdata/magedu/web-datadir-0 [root@localhost7B magedu]# mkdir /data/k8sdata/magedu/web-datadir-1 [root@localhost7B magedu]# mkdir /data/k8sdata/magedu/web-datadir-2 [root@localhost7B magedu]# mkdir /data/k8sdata/magedu/web-datadir-3 [root@localhost7B magedu]# mkdir /data/k8sdata/magedu/mysql-datadir-5 [root@localhost7B ]# systemctl restart nfs-server.service 2.创建PV,为什么创建多个,原因是replicas随时可能伸缩。 [root@localhost7C mysql]# cat pv/mysql-persistentvolume.yaml [root@localhost7C statfulset]# cat web-pv.yaml apiVersion: v1 kind: PersistentVolume metadata: name: web-pv0 labels: type: web-pv0 spec: capacity: storage: 1Gi accessModes: - ReadWriteOnce persistentVolumeReclaimPolicy: Retain nfs: path: /data/k8sdata/magedu/web-datadir-0 server: 192.168.80.110 --- apiVersion: v1 kind: PersistentVolume metadata: name: web-pv1 labels: type: web-pv1 spec: capacity: storage: 1Gi accessModes: - ReadWriteOnce persistentVolumeReclaimPolicy: Retain nfs: path: /data/k8sdata/magedu/web-datadir-1 server: 192.168.80.110 --- apiVersion: v1 kind: PersistentVolume metadata: name: web-pv2 labels: type: web-pv2 spec: capacity: storage: 1Gi accessModes: - ReadWriteOnce persistentVolumeReclaimPolicy: Retain nfs: path: /data/k8sdata/magedu/web-datadir-2 server: 192.168.80.110 --- apiVersion: v1 kind: PersistentVolume metadata: name: web-pv3 labels: type: web-pv3 spec: capacity: storage: 1Gi accessModes: - ReadWriteOnce persistentVolumeReclaimPolicy: Retain nfs: path: /data/k8sdata/magedu/web-datadir-3 server: 192.168.80.110 创建另一个PV,测试使用 [root@localhost7C statfulset]# cat test.yaml --- apiVersion: v1 kind: PersistentVolume metadata: name: mysql-datadir-5 spec: capacity: storage: 50Gi accessModes: - ReadWriteOnce nfs: path: /data/k8sdata/magedu/mysql-datadir-5 server: 192.168.80.110 3.对于StatefulSet,PVC不需要创建的,PVC模版会自动创建,此处是为方便理解。 当手工创建PV时指定了label的键值对,在PVC里通过selector可以指定PV的label,就达到调用效果。 当PVC使用模版时,是怎么生成PVC模版的,并如何调用PV?PV和PVC是怎么bound起来的呢?(应该是随机性找Availableu状态的PV ) [root@localhost7C statfulset]# cat web-pvc.yaml kind: PersistentVolumeClaim apiVersion: v1 metadata: name: www-web-0 spec: accessModes: - ReadWriteOnce resources: requests: storage: 1Gi storageClassName: my-storage-class selector: matchLabels: type: web-pv0 --- kind: PersistentVolumeClaim apiVersion: v1 metadata: name: www-web-1 spec: accessModes: - ReadWriteOnce resources: requests: storage: 1Gi storageClassName: my-storage-class selector: matchLabels: type: web-pv1 3.创建 headless service和StatefulSet [root@localhost7C statfulset]# cat web.yaml apiVersion: v1 kind: Service metadata: name: web-headless # labels: app: nginx spec: ports: - port: 80 name: web clusterIP: None selector: app: nginx --- apiVersion: v1 kind: Service metadata: name: web labels: app: nginx spec: ports: - port: 80 name: web selector: app: nginx --- apiVersion: apps/v1 kind: StatefulSet metadata: name: web #pod名 spec: selector: matchLabels: app: nginx serviceName: "web-headless" # headless servers replicas: 2 template: metadata: labels: app: nginx spec: terminationGracePeriodSeconds: 10 containers: - name: nginx image: nginx imagePullPolicy: IfNotPresent ports: - containerPort: 80 name: web volumeMounts: - name: www #调用PVCPVC模版名 mountPath: /usr/share/nginx/html volumeClaimTemplates: #PVC模版,与template平级 - metadata: name: www #PVC模版名 spec: accessModes: [ "ReadWriteOnce" ] resources: requests: storage: 1Gi [root@localhost7C statfulset]# kubectl apply -f web-pv.yaml -f test.yaml -f web.yaml PVC的名称是www-web-0看似有规律的名字, 首先StatefulSet的name叫web,设置的replicas为3个,volumeMounts和volumeClaimTemplates的name必须相同,为www, 所以StatefulSet创建的第一个Pod的name应该为web-0,第二个为web-1。这里StatefulSet中的Pod与PVC之间的绑定关系是通过名称来匹配的即: PVC_name = volumeClaimTemplates_name + "-" + pod_name www-web-0 = www + "-" + web-0 [root@localhost7C statfulset]# kubectl get pv,pvc,pod,svc -A -o wide NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE VOLUMEMODE persistentvolume/web-pv0 1Gi RWO Retain Bound default/www-web-2 84s Filesystem persistentvolume/web-pv1 1Gi RWO Retain Bound default/www-web-1 84s Filesystem persistentvolume/web-pv2 1Gi RWO Retain Available 84s Filesystem persistentvolume/web-pv3 1Gi RWO Retain Bound default/www-web-0 84s Filesystem persistentvolume/mysql-datadir-5 50Gi RWO Retain Available 84s Filesystem NAMESPACE NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE VOLUMEMODE default persistentvolumeclaim/www-web-0 Bound web-pv3 1Gi RWO 36s Filesystem default persistentvolumeclaim/www-web-1 Bound web-pv1 1Gi RWO 33s Filesystem default persistentvolumeclaim/www-web-2 Bound web-pv0 1Gi RWO 30s Filesystem NAMESPACE NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES default pod/web-0 1/1 Running 0 36s 10.20.4.65 192.168.80.170 <none> <none> default pod/web-1 1/1 Running 0 33s 10.20.5.60 192.168.80.160 <none> <none> default pod/web-2 1/1 Running 0 30s 10.20.4.66 192.168.80.170 <none> <none> NAMESPACE NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR default service/web ClusterIP 10.10.236.217 <none> 80/TCP 36s app=nginx default service/web-headless ClusterIP None <none> 80/TCP 36s app=nginx 测试:当PVC使用模版时,是怎么生成PVC模版的,并如何调用PV?PV和PVC是怎么bound起来的呢?(应该是随机性找Availableu状态的PV ) [root@localhost7C statfulset]# kubectl scale statefulset web --replicas=5 [root@localhost7C statfulset]# kubectl get pv,pvc -A -o wide NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE VOLUMEMODE persistentvolume/mysql-datadir-5 50Gi RWO Retain Bound default/www-web-4 17m Filesystem persistentvolume/web-pv0 1Gi RWO Retain Bound default/www-web-2 17m Filesystem persistentvolume/web-pv1 1Gi RWO Retain Bound default/www-web-1 17m Filesystem persistentvolume/web-pv2 1Gi RWO Retain Bound default/www-web-3 17m Filesystem persistentvolume/web-pv3 1Gi RWO Retain Bound default/www-web-0 17m Filesystem NAMESPACE NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE VOLUMEMODE default persistentvolumeclaim/www-web-0 Bound web-pv3 1Gi RWO 16m Filesystem default persistentvolumeclaim/www-web-1 Bound web-pv1 1Gi RWO 16m Filesystem default persistentvolumeclaim/www-web-2 Bound web-pv0 1Gi RWO 16m Filesystem default persistentvolumeclaim/www-web-3 Bound web-pv2 1Gi RWO 4m38s Filesystem default persistentvolumeclaim/www-web-4 Bound mysql-datadir-5 50Gi RWO 4m35s Filesystem #测试短和长域名 FQDN:$(podname).(headless server name) FQDN:$(podname).(headless server name).namespace.svc.zzhz.local [root@localhost7C statfulset]# kubectl exec -it web-0 bash root@web-0:/# apt update root@web-0:/# apt-get update root@web-0:/# apt install iputils-ping root@web-0:/# hostname web-0 root@web-0:/# ping web-2.web-headless.default.svc.zzhz.local PING web-2.web-headless.default.svc.zzhz.local (10.20.4.66) 56(84) bytes of data. 64 bytes from web-2.web-headless.default.svc.zzhz.local (10.20.4.66): icmp_seq=1 ttl=64 time=0.122 ms 64 bytes from web-2.web-headless.default.svc.zzhz.local (10.20.4.66): icmp_seq=2 ttl=64 time=0.055 ms root@web-0:/# ping web-1.web-headless PING web-1.web-headless.default.svc.zzhz.local (10.20.5.60) 56(84) bytes of data. 64 bytes from web-1.web-headless.default.svc.zzhz.local (10.20.5.60): icmp_seq=1 ttl=62 time=0.413 ms 64 bytes from web-1.web-headless.default.svc.zzhz.local (10.20.5.60): icmp_seq=2 ttl=62 time=0.591 ms