Kubernetes 有状态服务 Statefulset 介绍

2020-11-20 0 By admin

在 Kubernetes 容器编排工具中 Deployment 和 DaemonSet 资源对象都是面向无状态服务的,它们所创建的 Pod 对象的名称都追加随机字符命名。
如果想要部署有状态服务则需要使用 StatefulSet 资源对象,它创建的 Pod 对象的名称有特定规律,由${deployment}-{0…n}格式组成。

一、补充说明

1.1、有状态服务

一般我们接触到的中间件集群就是有状态的服务。分布式的中间件集群由多个应用节点组成一个统一的对外提供服务的应用;各节点因角色不同、高可用需要等原因,彼此之间维护各自的状态和数据等信息。例如:Mysql 主从架构部署过程中的ID值,ES集群中的不同的node.name等。

1.2、StatefulSet 资源对象

StatefulSet本质上是Deployment的一种变体,在v1.9版本中已成为GA版本,它为了解决有状态服务的问题,它所管理的Pod拥有固定的Pod名称,启停顺序。
在管理 Statefulset 资源对象过程中,我们需要注意其服务发现使用 headless Service对象,其磁盘存储应该做到Pod间彼此隔离。

1.3、服务发现方式

Statefulset 创建的Pod 对象,在Kubernetes 集群中的服务发现方式和 Deployment 的略有不同。
Deployment 创建的Pod,其PodName不会在DNS服务中注册解析记录。服务发现方式是通过相应的ServiceName生效的。访问ServiceName的请求会直接转发到Pod上。
StatefulSet 创建的Pod,其PodName 不会在DNS服务中注册解析记录。服务发现方式是通过响应的Headless ServiceName生效的。访问时需要$[podName].{Headless ServiceName} 才能将请求转发到对应的Pod上。

1.4、headless service

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

二、部署实例

2.1、部署 headless Service

apiVersion: v1
kind: Service
metadata:
  name: elasticsearch-master-headless
  labels:
    app: elasticsearch-master
spec:
  clusterIP: None
  publishNotReadyAddresses: true
  selector:
    app: elasticsearch-master
  ports:
  - name: http
    port: 9200
    protocol: TCP
    targetPort: 9200
  - name: transport
    port: 9300
    protocol: TCP
    targetPort: 9300
  type: ClusterIP

注:将 service.spec.publishNotReadyAddresses 设置为 true,允许 DNS 解析 headless 服务是发现未就绪的 Pod。

如果配置 Headless Service 时,没有设置publishNotReadyAddresses 为true;则Statefulset 的Pod 的状态如果未就绪;则不能使用${podName}.${Headless Service} 查询DNS解析记录。

2.2、部署 StatefulSet

apiVersion: apps/v1
kind: StatefulSet
metadata:
  generation: 1
  labels:
    app: elasticsearch-master
  name: elasticsearch-master
  namespace: paas-middleware
spec:
  podManagementPolicy: Parallel
  replicas: 3
  revisionHistoryLimit: 10
  selector:
    matchLabels:
      app: elasticsearch-master
  serviceName: elasticsearch-master-headless
  template:
    metadata:
      labels:
        app: elasticsearch-master
      name: elasticsearch-master
    spec:
      containers:
      - env:
        - name: node.name
          valueFrom:
            fieldRef:
              apiVersion: v1
              fieldPath: metadata.name
        - name: cluster.name
          value: elastic-middleware
        - name: discovery.zen.ping.unicast.hosts
          value: elasticsearch-master-0.elasticsearch-master-headless,*****
        - name: ES_JAVA_OPTS
          value: -Xmx1g -Xms1g
        - name: bootstrap.memory_lock
          value: "false"
        image: docker.elastic.co/elasticsearch/elasticsearch:5.1.1
        imagePullPolicy: IfNotPresent
        name: elasticsearch
******

注:podManagementPolicy字段默认为OrderadReady(串行的方式运行创建各pod副本);设置为Parallel可以并行的方式创建和删除pod资源。
注:revisionHistoryLimit 字段设置资源对象记录更新revision(版次)数;当资源频繁更新时,通过这个字段决定我们可以回滚配置的长度。
注:serviceName 和 headless Service 相关联。

三、Statefulset 细节说明

3.1、Statefulset的启停顺序

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

3.2、Statefulset Pod管理策略

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

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