StatefulSet

StatefulSet

RC、RS、Deployment、DS(DaemonSet)这些Pod控制器都是面向无状态的服务,它们所管理的Pod的IP、名字、启停顺序等都是随机的

这些Pod控制器都有一个相同点

template(模板):根据模板创建出来的Pod,它们的状态都是一摸一样的(除了名称、IP、域名之外)

可以理解为:任何一个Pod都可以被删除,然后用新生成的Pod进行替换

StatefulSet:

顾名思义:有状态的集合,管理所有有状态的服务,比如MySQL、MongoDB集群等

它之前的名字是:PetSet

Pet:宠物

把之前按无状态的服务比喻为牛、羊等牲畜。把有状态的服务比喻为:宠物

StatefulSet本质上是Deployment的一种变体,在v1.9版本中已成为GA版本,它为了解决有状态服务的问题,它所管理的Pod拥有固定的Pod名称,启停顺序,在StatefulSet中,Pod名字称为网络标识(hostname),还必须要用到共享存储

有状态的服务:后端生成的每一个Pod都具有自己的唯一性,不可随意被删除

需要记录前一次或者多次通信中的相关事件,以作为下一次通信的分类标准。比如:mysql等数据库服务。(Pod的名称不能随意变化,数据持久化的目录也是不一样的,每一个Pod都有自己独有的数据持久化存储目录)

一个小实例:

[root@master ~]# vim  statefulset.yaml
apiVersion: v1
kind: Service
metadata:
  name: headless-svc
  labels:
    app: headless-svc
spec:
  ports:
  - port: 80
  selector:
    app: headless-pod
  clusterIP: None
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: statefulset-test
spec:
  serviceName: headless-svc
  replicas: 3
  selector:
    matchLabels:
      app: headless-pod
  template:
    metadata:
      labels:
        app: headless-pod
    spec:
      containers:
      - name: myhttpd
        image: httpd
        ports:
        - containerPort: 80
[root@master ~]# kubectl  apply  -f  statefulset.yaml 
service/headless-svc created
statefulset.apps/statefulset-test created
[root@master ~]# kubectl  get svc
NAME           TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
headless-svc   ClusterIP   None         <none>        80/TCP    4m

Deployment控制的pod的名称由来:

​ Deployment+RS+随机字符串(Pod的名称),没有顺序的额,可以被随意替代

StategulSet的三个组成部分:

1、headless-svc:无头服务。因为没有IP地址,所以它不具备负载均衡的功能了

作用:为后端的每一个Pod去命名

因为statefulset要求Pod的名称是有顺序的,每一个Pod都不能被随意取代,也就是说即使Pod重建之后,名称依然不变

[root@master ~]# kubectl  get pod
NAME                 READY   STATUS    RESTARTS   AGE
statefulset-test-0   1/1     Running   0          23m
statefulset-test-1   1/1     Running   0          22m
statefulset-test-2   1/1     Running   0          22m
[root@master ~]# kubectl  delete  pod  statefulset-test-0
[root@master ~]# kubectl  get pod
NAME                 READY   STATUS              RESTARTS   AGE
statefulset-test-0   0/1     ContainerCreating   0          6s
statefulset-test-1   1/1     Running             0          25m
statefulset-test-2   1/1     Running             0          25m
//Pod重建之后名称没有发生变化

2、statefulset:定义具体的应用

3、volumeClaimTeplates:自动创建PVC,为后端的Pod提供专有的存储

存储卷申请模板,创建PVC,指定pvc名称大小,将自动创建pvc,且pvc必须由存储类供应

为什么需要 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的原因

每一个pod—>对应一个pvc---->每一个pvc对应一个pv

​ storageclass:自动创建PV

​ 需要解决:自动创建PVC----->volumeClaimTeplates

一、创建StorageClass资源对象

​ 1、基于NFS服务,创建NFS服务

[root@master ~]# showmount  -e
Export list for master:
/nfsdata *

​ 2、创建rbac权限

[root@master ~]# vim rbac-rolebind.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  name: nfs-provisioner
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: nfs-provisioner-runner
rules:
   -  apiGroups: [""]
      resources: ["persistentvolumes"]
      verbs: ["get", "list", "watch", "create", "delete"]
   -  apiGroups: [""]
      resources: ["persistentvolumeclaims"]
      verbs: ["get", "list", "watch", "update"]
   -  apiGroups: ["storage.k8s.io"]
      resources: ["storageclasses"]
      verbs: ["get", "list", "watch"]
   -  apiGroups: [""]
      resources: ["events"]
      verbs: ["watch", "create", "update", "patch"]
   -  apiGroups: [""]
      resources: ["services", "endpoints"]
      verbs: ["get","create","list", "watch","update"]
   -  apiGroups: ["extensions"]
      resources: ["podsecuritypolicies"]
      resourceNames: ["nfs-provisioner"]
      verbs: ["use"]
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: run-nfs-provisioner
subjects:
  - kind: ServiceAccount
    name: nfs-provisioner
    namespace:  default   //这个字段必须要写,不然会报错
roleRef:
  kind: ClusterRole
  name: nfs-provisioner-runner
  apiGroup: rbac.authorization.k8s.io
[root@master ~]# kubectl apply -f  rbac-rolebind.yaml 
serviceaccount/nfs-provisioner unchanged
clusterrole.rbac.authorization.k8s.io/nfs-provisioner-runner unchanged
clusterrolebinding.rbac.authorization.k8s.io/run-nfs-provisioner created

​ 3、创建Deployment资源对象,用Pod代替真正的NFS服务

[root@master ~]# vim nfs-deployment.yaml
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: nfs-client-provisioner
spec:
  replicas: 1
  strategy:
    type: Recreate
  template:
    metadata:
      labels:
        app: nfs-client-provisioner
    spec:
      serviceAccount: nfs-provisioner
      containers:
        - name: nfs-client-provisioner
          image: registry.cn-hangzhou.aliyuncs.com/open-ali/nfs-client-provisioner
          volumeMounts:
            - name: nfs-client-root
              mountPath:  /persistentvolumes
          env:
            - name: PROVISIONER_NAME
              value: bdqn
            - name: NFS_SERVER
              value: 192.168.1.70
            - name: NFS_PATH
              value: /nfsdata
      volumes:
        - name: nfs-client-root
          nfs:
            server: 192.168.1.70
            path: /nfsdata
[root@master ~]# kubectl  apply  -f nfs-deployment.yaml 
deployment.extensions/nfs-client-provisioner created
[root@master ~]# kubectl  get pod
NAME                                     READY   STATUS    RESTARTS   AGE
nfs-client-provisioner-f6cb6688b-5zn8d   1/1     Running   0          7s

​ 4、创建storaclass

[root@master ~]# vim test-storageclass.yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: sc-nfs
provisioner: bdqn
reclaimPolicy: Retain
[root@master ~]# kubectl  apply  -f  test-storageclass.yaml 
storageclass.storage.k8s.io/sc-nfs created
[root@master ~]# kubectl  get sc
NAME     PROVISIONER   AGE
sc-nfs   bdqn          10s

二、解决自动创建PVC

[root@master ~]# vim  statefulset.yaml
apiVersion: v1
kind: Service
metadata:
  name: headless-svc
  labels:
    app: headless-svc
spec:
  ports:
  - port: 80
    name: myweb
  selector:
    app: headless-pod
  clusterIP: None
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: statefulset-test
spec:
  serviceName: headless-svc
  replicas: 3
  selector:
    matchLabels:
      app: headless-pod
  template:
    metadata:
      labels:
        app: headless-pod
    spec:
      containers:
      - image: httpd
        name: myhttpd
        ports:
        - containerPort: 80
          name: httpd
        volumeMounts:
        - mountPath: /mnt
          name: test
  volumeClaimTemplates:  //自动的创建PVC
  - metadata:
      name: test
      annotations:   //这是指定storageclass
        volume.beta.kubernetes.io/storage-class: sc-nfs
    spec:
      accessModes:
        - ReadWriteOnce
      resources:
        requests:
          storage: 100Mi
[root@master ~]# kubectl  apply  -f  statefulset.yaml 
service/headless-svc created
statefulset.apps/statefulset-test created
[root@master ~]# kubectl  get pod
NAME                                     READY   STATUS    RESTARTS   AGE
nfs-client-provisioner-f6cb6688b-5zn8d   1/1     Running   0          13m
statefulset-test-0                       1/1     Running   0          23s
statefulset-test-1                       1/1     Running   0          16s
statefulset-test-2                       1/1     Running   0          9s

注意:

​ 如果生成的Pod,第一个出现了问题,后面的都不会生成

根据volumeClaimTemplates自动创建的PVC:

[root@master ~]# kubectl  get pvc
NAME                      STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   AGE
test-statefulset-test-0   Bound    pvc-3a105a9d-5892-4080-a993-20fd2540cd3e   100Mi      RWO            sc-nfs         46m
test-statefulset-test-1   Bound    pvc-123bf53d-a72b-4bfa-a901-bb98efcda056   100Mi      RWO            sc-nfs         45m
test-statefulset-test-2   Bound    pvc-8529c668-5b38-4024-93af-b18fa238b0ba   100Mi      RWO            sc-nfs         45m

如果集群中没有StorageClass的动态供应PVC的机制,也可以提前手动创建多个PV、PVC,手动创建的PVC名称必须符合之后创建的StatefulSet命名规则:(volumeClaimTemplates.name)-(pod_name)

Statefulset名称为statefulset-test

三个Pod副本: statefulset-test-0,statefulset-test-1,statefulset-test-2

volumeClaimTemplates名称为:test

那么自动创建出来的PVC名称为test-statefulset-test-[0-2],为每个Pod创建一个PVC

规律总结:

  • 匹配Pod name(网络标识)的模式为: ( s t a t e f u l s e t 名 称 ) − (statefulset名称)- (statefulset)(序号),比如上面的示例:statefulset-test-0,statefulset-test-1,statefulset-test-2。
  • StatefulSet为每个Pod副本创建了一个DNS域名,这个域名的格式为: $(podname).(headless server name),也就意味着服务间是通过Pod域名来通信而非Pod IP,因为当Pod所在Node发生故障时,Pod会被飘移到其它Node上,Pod IP会发生变化,但是Pod域名不会有变化。
  • StatefulSet使用Headless服务来控制Pod的域名,这个域名的FQDN为: ( s e r v i c e n a m e ) . (service name). (servicename).(namespace).svc.cluster.local,其中,“cluster.local”指的是集群的域名。
  • 根据volumeClaimTemplates,为每个Pod创建一个pvc,pvc的命名规则匹配模式:(volumeClaimTemplates.name)-(pod_name),比如上面的volumeMounts.name=test, Pod name=statefulset-test-[0-2],因此创建出来的PVC是test-statefulset-test-0,test-statefulset-test-1,test-statefulset-test-2
  • 删除Pod不会删除其pvc,手动删除pvc将自动释放pv。
    关于Cluster Domain、headless service名称、StatefulSet 名称如何影响StatefulSet的Pod的

StatefulSet的启停顺序:

  • 有序部署:部署StatefulSet时,如果有多个Pod副本,它们会被顺序地创建(从0到N-1)并且,在下一个Pod运行之前所有之前的Pod必须都是Running和Ready状态。
  • 有序删除:当Pod被删除时,它们被终止的顺序是从N-1到0。
  • 有序扩展:当对Pod执行扩展操作时,与部署一样,它前面的Pod必须都处于Running和Ready状态

StatefulSet Pod管理策略

在v1.7以后,通过允许修改Pod排序策略,同时通过.spec.podManagementPolicy字段确保其身份的唯一性。

  • OrderedReady:上述的启停顺序,默认设置。
  • Parallel:告诉StatefulSet控制器并行启动或终止所有Pod,并且在启动或终止另一个Pod之前不等待前一个Pod变为Running and Ready或完全终止

StatefulSet使用场景

  • 稳定的持久化存储,即Pod重新调度后还是能访问到相同的持久化数据,基于PVC来实现
  • 稳定的网络标志,即Pod重新调度后其PodName和HostName不变,基于Headless Service(即没有Cluster IP的Service)来实现
  • 有序部署,有序扩展,即Pod是有顺序的,在部署或者扩展的时候要依据定义的顺序依次依次进行(即从0到N-1,在下一个Pod运行之前所有之前的Pod必须都是Running和Ready状态),基于init containers来实现
  • 有序收缩,有序删除(即从N-1到0)

更新策略:

在Kubernetes 1.7及更高版本中,通过.spec.updateStrategy字段允许配置或禁用Pod、labels、source request/limits、annotations自动滚动更新功能。

**OnDelete:**通过.spec.updateStrategy.type 字段设置为OnDelete,StatefulSet控制器不会自动更新StatefulSet中的Pod。用户必须手动删除Pod,以使控制器创建新的Pod。

**RollingUpdate:**通过.spec.updateStrategy.type 字段设置为RollingUpdate,实现了Pod的自动滚动更新,如果.spec.updateStrategy未指定,则此为默认策略。
StatefulSet控制器将删除并重新创建StatefulSet中的每个Pod。它将以Pod终止(从最大序数到最小序数)的顺序进行,一次更新每个Pod。在更新下一个Pod之前,必须等待这个Pod Running and Ready。

**Partitions:**通过指定 .spec.updateStrategy.rollingUpdate.partition 来对 RollingUpdate 更新策略进行分区,如果指定了分区,则当 StatefulSet 的 .spec.template 更新时,具有大于或等于分区序数的所有 Pod 将被更新。

具有小于分区的序数的所有 Pod 将不会被更新,即使删除它们也将被重新创建。如果 StatefulSet 的 .spec.updateStrategy.rollingUpdate.partition 大于其 .spec.replicas,则其 .spec.template 的更新将不会传播到 Pod。在大多数情况下,不需要使用分区

StatefulSet注意事项:

  1. 还在beta状态,需要kubernetes v1.5版本以上才支持
  2. 所有Pod的Volume必须使用PersistentVolume或者是管理员事先创建好
  3. 为了保证数据安全,删除StatefulSet时不会删除Volume
  4. StatefulSet需要一个Headless Service来定义DNS domain,需要在StatefulSet之前创建好
  5. 目前StatefulSet还没有feature complete,比如更新操作还需要手动patch

更多可以参考:https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/

进入容器,验证持久化是否成功

[root@master ~]# kubectl  get pod
NAME                                     READY   STATUS    RESTARTS   AGE
nfs-client-provisioner-f6cb6688b-5zn8d   1/1     Running   0          30m
statefulset-test-0                       1/1     Running   0          17m
statefulset-test-1                       1/1     Running   0          16m
statefulset-test-2                       1/1     Running   0          16m
[root@master ~]# kubectl exec  -it  statefulset-test-0  /bin/sh
# cd  /mnt
# touch  testfile
# exit
[root@master ~]# ls  /nfsdata/default-test-statefulset-test-0-pvc-3a105a9d-5892-4080-a993-20fd2540cd3e/
testfile

小结

Deployment、RC、RS、DS:

这些Pod控制器都是面向无状态的服务,他们管理的Pod的IP、名字、启停顺序等都是随机的

这些根据模板创建出来的Pod,特们的状态都是一摸一样的(除了名称、IP、域名之外)

任何一个Pod都可以被删除,然后用因生成的Pod进项替换

StatefulSet:

顾名思义:有状态的集合,管理所有的有状态服务,比如MySQL集群等

后端生成的每一个Pod都具有自己的唯一性,不可被随意删除

需要记录前一次或者多次通信中的相关事件,以作为下一次通信的分类标准

Pod的名称不能随意变化,数据持久化的目录也是不一样的,每一个Pod又都自己独有的数据持久化存储目录

扩容、缩容:在此过程中,Pod的生成或删除操作也是有顺序性的

[root@master ~]# kubectl  get pod  -n zhb
NAME                                     READY   STATUS    RESTARTS   AGE
nfs-client-provisioner-f6cb6688b-x2zls   1/1     Running   1          42h
statefulset-test-0                       1/1     Running   1          42h
statefulset-test-1                       1/1     Running   1          42h
statefulset-test-2                       1/1     Running   1          42h
statefulset-test-3                       1/1     Running   0          76s
statefulset-test-4                       1/1     Running   0          66s

升级操作:

[root@master ~]# kubectl explain sts.spec.updateStrategy.rollingUpdate.partition

partition:如果partition后面的值等于N,N+的都会更新,默认值为0(所有都会更新)

如果N等于2,那么它会从statefulset-test-2开始更新,以此类推

statefulset-test-0
statefulset-test-1
statefulset-test-2
statefulset-test-3
statefulset-test-4

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值