k8s学习记录,StatefulSet(八)

StatefulSet概念

StatefulSet(有状态集群,简写sts)常用于部署有状态的且需要有序启动的应用程序

比如在进行SpringCloud项目容器化时,Eureka的部署是比较适合用StatefulSet部署方式的,可以给每个Eureka实例创建一个唯一且固定的标识符,并且每个Eureka实例无需配置多余的Service,其余SpringBoot应用可以直接通过Eureka的Headless Service即可进行注册

StatefulSet主要用于管理有状态应用程序的工作负载API对象。比如在生产环境中,可以部署ElasticSearch集群、MongoDB集群或者需要持久化的RabbitMQ集群、Redis集群 、Kafka集群和ZooKeeper集群等

与Deployment的区别

StatefulSet为每个Pod维护了一个粘性标识。这些Pod是根据相同的规范创建的,但是不可互换,每个Pod都有一个持久的标识符,在重新调度时也会保留,一般格式为StatefulSetNameNumber。比如定义一个名字是Redis-Sentinel的StatefulSet,指定创建三个Pod,那么创建出来的Pod名字就是Redis-Sentinel、Redis-Sentinel-1、Redis-Sentinel-2。而StatefulSet创建的Pod一般使用HeadlessService(无头服务)进行通信,和普通的Service的区别在于HeadlessService没有ClusterIP,它使用的是Endpoint进行互相通信,Headless一般的格式为:statefulSetName-{0..N-1}.serviceName.namespace.svc.cluster.local

假如公司某个项目需要在Kubernetes中部署一个主从模式的Redis,此时使用StatefulSet部署就极为合适,因为StatefulSet启动时,只有当前一个容器完全启动时,后一个容器才会被调度,并且每个容器的标识符是固定的,那么就可以通过标识符来断定当前Pod的角色。比如用一个名为redis-ms的StatefulSet部署主从架构的Redis,第一个容器启动时,它的标识符为redis-ms-0,并且Pod内主机名也为redis-ms-0,此时就可以根据主机名来判断,当主机名为redis-ms-0的容器作为Redis的主节点,其余从节点,那么Slave连接Master主机配置就可以使用不会更改的Master的Headless Service,此时Redis从节点(Slave)配置文件如下:

redis-ms-0.redis-ms.public-service.svc.cluster.local 6379
tcp-backlog 511
timeout 0
tcp-keepalive 0

其中redis-ms-0.redis-ms.public-service.svc.cluster.local是Redis Master的Headless Service,在同一命名空间下只需要写redis-ms-0.redis-ms即可,后面的public-service.svc.cluster.local可以省略

一般StatefulSet用于有以下一个或者多个需求的应用程序:

  • 需要稳定的独一无二的网络标识符。
  • 需要持久化数据。
  • 需要有序的、优雅的部署和扩展。
  • 需要有序的自动滚动更新。

⚠️注意事项

  • Pod所用的存储必须由PersistentVolume Provisioner(持久化卷配置器)根据请求配置StorageClass,或者由管理员预先配置,当然也可以不配置存储
  • 为了确保数据安全,删除和缩放StatefulSet不会删除与StatefulSet关联的卷,可以手动选择性地删除PVC和PV
  • StatefulSet目前使用Headless Service(无头服务)负责Pod的网络身份和通信,需要提前创建此服务
  • 删除一个StatefulSet时,不保证对Pod的终止,要在StatefulSet中实现Pod的有序和正常终止,可以在删除之前将StatefulSet的副本缩减为0

定义一个StatefulSet资源文件

暂时没有添加存储配置,后面再补充

apiVersion: v1
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:
  serviceName: "nginx"
  replicas: 2
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx
        ports:
        - containerPort: 80
          name: web
  • kind: Service定义了一个名字为Nginx的Headless Service,创建的Service格式为nginx-0.nginx.default.svc.cluster.local,其他的类似,因为没有指定Namespace(命名空间),所以默认部署在default。
  • kind: StatefulSet定义了一个名字为web的StatefulSet,replicas表示部署Pod的副本数,本实例为2。
  • 在1.8版本之后,如果未指定匹配Pod Selector,则会导致StatefulSet创建错误
  • 当StatefulSet控制器创建Pod时,它会添加一个标签statefulset.kubernetes.io/pod-name,该标签的值为Pod的名称,用于匹配Service

根据上面的yaml配置创建statefulset

  • 也可以和deployment一样使用scale进行扩容/缩容

  • 其他的Pod通过podname.servicename来解析statefulset的IP地址

  • Pod启动会按照顺序启动,只有当Pod的状态是Ready时,才会接着往下启动

kubectl scale sts web --replicas=5

  • 删除时,则是倒序,按照Pod名字进行删除
kubectl scale sts web --replicas=2

  • 当Pod正在从5个副本减少到2个副本的过程中,如果web-0此时异常或被删除了,那么会先把web-0启动起来,再接着往后执行

StatefulSet更新策略

  • 更新策略默认为RollingUpdate,更新时,会按pod名字倒序向上更新,如果更新过程中,最上面的pod有挂掉的,更新暂停,先重启挂掉的容器,之后再继续更新
updateStrategy:
    rollingUpdate:
      partition: 0
    type: RollingUpdate

#对已有的5个Pod进行更新镜像操作
kubectl set image sts web nginx=nginx:1.15.3 --record

更新过程中,使用命令删除第一个pod,观察pod的更新顺序

kubectl delete po web-0

  • StatefulSet灰度发布
updateStrategy:
    rollingUpdate:
      partition: 3 #当statefulset配置了5个副本时,如果partition设置为3,那么在更新时,只会更新大于3的副本【更新web-3, web-4,这2个Pod】
    type: RollingUpdate

  • 更新策略为OnDelete时,当前已经运行的Pod不会更新,当Pod被删除后,重建时则会执行更新策略
updateStrategy:
    type: OnDelete

#然后再执行更新策略,更新镜像版本为1.15.2
kubectl set image sts web nginx=nginx:1.15.2 --record

#此时,再输入命令将Pod删除
kubectl delete po web-0

StatefulSet的级联删除和非级联删除

  • 级联删除:删除StatefulSet时同时删除Pod
#默认删除策略是级联删除
kubectl delete sts web

  • 非级联删除:删除StatefulSet时不删除Pod
kubectl delete sts web --casecade=orphan
# 删除statefulset之后,再删除对应的pod,那么pod不会被自动重建

posted @ 2021-05-14 00:05  Hei蛋炒饭  阅读(419)  评论(0编辑  收藏  举报