zoukankan      html  css  js  c++  java
  • StatefulSet介绍

    一、什么是StatefulSet

    StatefulSet(有状态集,缩写为sts)常用于部署有状态的且需要有序启动的应用程序,比如在进行SpringCloud项目容器化时,Eureka的部署是比较适合用StatefulSet部署方式的,可以给每个Eureka实例创建一个唯一且固定的标识符,并且每个Eureka实例无需配置多余的Service,其余Spring Boot应用可以直接通过Eureka的Headless Service即可进行注册
    
    Eureka的statefulset的资源名称是eureka,eureka-0 eureka-1 eureka-2
    Service:headless service,没有ClusterIP	eureka-svc
    Eureka-0.eureka-svc.NAMESPACE_NAME  eureka-1.eureka-svc
    

    二、StatefulSet的基本概念

    	StatefulSet主要用于管理有状态应用程序的工作负载API对象。比如在生产环境中,可以部署ElasticSearch集群、MongoDB集群或者需要持久化的RabbitMQ集群、Redis集群、Kafka集群和ZooKeeper集群等。
    	和Deployment类似,一个StatefulSet也同样管理着基于相同容器规范的Pod。不同的是,StatefulSet为每个Pod维护了一个粘性标识。这些Pod是根据相同的规范创建的,但是不可互换,每个Pod都有一个持久的标识符,在重新调度时也会保留,一般格式为StatefulSetName-Number。比如定义一个名字是Redis-Sentinel的StatefulSet,指定创建三个Pod,那么创建出来的Pod名字就为Redis-Sentinel-0、Redis-Sentinel-1、Redis-Sentinel-2。而StatefulSet创建的Pod一般使用Headless Service(无头服务)进行通信,和普通的Service的区别在于Headless Service没有ClusterIP,它使用的是Endpoint进行互相通信,Headless一般的格式为:
    statefulSetName-{0..N-1}.serviceName.namespace.svc.cluster.local。
    说明:
    		serviceName为Headless Service的名字,创建StatefulSet时,必须指定Headless Service名称;
    		0..N-1为Pod所在的序号,从0开始到N-1;
    		statefulSetName为StatefulSet的名字;
    		namespace为服务所在的命名空间;
    		cluster.local为Cluster Domain(集群域)。
    	
    	假如公司某个项目需要在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)配置文件如下:
    	port 6379
    	slaveof 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注意事项

    一般StatefulSet用于有以下一个或者多个需求的应用程序:
    	  需要稳定的独一无二的网络标识符
    	  需要持久化数据
    	  需要有序的、优雅的部署和扩展
    	  需要有序的自动滚动更新
    	
    	如果应用程序不需要任何稳定的标识符或者有序的部署、删除或者扩展,应该使用无状态的控制器部署应用程序,比如Deployment或者ReplicaSet
    	StatefulSet是Kubernetes 1.9版本之前的beta资源,在1.5版本之前的任何Kubernetes版本都没有
    	Pod所用的存储必须由PersistentVolume Provisioner(持久化卷配置器)根据请求配置StorageClass,或者由管理员预先配置,当然也可以不配置存储
    	为了确保数据安全,删除和缩放StatefulSet不会删除与StatefulSet关联的卷,可以手动选择性地删除PVC和PV
    	StatefulSet目前使用Headless Service(无头服务)负责Pod的网络身份和通信,需要提前创建此服务
    	删除一个StatefulSet时,不保证对Pod的终止,要在StatefulSet中实现Pod的有序和正常终止,可以在删除之前将StatefulSet的副本缩减为0
    

    四、定义一个StatefulSet资源文件

    4.1、定义一个简单的StatefulSet的示例如下:

    cat > nginx-sts.yaml << EFO
    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:1.15.2
            ports:
            - containerPort: 80
              name: web
    EFO
    # 此示例没有添加存储配置,后面的章节会单独讲解存储相关的知识点
    

    4.2、创建一个StatefulSet

    [root@k8s-master01 ~]# kubectl create -f nginx-sts.yaml
    service/nginx created
    statefulset.apps/web created
    
    # 查看svc信息
    [root@k8s-master01 ~]# kubectl get svc
    NAME         TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
    kubernetes   ClusterIP   10.96.0.1    <none>        443/TCP   42h
    nginx        ClusterIP   None         <none>        80/TCP    24s
    
    # 查看pod信息
    [root@k8s-master01 ~]# kubectl get po
    NAME                        READY   STATUS              RESTARTS   AGE
    nginx-66bbc9fdc5-vc2gh      1/1     Running             0          12h
    nginx-v2-644cd9ccc7-b99nf   1/1     Running             0          11h
    web-0                       1/1     Running             0          113s
    web-1                       0/1     ContainerCreating   0          111s
    
    # 查看sts
    [root@k8s-master01 ~]# kubectl get sts
    NAME   READY   AGE
    web    2/2     2m42s
    

    4.3、StatefulSet的扩容

    [root@k8s-master01 ~]# kubectl scale --replicas=3 sts web
    statefulset.apps/web scaled
    
    # 查看pod、发现名字是固定增长的
    [root@k8s-master01 ~]# kubectl get pod
    NAME                        READY   STATUS              RESTARTS   AGE
    nginx-66bbc9fdc5-vc2gh      1/1     Running             0          12h
    nginx-v2-644cd9ccc7-b99nf   1/1     Running             0          12h
    web-0                       1/1     Running             0          4m48s
    web-1                       1/1     Running             0          4m46s
    web-2                       0/1     ContainerCreating   0          28s
    

    4.4、StatefulSet的缩容

    [root@k8s-master01 ~]# kubectl scale --replicas=2 sts web 
    statefulset.apps/web scaled
    
    # 先删最后一个
    [root@k8s-master01 ~]# kubectl get pod              
    NAME                        READY   STATUS        RESTARTS   AGE
    busybox                     1/1     Running       0          3m41s
    nginx-66bbc9fdc5-vc2gh      1/1     Running       0          12h
    nginx-v2-644cd9ccc7-b99nf   1/1     Running       0          12h
    web-0                       1/1     Running       0          12m
    web-1                       1/1     Running       0          12m
    web-2                       0/1     Terminating   0          7m45s
    

    五、StatefulSet更新策略

    5.1、On Delete策略

    	OnDelete更新策略实现了传统(1.7版本之前)的行为,它也是默认的更新策略。当我们选择这个更新策略并修改StatefulSet的.spec.template字段时,StatefulSet控制器不会自动更新Pod,我们必须手动删除Pod才能使控制器创建新的Pod。
    

    5.2、RollingUpdate策略

    	RollingUpdate(滚动更新)更新策略会更新一个StatefulSet中所有的Pod,采用与序号索引相反的顺序进行滚动更新
    	
    	比如Patch一个名称为web的StatefulSet来执行RollingUpdate更新:
    [root@k8s-master01]# kubectl patch statefulset web -p '{"spec":{"updateStrategy":{"type":"RollingUpdate"}}}'
    statefulset.apps/web patched
    
    查看更改后的StatefulSet:
    [root@k8s-master01 2.2.7]# kubectl get sts web -o yaml | grep -A 1 "updateStrategy"
      updateStrategy:
        type: RollingUpdate
        
    然后改变容器的镜像进行滚动更新:
    [root@k8s-master01 2.2.7]# kubectl patch statefulset web --type='json' -p='[{"op": "replace", "path": "/spec/template/spec/containers/0/image", "value":"dotbalo/canary:v1"}]'
    statefulset.apps/web patched
    
    	如上所述,StatefulSet里的Pod采用和序号相反的顺序更新。在更新下一个Pod前,StatefulSet控制器会终止每一个Pod并等待它们变成Running和Ready状态。在当前顺序变成Running和Ready状态之前,StatefulSet控制器不会更新下一个Pod,但它仍然会重建任何在更新过程中发生故障的Pod,使用它们当前的版本。已经接收到请求的Pod将会被恢复为更新的版本,没有收到请求的Pod则会被恢复为之前的版本
    	
    	在更新过程中可以使用 kubectl rollout status sts/<name> 来查看滚动更新的状态:
    [root@k8s-master01 ~]# kubectl rollout status sts/web
    

    5.3、分段更新(partition)

    	StatefulSet可以使用RollingUpdate更新策略的partition参数来分段更新一个StatefulSet。分段更新将会使StatefulSet中其余的所有Pod(序号小于分区)保持当前版本,只更新序号大于等于分区的Pod,利用此特性可以简单实现金丝雀发布(灰度发布)或者分阶段推出新功能等。注:金丝雀发布是指在黑与白之间能够平滑过渡的一种发布方式。
    
    	# 比如我们定义一个分区"partition":3,可以使用patch直接对StatefulSet进行设置
    [root@k8s-master01 ~]# kubectl patch statefulset web -p '{"spec":{"updateStrategy":{"type":"RollingUpdate","rollingUpdate":{"partition":3}}}}'
    statefulset.apps/web patched
    
    	# 然后再次patch改变容器的镜像:
    [root@k8s-master01 ~]# kubectl patch statefulset web --type='json' -p='[{"op": "replace", "path": "/spec/template/spec/containers/0/image", "value":"k8s.gcr.io/nginx-slim:0.7"}]'
    statefulset.apps/web patched
    	# 删除Pod触发更新
    [root@k8s-master01 ~]# kubectl delete po web-1
    pod "web-1" deleted
    

    六、删除StatefulSet

    删除StatefulSet有两种方式,即级联删除和非级联删除。使用非级联方式删除StatefulSet时,StatefulSet的Pod不会被删除;使用级联删除时,StatefulSet和它的Pod都会被删除

    6.1、级联删除

    使用kubectl delete sts xxx删除StatefulSet时,只需提供--cascade=false参数,就会采用非级联删除,此时删除StatefulSet不会删除它的Pod

    [root@k8s-master01 ~]# kubectl get po 
    NAME                        READY   STATUS    RESTARTS   AGE
    busybox                     1/1     Running   0          56m
    nginx-66bbc9fdc5-vc2gh      1/1     Running   0          13h
    nginx-v2-644cd9ccc7-b99nf   1/1     Running   0          13h
    web-0                       1/1     Running   0          64m
    web-1                       1/1     Running   0          2m54s
    
    # 删除sts
    [root@k8s-master01 ~]# kubectl delete statefulset web --cascade=false
    warning: --cascade=false is deprecated (boolean value) and can be replaced with --cascade=orphan.
    statefulset.apps "web" deleted
    
    # 可以看到已经删除了sts,但是pod还在
    [root@k8s-master01 ~]# kubectl get sts
    No resources found in default namespace.
    [root@k8s-master01 ~]# kubectl get pod
    NAME                        READY   STATUS    RESTARTS   AGE
    busybox                     1/1     Running   0          57m
    nginx-66bbc9fdc5-vc2gh      1/1     Running   0          13h
    nginx-v2-644cd9ccc7-b99nf   1/1     Running   0          13h
    web-0                       1/1     Running   0          65m
    web-1                       1/1     Running   0          4m
    
    # 由于此时删除了StatefulSet,因此单独删除Pod时,不会被重建
    [root@k8s-master01 ~]# kubectl get pod
    NAME                        READY   STATUS    RESTARTS   AGE
    busybox                     1/1     Running   0          59m
    nginx-66bbc9fdc5-vc2gh      1/1     Running   0          13h
    nginx-v2-644cd9ccc7-b99nf   1/1     Running   0          13h
    web-0                       1/1     Running   0          68m
    web-1                       1/1     Running   0          6m21s
    [root@k8s-master01 ~]# kubectl delete pod web-1
    pod "web-1" deleted
    [root@k8s-master01 ~]# kubectl get po
    NAME                        READY   STATUS    RESTARTS   AGE
    busybox                     1/1     Running   0          60m
    nginx-66bbc9fdc5-vc2gh      1/1     Running   0          13h
    nginx-v2-644cd9ccc7-b99nf   1/1     Running   0          13h
    web-0                       1/1     Running   0          68m
    
    # 当再次创建此StatefulSet时,web-0会被重新创建,web-1由于已经存在而不会被再次创建,因为最初此StatefulSet的replicas是2,所以web-2会被删除,如下(忽略AlreadyExists错误)
    [root@k8s-master01 ~]# kubectl create -f nginx-sts.yaml 
    statefulset.apps/web created
    Error from server (AlreadyExists): error when creating "nginx-sts.yaml": services "nginx" already exists
    
    [root@k8s-master01 ~]# kubectl get po
    NAME                        READY   STATUS    RESTARTS   AGE
    busybox                     1/1     Running   1          64m
    nginx-66bbc9fdc5-vc2gh      1/1     Running   0          13h
    nginx-v2-644cd9ccc7-b99nf   1/1     Running   0          13h
    web-0                       1/1     Running   0          72m
    web-1                       1/1     Running   0          26s
    web-2                       1/1     Running   0          24s
    

    6.2、非级联删除

    省略--cascade=false参数即为级联删除

    [root@k8s-master01 ~]# kubectl delete statefulset web
    statefulset.apps "web" deleted
    

    也可以使用-f参数直接删除StatefulSet和Service(此文件将sts和svc写在了一起)

    [root@k8s-master01 ~]# kubectl delete -f nginx-sts.yaml 
    service "nginx" deleted
    Error from server (NotFound): error when deleting "nginx-sts.yaml": statefulsets.apps "web" not found
    
  • 相关阅读:
    Atitit.js图表控件总结
    atitit.attilax的软件 架构 理念.docx
    Atitit.异常处理 嵌套  冗长的解决方案
    Atitit.异常处理 嵌套  冗长的解决方案
    Atitit.atiagent  agent分销系统 代理系统 设计文档
    Atitit.atiagent  agent分销系统 代理系统 设计文档
    Atitit ati licenseService    设计原理
    Atitit ati licenseService    设计原理
    Atitit.项目修改补丁打包工具 使用说明
    Atitit.项目修改补丁打包工具 使用说明
  • 原文地址:https://www.cnblogs.com/hsyw/p/14173542.html
Copyright © 2011-2022 走看看