K8S介绍系列---Statefulset介绍

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了K8S介绍系列---Statefulset介绍相关的知识,希望对你有一定的参考价值。

参考技术A 在k8s中,replicaset和deployment是处理无状态的服务,但对于有状态的应用,就需要statefulset来处理

stateful不仅能管理pod对象,还能确保这些pod的顺序性和一致性

会创建volumeClaimTemplates配置,包括持久卷persistentVolume和用于绑定持久卷和pod的persistVolumeClaim资源,pod中保存了序号,哪怕重新调度或重启也不会变

由StatefulSetController,StatefulSetControl ,StatefulPodControl 三个组件协作完成,StatefulSetController 从podInformer和ReplicasetInformer中接受增改时间将事件推入队列,StatefulSetController 在run方法中启动多个协程,从队列中获取带出里的StatefulSet 资源进行同步

使用单调递增策略,升序一次创建副本降序删除副本,当出现pod不健康,新的pod不会被创建,StatefulSetController 会等待 Pod 恢复后继续执行下面的逻辑

通过stateful应该持有的副本数对当前副本进行分组,一部分是需要保证存活的replicas,另一部分需要被终止的副本condmened,分组后的replicas数量不足,通过newVersionedStatefulSetPod 函数创建新的 Pod,不过这里的 Pod 也只是待创建的模板。
拿到线上应该存在的 replicas 数组时,我们就可以进行通过 CreateStatefulPod 进行扩容了,每个 Pod 的更新和创建都会等待前面所有 Pod 正常运行,它会调用 isFailed、isCreated、isTerminating 等方法保证每一个 Pod 都正常运行时才会继续处理下一个 Pod,如果使用滚动更新策略,那么会在完成扩容之后才会对当前的 Pod 进行更新:
拿到线上应该存在的 replicas 数组时,我们就可以进行通过 CreateStatefulPod 进行扩容了,每个 Pod 的更新和创建都会等待前面所有 Pod 正常运行,它会调用 isFailed、isCreated、isTerminating 等方法保证每一个 Pod 都正常运行时才会继续处理下一个 Pod,如果使用滚动更新策略,那么会在完成扩容之后才会对当前的 Pod 进行更新:

当 StatefulSetController 处理完副本的创建和更新任务之后,就开始删除需要抛弃的节点了,节点的删除也需要确定按照降序依次进行:

我们首先会删除待抛弃列表中的副本,其次根据滚动更新 RollingUpdate 的配置从高到低依次删除所有 Pod 版本已经过时的节点,所有删除节点的方式都会通过 DeleteStatefulPod 方法进行,该方法会通过客户端的接口直接根据 Pod 名称删除对应的资源。

先会删除待抛弃列表中的副本,其次根据滚动更新 RollingUpdate 的配置从高到低依次删除所有 Pod 版本已经过时的节点,所有删除节点的方式都会通过 DeleteStatefulPod 方法进行,该方法会通过客户端的接口直接根据 Pod 名称删除对应的资源。

Pod 的序列号(Ordinal)是其唯一性和顺序性的保证,在创建和删除 StatefulSet 的副本时,我们都需要按照 Pod 的序列号对它们按照顺序操作,副本的创建会按照序列号升序处理,副本的更新和删除会按照序列号降序处理。
创建 StatefulSet 中的副本时,就会在 newStatefulSetPod 函数中传入当前 Pod 的 ordinal 信息,该方法会调用 GetPodFromTemplate 获取 StatefulSet 中的 Pod 模板并且初始化 Pod 的 metadata 和引用等配置:

getPodName 函数的实现非常简单,它将 StatefulSet 的名字和传入的序列号通过破折号连接起来组成我们经常见到的 web-0、web-1 等形式的副本名;initIdentity 会更新 Pod 的主机名、资源名、命名空间标签,而 updateStorage 会为待创建的副本设置卷:

设置卷的配置主要来自于 StatefulSet 规格中的 volumeClaimTemplates 模板,所有卷相关的配置信息都会通过该方法传递过来。

Pod 通过当前名字存储自己对应的序列号,在 StatefulSetController 同步时就会从 Pod 的名字中取出序列号并进行排序,随后的各种循环就可以选择使用正序或者倒序的方式依次处理各个节点了。

当我们删除一个 Kubernetes 中的 StatefulSet 资源时,它对应的全部 Pod 副本都会被 垃圾收集器 自动删除,该收集器在检查到当前 Pod 的 metadata.ownerReferences 已经不再存在时就会删除 Pod 资源
我们会发现除了 StatefulSet 和 Pod 之外的任何其他资源都没有被删除,之前创建的 PersistentVolume 和 PersistentVolumeClaim 对象都没有发生任何的变化,这也是 StatefulSet 的行为,它会在服务被删除之后仍然保留其中的状态,也就是数据,这些数据就都存储在 PersistentVolume 中。

如果我们重新创建相同的 StatefulSet,它还会使用之前的 PV 和 PVC 对象,不过也可以选择手动删除所有的 PV 和 PVC 来生成新的存储,这两个对象都属于 Kubernetes 的存储系统,感兴趣的读者可以通过 存储系统 了解 Kubernetes 中 Volume 的设计和实现。

Kubernetes基础_05_StatefulSet全解析(有状态的Pod)

系列文章目录

文章目录


前言

Nginx 是平等的,无状态的,如下:

因为nginx是不存储数据的,只是做路由转发,做负载均衡,即使是运行服务端的tomcat也是无状态的。

一、StatefulSet的引入

官网https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/

StatefulSet is the workload API object used to manage stateful applications.
Manages the deployment and scaling of a set of Pods, and provides guarantees about the ordering and uniqueness of these Pods.

  • Stable, unique network identifiers.
  • Stable, persistent storage.
  • Ordered, graceful deployment and scaling.
  • Ordered, automated rolling updates.

其他接触的Pod的管理对象比如RS、Deployment、DaemonSet和Job都是面向无状态的服务,但是现实中有很多服务是有状态的,比如MySQL集群、MongoDB集群、ZK集群等,都是存储数据的,它们都有以下共同的特点:

  • 每个节点都有固定的ID,通过该ID,集群中的成员可以互相发现并且通信(不平等,每个id不同)
  • 集群的规模是比较固定的,集群规模不能随意变动
  • 集群里的每个节点都是有状态的,通常会持久化数据到永久存储中(持久化存储)
  • 如果磁盘损坏,则集群里的某个节点无法正常运行,集群功能受损

而之前的RC/Deployment没办法满足要求,所以从Kubernetes v1.4版本就引入了PetSet资源对象,在v1.5版本时更名为StatefulSet。从本质上说,StatefulSet可以看作是Deployment/RC对象的特殊变种

  • StatefulSet里的每个Pod都有稳定、唯一的网络标识,可以用来发现集群内其他的成员(不平等,每个id不同)
  • Pod的启动顺序是受控的,操作第n个Pod时,前n-1个Pod已经是运行且准备好的状态
  • StatefulSet里的Pod采用稳定的持久化存储卷,通过PV/PVC来实现,删除Pod时默认不会删除与StatefulSet相关的存储卷
  • StatefulSet需要与Headless Service配合使用

日志监控每个pv pvc 会报错,找不到bound pv

pv pvc 是持久化存储 statefulSet是有状态,其完成持久化存储必须借助pv pvc

deployment 无法满足,因为deployment里面的pod都是没有状态的

集群内唯一标识id + pod启动顺序受控制 + 持久化存储

二、StatefulSet实践

vi nginx-st.yaml
kubectl apply nginx-st.yaml
watch kubectl get pods    # 观察pod的创建顺序,以及pod的名字(重要)
# 定义Service    service暴露出去statefulSet,和之前暴露deployment一样
apiVersion: v1
kind: Service
metadata:
  name: nginx
  labels:
    app: nginx
spec:
  ports:
  - port: 80
    name: web
  clusterIP: None
  selector:
    app: nginx
---
# 定义StatefulSet
apiVersion: apps/v1
kind: StatefulSet  
metadata:
  name: web #  这里定义StatefulSet的名称,启动起来之后带了序号(状态性,每个不平等),而且顺序就是序号(有序性)
spec:
  selector:
    matchLabels:
      app: nginx 
  serviceName: "nginx"  
  replicas: 3 
  template:
    metadata:
      labels:
        app: nginx 
    spec:
      terminationGracePeriodSeconds: 10
      containers:
      - name: nginx
        image: nginx
        ports:
        - containerPort: 80
          name: web

总结

以上是关于K8S介绍系列---Statefulset介绍的主要内容,如果未能解决你的问题,请参考以下文章

K8S系列深入解析滚动升级

K8S系列深入解析有状态服务

mysql on k8s statefulset部署实践

k8s的StatefulSet(有状态服务)实现

第一篇:《Kubernetes 入门介绍》

第一篇:《Kubernetes 入门介绍》