• 九. k8s--statefulset控制器


    为什么要用statefulset控制器

    RC、Deployment、DaemonSet都是面向无状态的服务,它们所管理的Pod的IP、名字,启停顺序等都是随机的,而StatefulSet是什么?顾名思义,有状态的集合,管理所有有状态的服务,比如MySQL、MongoDB集群等。

    StatefulSet本质上是Deployment的一种变体,在v1.9版本中已成为GA版本,它为了解决有状态服务的问题,它所管理的Pod拥有固定的Pod名称,启停顺序,在StatefulSet中,Pod名字称为网络标识(hostname),还必须要用到共享存储。

    在Deployment中,与之对应的服务是service,而在StatefulSet中与之对应的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
    

    statefulset控制器应用

    statefulset要满足一下几点

    • 稳定且唯一的网络标识符;

      如: Redis集群, 在Redis集群中,它是通过槽位来存储数据的,假如:第一个节点是0~1000,第二个节点是1001~2000,第三个节点2001~3000...等等,这就使得Redis集群中每个节点要通过ID来标识自己,如: 第二个节点宕机了,重建后它必须还叫第二个节点,或者说第二个节点叫R2,它必须还叫R2,这样在获取1001~2000槽位的数据时,才能找到数据,否则Redis集群将无法找到这段数据。

    • 稳定且持久的存储

    • 有序、平滑的部署和扩展

      如 MySQL集群,要先启动主节点, 若从节点没有要求,则可一起启动,若从节点有启动顺序要求,可先启动第一个从节点,接着第二从节点等;这个过程就是有顺序,平滑安全的启动。

    • 有序、平滑的终止和删除

      即: 我们先终止从节点,若从节点是有启动顺序的,那么关闭时,也要按照逆序终止,即启动时是从S1~S4以此启动,则关闭时,则是先关闭S4,然后时S3,依次关闭,最后在关闭主节点。

    • 有序的滚动更新

      MySQL在更新时,应该先更新从节点,全部的从节点都更新完了,最后在更新主节点,因为新版本一般可兼容老版本,但是一定要注意,若新版本不兼容老版本就很很麻烦

    statefulset组成

    • Headless Service 用于定义网络标识(DNS)
    • volumeClaimTemplates 用于创建PV
    • StatefulSet 用于定义具体应用

    创建一个statefulset

    apiVersion: v1
    kind: Service
    metadata:
      name: myapp-sts
      labels:
        app: myapp-sts
    spec:
      ports:
      - port: 80
        name: web
      clusterIP: "None"
      selector:
        app: myapp-pod
    ---
    apiVersion: apps/v1
    kind: StatefulSet
    metadata:
      name: myapp
    spec:
      serviceName: myapp-sts #声明它属于哪个Headless Service.
      replicas: 2
      selector:
        matchLabels:
          app: myapp-pod
      template:
        metadata:
          labels:
            app: myapp-pod
        spec:
          containers:
          - name: myapp
            image: ikubernetes/myapp:v1
            ports:
            - containerPort: 80
              name: web
            volumeMounts:
            - name: myappdata
              mountPath: /usr/share/nginx/html
      volumeClaimTemplates:
      - metadata:
          name: myappdata
        spec:
          accessModes: ["ReadWriteOnce"]
          #storageClassName: "rook-ceph-block"
          resources:
            requests:
              storage: 1Gi
    

    可以正确解析到ip

    [root@master statfulset]# nslookup myapp-1.myapp-sts.default.svc.cluster.local 10.96.0.10
    Server:         10.96.0.10
    Address:        10.96.0.10#53
    
    Name:   myapp-1.myapp-sts.default.svc.cluster.local
    Address: 10.244.1.30
    
    [root@master statfulset]# nslookup myapp-0.myapp-sts.default.svc.cluster.local 10.96.0.10
    Server:         10.96.0.10
    Address:        10.96.0.10#53
    
    Name:   myapp-0.myapp-sts.default.svc.cluster.local
    Address: 10.244.1.29
    

    扩容和缩容

    #扩容至三个pod
    kubectl scale sts myapp --replicas=3
    #然后重新缩容至两个pod
    kubectl scale sts myapp --replicas=2
    

    扩容当中出现了一个问题, 新创建的pod处于pending状态, describe看到是mount的问题, 原来是之前pod挂载的pv变成了released状态, 并没有变成available状态, 经过查找发现最关键的是PV的spec.claimRef字段,该字段记录着原来PVC的绑定信息,删除绑定信息,即可重新释放PV从而达到Available。

    statefulset管理pod的启停顺序

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

    statefulset管理策略

    • OrderedReady:上述的启停顺序,默认设置。

      spec:
        podManagementPolicy: OrderedReady
      
    • Parallel:告诉StatefulSet控制器并行启动或终止所有Pod,并且在启动或终止另一个Pod之前不等待前一个Pod变为Running and Ready或完全终止。

      spec:
        podManagementPolicy: Parallel
      

    statefulSet的更新策略:

    kubectl explain sts.spec.updateStrategy.rollingUpdate
    

    partition: 这种更新策略的含义是, 若当前statefulSet的副本数为5个,则Pod名为pod-0~pod-4,那么此时定义partition=4, 就意味着我要更新大于等于4的Pod,而只有pod-4的ID 4 是大于等于4的,所以只有pod-4会被更新,其它不会,这就是金丝雀更新。若后期发现pod-4更新后,工作一切正常,那么就可以调整partition=0,这样只要大于等于0的pod ID都将被更新。

    金丝雀更新

    修改滚动更新策略,查看效果

    kubectl patch sts myapp -p '{"spec":{"updateStrategy":{"rollingUpdate":{"partition":2}}}}'
    
    #修改statefulset的image
    kubectl set image sts/myapp myapp=ikubernetes/myapp:v2
    
    #查看已经修改成功了
    [root@master statfulset]# kubectl get sts myapp -o wide
    NAME    READY   AGE   CONTAINERS   IMAGES
    myapp   4/4     16h   myapp        ikubernetes/myapp:v2
    

    因为策略写的是从第二个容器开始更新

    通过命令kubectl get pod myapp-1 -o yaml可以看到2之前的image没有改变

    通过命令kubectl get pod myapp-2 -o yaml可以看到2之后的image都已经改变了

    #再重新把partition改为0, 则把之前的pod的image都修改生效了
    kubectl patch sts myapp -p '{"spec":{"updateStrategy":{"rollingUpdate":{"partition":0}}}}'
    
    这种方式就可以模拟金丝雀发布
    [root@master statfulset]# kubectl get pods -l app=myapp-pod -o custom-columns=NAME:metadata.name,IMAGE:spec.containers[0].image
    NAME      IMAGE
    myapp-0   ikubernetes/myapp:v2
    myapp-1   ikubernetes/myapp:v2
    myapp-2   ikubernetes/myapp:v2
    myapp-3   ikubernetes/myapp:v2
    

    暂存更新操作

    分区更新操作
    将spec.updateStrategy.rollingUpdate.partition设置为Pod副本数量时,即意味着所有Pod资源都不会处于可直接更新的分区内,直到partition小于Pod数时,才会开始更新

    此时,即便删除某Pod,也会按旧版本进行重建,即暂存状态的更新对所有Pod资源均不产生影响

    使用go-template自定义资源输出信息

    kubectl get pod myapp-1 -o go-template --template='{{.status.podIP}}'
    
    [root@master statfulset]# kubectl get pod myapp-1 -o go-template --template='{{range .spec.containers}}{{.image}}{{end}}'
    ikubernetes/myapp:v2
    

    因为这里查看containers的image信息是一个列表信息, 所以要用到range

    关于更多的go-template的使用方法, 可以参考这位老哥写的博客: https://www.bbsmax.com/A/gAJGgjX3JZ/

    参考链接

    https://www.cnblogs.com/wn1m/p/11289079.html

    https://www.cnblogs.com/tylerzhou/p/11027559.html

    https://www.cnblogs.com/xzkzzz/p/9871837.html

    https://pdf.us/2019/03/15/3013.html

  • 相关阅读:
    交换排序------冒泡法 及其优化
    [编程题]最大和子矩阵
    [编程题] N阶楼梯上楼问题
    2017年东北大学计算机专业考博 面试编程题(某教授 实验室)
    幸运的袋子 (牛客网 16年网易内推 编程题)
    OpenvSwitch代码分析之bridge和port
    阅读书籍---程序员必读系列
    嵌入式开发之davinci--- 8168 电源调试总结
    嵌入式开发之davinci--- 8148/8168/8127 中的添加算饭scd 场景检测 文档简介
    嵌入式开发之davinci--- 8148/8168/8127 中的图像缩放sclr、swms之后出现图像视频卡顿、屏幕跳跃的问题
  • 原文地址:https://www.cnblogs.com/peitianwang/p/11507802.html
Copyright © 2020-2023  润新知