Kubernetes 学习14 kubernetes statefulset

一、概述

  1、在应用程序中我们有两类,一种是有状态一种是无状态。此前一直演示的是deployment管理的应用,比如nginx或者我们自己定义的myapp它们都属于无状态应用。

  2、而对于有状态应用,比如redis,mysql,还有etcd,还有zookeeper等等需要存数据的都属于有状态。它们不光有所谓的节点之分,每一个对应的pod还有角色之分,有的是主节点,有的是从节点。而后,从节点不光有所谓的从之分可能还有先后次序之分,我们不同的分布式系统它们的运维管理,逻辑和运维操作过程是不相同的,因此没有办法把一种控制器把每一种功能都同步进来让我们非常简单的去操作这些有状态的应用,几乎没有任何控制器能做到,后来即便有了statefulset我们去用其实现真正功能控制时也是极其麻烦的。所以我们说statefulset即便在应用程度上能在一定程度上能实现有状态应用的管理效果,但我们需要自行把我们对某个应用的运维管理过程写成脚本注入到statefulset的应用文件中才能使用,但是稍有不慎就会有问题。好在k8s支持所谓叫做TPR,后来改成CRD了(第三方资源或自定义资源)这种机制,甚至于还支持其它更为复杂的机制比如叫api聚合,当我们使用api聚合时就需要自己去修改k8s源代码增强我们自己所需要功能,对大多数人来讲这是不可能的任务,因为它是使用GO语言开发的,所以好在k8s很有弹性支持非常灵活的扩展功能,所以我们能够实现需要自定义一些资源才能解决大多数问题,但即便如此我们想能够使用statefulset封装所有有状态应用还是一个难题,后来coreOS在此基础之上给我们提供了一个组件叫Operator,大家知道Operator就表示运维工程师的意思,所以我们可以把运维工程师的任务,做的日常操作封装在这么一个组件中就可以把Operator当运维工程师用了,能帮你运维很复杂的运维逻辑。里面主要是封装了一些自定义资源还有现有的系统上的应用资源来完成的。

二、StatefulSet(有状态副本集)

  1、一般来讲,无状态的我们更关注的是群体,任何一个都可以轻易的被其它的所取代,换一个然后再新增一个,和原来一不一样都没关系。只要应用程序一样都ok,因为它没有任何数据和本地的状态,但是对有状态的应用来讲我们必须要把他们当宠物,相当于群体和个体(cattle[畜生],pet[宠物])的区别。k8s从1.3开始支持叫PetSet,就叫宠物集,在1.5的时候才改名叫StatefulSet,从名字中可以看出来他们是怎么被理解的。

  2、StatefulSet管理的应用程序,在k8s之上,StatefulSet一般要求主要用于管理拥有以下特性的应用程序。

    a、稳定且需要有唯一的网络标识符

    b、稳定且持久的存储设备,意思是这个节点down了重新启动时确保这个节点存放的数据还在,不在的话构建起来就极其麻烦

    c、有序,平滑的部署和扩展,比如redis的主从复制集群,那么我们应该先启动主节点,然后再启动从节点,如果没有先后顺序可以一下全启动,如果有先后顺序那么需要串行来,先启动第一个,再启第二个再启第三个这种方式来有序平滑的部署和扩展

    d、有序,平滑的终止和删除,比如现在为一主八从的redis集群,那么应该把这八个从节点先关掉。并且如果启动为串行启动那么关闭时候也需要串行关闭。

    e、有序的滚动更新。如果是主从复制服务器我们应该先滚动更新从节点然后再滚动更新主节点。

  3、一个典型的statefulset应该由三个组件组成

    a、headless service(无头服务)

    b、StatefulSet (stateful控制器)

    c、volumeClaimTemplate(存储卷申请模板)

  4、为什么会有上面的需求呢?

    a、我们在定义deployment的时候每一个pod的名称是没有顺序的,它是随机字符串,我们无法识别他们的顺序,因此它是无序的。但是在statefulset中要求必须是有序的。比如我们有r1到r8,r1代表第一个从节点,r8代表最后一个节点,那我们启动时候应该是先启动r1再启动r8,关闭时应该是先关闭r8再关闭r1。既然如此,每一个pod都不能随意被别人所取代,此前是谁,挂了重新启动起来还是应该是谁,比如r6因为故障重建了那么他还是r6,尤其是redis cluster,redis中由很多槽位来存储,第一个节点1-5000,第二个是5001到10000,第三个节点是10001到16383,第一个节点挂了我所有替换出来的时候他没有顺序了这就很麻烦,因为它只有靠顺序才能识别出来它是管理哪些槽位的,由标识符或ip地址决定,但是pod的ip地址是经常发生变化的,因此我们不以ip地址来识别而是以节点名称,所以在有状态集中节点名不能变,每一个节点的节点名是不能动的,并且第一次是什么名我把它删了再重建后这个pod的名称还必须是这个名字。因为pod的名称是作为识别pod唯一性的标识符,这个标识符必须稳定,持久,可行,有效。那么怎么能确保其有这些特性呢?这个时候就需要用到一个headless service来确保我们解析的名称是直达后端pod ip地址,并确保还要给每一个pod配置一个唯一的名称,所以其需要一个headless。

    b、我们讲过大多数有状态副本集都会用到一个功能就是持久存储。任然以redis为例,redis cluster三个节点存储的数据一样么?对于分布式系统来讲其最大的特点就是数据是不一样的,所以这三个pod不能共享同一个后端存储,比如我们作为一个nfs存储卷,多路访问同一个节点上的同一个存储卷是可以的。那么现在我们能不能让我们三个redis的分布式的集群的各节点使用同一个存储卷?他们存的数据完全是不一样的,因此他们肯定不能使用同一个存储卷,因此每个节点应该有自己专用的存储卷。

    c、如果我们在deployment中定义模板中定义一个存储卷,要基于pod模板创建一个pod,这个pod中定义的存储卷,那么如果做了5个pod副本,那么这5个副本肯定是访问同一个存储卷,因为是基于模板创建的pod,因此在模板中创建的存储卷对所有的pod都是一样的。但是我们并没有说在statefulset中每一个pod都不能使用同一个存储卷,因此我们基于Pod模板来创建pod是不适用的,这就是为什么要给其定义volumeClaimTemplate的原因。这样我们创建每一个pod时他会自动生成一个pvc,从而请求绑定一个pv,从而有自己的专用存储卷,每一个pod都会申请一个专用的pvc和pv,因此如果要做一主两从那么至少需要有三个卷让各自分别使用而不是多个pod使用同一个存储卷。

三、statefulset 实例

  1、实例1

 

转载于:https://www.cnblogs.com/Presley-lpc/p/11059218.html

你可能感兴趣的:(数据库,运维,后端)