K8s StatfulSet使用总结

Stella981
• 阅读 525

StatefulSet:
在1.3以前K8s中StatefulSet叫PetSet(宠物集),由此也可看出StatefulSet是关注个体,而非群体。
StatefulSet要满足以下几点:

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

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

  • 稳定且持久的存储

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

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

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

    创建一个StatefulSet控制器的示例: vim pod-statefulset.yaml apiVersion: v1 kind: Service metadata: name: myapp labels: app: myapp spec: ports:

    • port: 80 name: web clusterIP: None selector: app: myapp-pod

    apiVersion: apps/v1 kind: StatefulSet metadata: name: myapp spec: serviceName: myapp replicas: 3 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: #注意: 它是statefulset.spec.volumeClaimTemplates.

    • metadata: name: myappdata spec: accessModes: ["ReadWriteOnce"]
      #storageClassName: “gluster-dynamic” #这是定义存储类的。 resources: requests: storage: 2Gi

#实验中问题总结:
accessModes: [ “ReadWriteOnce” ]
  #这里需要注意: 你指定模式为RWO,那么你使用kubectl get pv时,必须有RWO权限的pv,因为本例是要创建3个StatefulSet的Pod,因此就需要3个RWO权限的pv,但我测试时,就只有一个pv是RWO的,因此导致创建Pod一直处于Pending状态,而且只有一个! 使用kubectl describe pvc PVC_NAME 查看时提示: no persistent volumes available for this claim and no storage class is set(此声明没有可用持久卷,也没有存储类),其实问题已经说的很白了,但没有经验,所以这点要特别注意!!
  #第二个问题: 我后来新增了3个RWO权限的pv,但在NFS上,忘记创建对应的目录了,使用exportfs -avr 也提示了,目录没有找到,但我没仔细看,结果导致我创建Pod时,一直处于ContainerCreating,查看kubectl describe pod myapp-0 看到mount.nfs: mounting 192.168.111.83:/data/volumes/v6 failed, reason given by server: No such file or directory 这样的错误,最后才想到可能是目录没有创建。
  #第三个问题:我在创建PV时,使用的是k8s集群外部的域名nfs.zcf.com 来指定NFS Server是谁,但我K8s集群内还不能解析集群外域名,也导致了访问超时的问题。
  #第四个问题:创建serive时总提示ClusterIP是无效值:
  解决步骤:
    1. 检查配置清单中clusterIP是否有写错.
    2. 检查是否有service同名冲突:
      kubectl get svc

#创建statefulset:
#执行创建statefulSet前,需要先手动创建出符合条件的PV,若你已经实现了动态供给存储卷,
#则可不用手动事先创建好PV。
  kubectl apply -f pod-statefulset.yaml

#查看:
  kubectl get svc
  kubectl get [statefulset |sts]
  kubectl get pvc    #volumeClaimTemplates可动态创建Pod内部的PVC,然后再创建名称空间级的PVC
注:
    Pod内容器挂载PV的过程 或 层级是这样的:
  容器要挂载网络磁盘---->Pod中要有对应的PVC---->Pod所在的名称空间中要有对于的PVC----->
  K8s集群中要有对应的PV---->要有输出共享存储的后端服务器上的共享空间
  而volumeClaimTemplates它可自动创建Pod 和 名称空间中的PVC。
  kubectl get pv
  kubectl get pods

终端2:
 kubectl  get  pods  -w

终端1:
 kubectl  delete  -f  pod-statefulset.yaml          #删除后,查看终端2上,删除Pod的顺序是否为先删除2,1,0
    #在k8s 1.13.5中测试时,发现:
    #  删除时,似乎没有顺序:
    kubect  get  pod  -w   -l  app=myapp-pod
        myapp-1   1/1   Terminating   0     31s
        myapp-0   1/1   Terminating   0     34s
        myapp-2   1/1   Terminating   0     28s
        myapp-1   0/1   Terminating   0     33s
        myapp-2   0/1   Terminating   0     31s
        myapp-0   0/1   Terminating   0     37s
        myapp-1   0/1   Terminating   0     41s
        myapp-1   0/1   Terminating   0     41s
        myapp-0   0/1   Terminating   0     47s
        myapp-0   0/1   Terminating   0     47s
        myapp-2   0/1   Terminating   0     41s
        myapp-2   0/1   Terminating   0     41s
                        
终端1:
 kubectl   apply  -f   pod-statefulset.yaml   #查看创建Pod的过程是否为先0,1,2
   #此测试是正常的:
    myapp-0   0/1   Pending   0     0s
    myapp-0   0/1   Pending   0     0s
    myapp-0   0/1   ContainerCreating   0     0s
    myapp-0   1/1   Running   0     3s
    myapp-1   0/1   Pending   0     0s
    myapp-1   0/1   Pending   0     0s
    myapp-1   0/1   ContainerCreating   0     0s
    myapp-1   1/1   Running   0     3s
    myapp-2   0/1   Pending   0     0s
    myapp-2   0/1   Pending   0     0s
    myapp-2   0/1   ContainerCreating   0     0s
    myapp-2   1/1   Running   0     2s


 kubectl  describe  pods  myapp-2  #查看myapp-2是否依然绑定PV-2,而且当你删除pod后,kubectl  get  pv,也会发现,Retain策略是不会释放绑定关系的.
 
#statefulSet的域名结构为:
pod_name.service_name.namespace_name.svc.cluster.local
如:
    上例中创建了三个Pod,其中一个叫myapp-0
    myapp-0.myapp.default.svc.cluster.local

#对statefulSet做扩缩容:
#扩容:
  kubectl  scale  sts  myapp  --replicas=5
    #注意:
    #   在定义StatefulSet时,Pod的模板中指定自动创建pvc,并关联可用PV时,选择可用大小为1Gi,我期望时,它自动关联时,选择最匹配的,但事实似乎并非如此。
    #   查看
    # kubectl get pv
    NAME   CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM                       STORAGECLASS   REASON   AGE
    pv01   1Gi        RWO,RWX        Retain           Available                                                       87m
    pv02   2Gi        ROX,RWX        Retain           Bound       default/myappdata-myapp-3                           87m
    pv03   5Gi        ROX,RWX        Retain           Bound       default/myappdata-myapp-4                           87m      #明明有一个1Gi的,它没有选择,而是选择了5Gi的
    pv04   10Gi       ROX,RWX        Retain           Available                                                       87m
    pv05   20Gi       ROX,RWX        Retain           Available                                                       87m
    pv06   1Gi        ROX,RWX        Retain           Bound       default/myappdata-myapp-0                           87m
    pv07   1Gi        ROX,RWX        Retain           Bound       default/myappdata-myapp-1                           87m
    pv08   2Gi        ROX,RWX        Retain           Bound       default/myappdata-myapp-2                           87m
            

终端2:
    kubectl  get  pods  -w          #当执行扩容Pod后, 会看到先创建myapp-3,然后是myapp-4

#缩容:
    kubectl  patch  sts  myapp  -p  ‘{"spec":{"replicas":2}}’

终端2:
    kubectl  get  pods  -w          #依然查看其缩容的过程,在缩容时,竟然是按顺序的,4,3,2
    myapp-4   1/1   Terminating   0     5m41s
    myapp-4   0/1   Terminating   0     5m43s
    myapp-4   0/1   Terminating   0     5m53s
    myapp-4   0/1   Terminating   0     5m53s
    myapp-3   1/1   Terminating   0     5m56s
    myapp-3   0/1   Terminating   0     5m57s
    myapp-3   0/1   Terminating   0     5m58s
    myapp-3   0/1   Terminating   0     5m58s
    myapp-2   1/1   Terminating   0     8m41s
    myapp-2   0/1   Terminating   0     8m43s
    myapp-2   0/1   Terminating   0     8m49s

#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":4}}}}’
     #注:
        在打补丁时,若对象为list类型,则需要使用"[]",来指明其下标,如: containers[0],就是第一个容器.

kubectl  describe  sts  myapp      #查看其滚动更新策略中partition的值是否修改为4了。
#在k8s 1.13.5中查看如下:
    .......
    Replicas:           824638453880 desired | 5 total
    Update Strategy:    RollingUpdate
      Partition:        824638454284
    .......
 #但通过kubectl  get  sts  myapp  -o  yaml  查看,就可以看到,已经修改为4了。
    .........
      updateStrategy:
        rollingUpdate:
          partition: 4
        type: RollingUpdate
   .......

  #以上statefulSet的更新策略已经修改好了,接着来修改pod的镜像为新版镜像,来查看其滚动更新的
  kubectl set image sts/myapp myapp=ikubernetes/myapp:v2

#查看:
  kubectl get sts -o wide    #查看statefulSet控制器层面的容器镜像是否修改成功了。

  kubectl get pods myapp-4 -o yaml    #查看statefulSet控制器下myapp-4这个容器的state(当前运行状态信息)中image是否修改成功了.
  kubectl get pods myapp-3 -o yaml    #查看其image应该是没有改变的

终端2:
  kubectl get pods -w    #当修改更新策略后,这里将可以看到滚动更新的效果了。

终端1:
  kubectl patch sts myapp -p ‘{"spec":{"updateStrategy":{"rollingUpdate":{"partition":0}}}}’
  #由于上面已经跟新了镜像,当这里修改了更新策略后,马上就会触发滚动更新!! 需要注意!!
  注意:
    statefulSet在实际使用中还是需要谨慎!

附上一张PVC和PV的关系图:

  K8s StatfulSet使用总结

另外,最好的学习平台是githup,它上面有很多别人做好的清单文件,可作为学习的参考。

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
待兔 待兔
4个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Jacquelyn38 Jacquelyn38
3年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
Stella981 Stella981
3年前
KVM调整cpu和内存
一.修改kvm虚拟机的配置1、virsheditcentos7找到“memory”和“vcpu”标签,将<namecentos7</name<uuid2220a6d1a36a4fbb8523e078b3dfe795</uuid
Easter79 Easter79
3年前
Twitter的分布式自增ID算法snowflake (Java版)
概述分布式系统中,有一些需要使用全局唯一ID的场景,这种时候为了防止ID冲突可以使用36位的UUID,但是UUID有一些缺点,首先他相对比较长,另外UUID一般是无序的。有些时候我们希望能使用一种简单一些的ID,并且希望ID能够按照时间有序生成。而twitter的snowflake解决了这种需求,最初Twitter把存储系统从MySQL迁移
Stella981 Stella981
3年前
Django中Admin中的一些参数配置
设置在列表中显示的字段,id为django模型默认的主键list_display('id','name','sex','profession','email','qq','phone','status','create_time')设置在列表可编辑字段list_editable
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
为什么mysql不推荐使用雪花ID作为主键
作者:毛辰飞背景在mysql中设计表的时候,mysql官方推荐不要使用uuid或者不连续不重复的雪花id(long形且唯一),而是推荐连续自增的主键id,官方的推荐是auto_increment,那么为什么不建议采用uuid,使用uuid究
Python进阶者 Python进阶者
10个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这