Kubernetes StatefulSet介绍

原创
半兽人 发表于: 2018-11-20   最后更新时间: 2022-10-29 00:50:24  
{{totalSubscript}} 订阅, 10,222 游览

在Kubernetes系统中,Pod的管理对象RC、Deployment、DaemonSet和Job都是面向无状态的服务。但现实中有很多服务是有状态的,特别是一些复杂的中间件集群,例如MySQL集群、MongoDB集群、Kafka集群、Zookeeper集群等。

这些应用集群有以下一些共同点:

  1. 每个节点都有固定的身份ID,通过这个ID,集群中的成员可以相互发现并且通信。
  2. 集群的规模是比较固定的,集群规模不能随意变动。
  3. 集群里的每个节点都是有状态的,通常会持久化数据到永久存储中。
  4. 如果磁盘损坏,则集群里的某个节点无法正常运行,集群功能受损。

如果用 RC/Deployment 控制 Pod 副本数的方式来实现上述有状态的集群,则我们会发现第一点是无法满足的,因为Pod的名字是随机产生的,Pod的IP地址也是在运行期才确定且可能有变动的,我们事先无法为每个Pod确定唯一不变的ID,为了能够在其他节点上恢复某个失败的节点,这种集群中的Pod需要挂接某种共享存储,为了解决这个问题,Kubernetes从v1.4版本开始引入了PetSet这个新的资源对象,并且在v1.5版本时更名为StatefulSet,StatefulSet从本质上来说,可以看作 Deployment/RC 的一个特殊变种,它有如下一些特性。

  • StatefulSet里的每个Pod都有稳定、唯一的网络标识,可以用来发现集群内的其他成员。假设StatefulSet的名字叫kafka,那么第一个Pod叫kafak-0,第二个Pod叫kafak-1,第三个叫kafka-2,以此类推。

  • StatefulSet控制的Pod副本的启停顺序是受控的,操作第n个Pod时,前n-1个Pod已经时运行且准备好的状态。

  • StatefulSet里的Pod采用稳定的持久化存储卷,通过 PV/PVC 来实现,删除Pod时默认不会删除与StatefulSet相关的存储卷(为了保证数据的安全)。

StatefulSet除了要与PV卷捆绑使用以存储Pod的状态数据,还要与Headless Service(无头服务)配合使用,即在每个StatefulSet的定义中要声明它属于哪个Headless Service。Headless Service与普通Service的关键区别在于,它没有Cluster IP,如果解析Headless Service的DNS域名,则返回的是该Service对应的全部Pod的Endpoint列表。StatefulSet在Headless Service的基础上又为StatefulSet控制的每个Pod实例创建了一个DNS域名,这个域名的格式为:

$(podname).$(headless service name)

比如一个3节点的 StatefulSet 集群,对应的 Headless Service 的名字为nginx,StatefulSet的名字为web,则 StatefulSet 里面的 3 个 Pod 的 DNS 名称分别为web-0.nginxweb-1.nginxweb-2.nginx,这些DNS名称可以直接在集群的配置文件中固定下来。

示例

kind: Service
metadata:
  name: nginx
  labels:
    app: nginx
spec:
  ports:
  - port: 80
    name: web
  clusterIP: None
  selector:
    app: nginx
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: web
spec:
  selector:
    matchLabels:
      app: nginx # 必须匹配 .spec.template.metadata.labels
  serviceName: "nginx"
  replicas: 3 # 默认值是 1
  minReadySeconds: 10 # 默认值是 0
  template:
    metadata:
      labels:
        app: nginx # 必须匹配 .spec.selector.matchLabels
    spec:
      terminationGracePeriodSeconds: 10
      containers:
      - name: nginx
        image: registry.k8s.io/nginx-slim:0.8
        ports:
        - containerPort: 80
          name: web
        volumeMounts:
        - name: www
          mountPath: /usr/share/nginx/html
  volumeClaimTemplates:
  - metadata:
      name: www
    spec:
      accessModes: [ "ReadWriteOnce" ]
      storageClassName: "my-storage-class"
      resources:
        requests:
          storage: 1Gi

上述例子中:

  • 名为 nginx 的 Headless Service 用来控制网络域名。
  • volumeClaimTemplates 提供存储。

部署和扩缩保证

  • 对于包含 N 个 副本的 StatefulSet,当部署 Pod 时,它们是依次创建的,顺序为 0..N-1。

  • 当删除 Pod 时,它们是逆序终止的,顺序为 N-1..0。

  • 在将扩缩操作应用到 Pod 之前,它前面的所有 Pod 必须是 Running 和 Ready 状态。

  • 在一个 Pod 终止之前,所有的继任者必须完全关闭。

StatefulSet 不应将 pod.Spec.TerminationGracePeriodSeconds 设置为 0。 这种做法是不安全的。

在上面的 nginx 示例被创建后,会按照 web-0、web-1、web-2 的顺序部署三个 Pod。 在 web-0 进入 RunningReady 状态前不会部署 web-1。在 web-1 进入 Running 和 Ready 状态前不会部署 web-2。 如果 web-1 已经处于 Running 和 Ready 状态,而 web-2 尚未部署,在此期间发生了 web-0 运行失败,那么 web-2 将不会被部署,要等到 web-0 部署完成并进入 Running 和 Ready 状态后,才会部署 web-2。

如果用户想将示例中的 StatefulSet 扩缩为 replicas=1,首先被终止的是 web-2。 在 web-2 没有被完全停止和删除前,web-1 不会被终止。 当 web-2 已被终止和删除、web-1 尚未被终止,如果在此期间发生 web-0 运行失败, 那么就不会终止 web-1,必须等到 web-0 进入 Running 和 Ready 状态后才会终止 web-1。

Pod 管理策略

StatefulSet 允许你放宽其排序保证,通过 .spec.podManagementPolicy 来设置。

  • 顺序 Pod 管理
    podManagementPolicy: "OrderedReady"是默认设置。它保证了Pod顺序。

  • 并行 Pod 管理
    podManagementPolicy: "Parallel"让 StatefulSet 控制器并行的启动或终止所有的 Pod,启动或者终止其他 Pod 前,无需等待 Pod 进入 Running 和 ready 或者完全停止状态。 这个选项只会影响扩缩操作的行为,更新不会被影响。

更新策略

StatefulSet 的 .spec.updateStrategy 字段让你可以配置和禁用掉自动滚动更新 Pod 的容器、标签、资源请求或限制、以及注解。有两个允许的值:

  • OnDelete
    当 StatefulSet 的 .spec.updateStrategy.type 设置为 OnDelete 时, 它的控制器将不会自动更新 StatefulSet 中的 Pod。 用户必须手动删除 Pod 以便让控制器创建新的 Pod。

  • RollingUpdate
    RollingUpdate 更新策略对 StatefulSet 中的 Pod 执行自动的滚动更新。这是默认的更新策略。

最大不可用 Pod

特性状态: Kubernetes v1.24
你可以通过指定 .spec.updateStrategy.rollingUpdate.maxUnavailable 字段来控制更新期间不可用的 Pod 的最大数量。 该值可以是绝对值(例如,“5”)或者是期望 Pod 个数的百分比(例如,10%)。 绝对值是根据百分比值四舍五入计算的。 该字段不能为 0。默认设置为 1。

该字段适用于 0 到 replicas - 1 范围内的所有 Pod。 如果在 0 到 replicas - 1 范围内存在不可用 Pod,这类 Pod 将被计入 maxUnavailable 值。

更多

Kubernetes之StatefulSet

更新于 2022-10-29

и 2年前

可以更详细一点吗

半兽人 -> и 2年前

好的,我尽快补充,我以为人看的少 :(

и -> 半兽人 2年前

感谢感谢

大天才/xyx 2年前

如果能够像deployment介绍一样配个yml就更好了

好的,我今天补全一下这篇文章。

小孙 3年前

看完了docker再看,思路清晰很多了,这个系列文章看了三四遍才理解了

半兽人 -> 小孙 3年前

书读百遍其义自见。

小孙 3年前

有点看不懂了,只是大概明天他是区别于RC这些无状态服务的,有状态服务的pod的

半兽人 -> 小孙 3年前

你的回复有错别字,我也没太理解额。
你可以参考一下:kubernetes有状态和无状态怎么理解?

查看kubernetes更多相关的文章或提一个关于kubernetes的问题,也可以与我们一起分享文章