[Kubernetes]深入理解StatefulSet

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/zll_0405/article/details/86683770

前面我写的一系列博客,如果你能够耐心看到这一篇,那你应该对一个概念就不是太陌生了:Deployment.
为什么提这个概念呢,这就要说到Deployment的一个不足了.Deployment不足以覆盖所有的应用编排问题,因为在它看来,一个应用的所有Pod,是完全一样的,所以它们之间就没有顺序,也无所谓运行在哪台宿主机上.需要时,Deployment就通过Pod模板创建新的Pod,不需要时,就"杀掉"任意一个Pod.
但是在实际场景中,并不是所有应用都满足这样的要求.比如:主从关系,主备关系,还有就是数据存储类应用,多个实例通常会在本地磁盘上保存一份数据,而这些实例一旦被杀掉,即使重建出来,实例与数据之间的对应关系也已经丢失,从而导致应用失败.
这种实例之间有不对等关系,或者有依赖关系的应用,被称为"有状态应用"(Stateful Application)
为了能对"有状态应用"做出支持,Kubernetes在Deployment基础上,扩展出了:StatefulSet.

StatefulSet设计

StatefulSet将真实世界里的应用状态,抽象为了两种情况:

  • 1,拓扑状态.这种情况是说,应用的多个实例之间不是完全对等的关系.这些应用实例,必须按照某些顺序启动,比如某个应用的主节点A要先于B启动,那么当我把A和B两个节点删除之后,重新创建出来时,也要是这个顺序才行.并且,新创建出来的A和B,必须和原来的A和B网络标识一样,这样原先的访问者才能使用同样的方法,访问到这个新Pod.
  • 2,存储状态.这种情况是说,应用的多个实例分别绑定了不同的存储数据.对于这些应用实例来说,Pod A第一次读取到的数据,和隔了十分钟之后再次读取到的数据,应该是同一份,哪怕在此期间Pod A被重新创建过.
所以,StatefulSet的核心功能,就是通过某种方式,记录这些状态,然后在Pod被重新创建时,能够为新Pod恢复这些状态.
Headless Service

在深入了解StatefulSet之前,咱们先来讲讲Headless Service.
我们知道,Service是Kubernetes项目中用来将一组Pod暴露给外界访问的一种机制,比如,一个Deployment有3个Pod,那么我就可以定义一个Service,然后用户只要能访问到这个Service,就能访问到某个具体的Pod.
但是,这个Service是怎么被访问到的呢?

第一种方式,以Service的VIP(Virtual IP,即:虚拟IP)方式.比如:当我访问192.168.0.1这个Service的IP地址时,它就是一个VIP.在实际中,它会把请求转发到Service代理的具体Pod上.
第二种方式,就是以Service的DNS方式.在这里又分为两种处理方法:第一种是Normal Service.这种情况下,当访问DNS记录时,解析到的是Service的VIP.第二种是Headless Service.这种情况下,访问DNS记录时,解析到的就是某一个Pod的IP地址.
可以看到,Headless Service不需要分配一个VIP,而是可以直接以DNS记录的方式解析出被代理Pod的IP地址.这样设计有什么好处呢?
这样设计可以使Kubernetes项目为Pod分配唯一"可解析身份".而有了这个身份之后,只要知道了一个Pod的名字以及它对应的Service的名字,就可以非常确定地通过这条DNS记录访问到Pod的IP地址.

再回到StatefulSet

介绍完Headless Service之后,咱们再回来讲讲,StatefulSet的核心功能,是如何在Pod被重新创建时,能够为新Pod恢复这些状态.

为了详细讲解,现在编写一个StatefulSet的YAML文件,如下:

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.9.1
        ports:
        - containerPort: 80
          name: web

可以看到,在这个YAML文件中,多了一个serviceName=nginx字段.这个字段的作用,就是告诉StatefulSet控制器,在执行控制循环时,要使用nginx这个Headless Service来保证Pod的"可解析身份."这样,在创建Pod过程中,StatefulSet给它所管理的所有Pod名字,进行编号,使得每个Pod实例不重复.而更重要的是,这些Pod的创建,也是严格按照编号顺序来进行的.
这样的意思就是说,当有主从关系时,有明确先后关系时,StatefulSet通过这种机制,使得先后创建顺序成为可能.

整个StatefulSet流程

接下来回顾一下整个流程.
首先,StatefulSet的控制器直接管理的是Pod,而StatefulSet区分这些实例的方式,就是通过在Pod的名字里面加上事先约定好的编号.
其次,Kubernetes通过Headless Service,为这些有编号的Pod,在DNS服务器中生成带有同样编号的DNS记录.只要StatefulSet能够保证这些Pod名字里的编号不变,那么Service中DNS记录也就不会变.
最后,StatefulSet还为每一个Pod分配并创建一个同样编号的PVC.这样就可以保证每个Pod都拥有一个独立的Volume.在这种情况下,即使Pod被删除,它所对应的PVC和PV依然会留下来,所以当这个Pod被重新创建出来之后,Kubernetes会为它找到同样编号的PVC,挂载这个PVC对应的Volume,从而获取到以前保存在Volume中的数据.

其实StatefulSet就是一种特殊的Deployment,只不过它的每个Pod都被编号了.正是由于这种机制,使得具有主从关系的创建成为可能.

关于StatefulSet相关内容到这里就介绍的差不多了.
以上内容来自我学习<深入剖析Kubernetes>专栏文章之后的一些见解,有偏颇之处,还望指出.
感谢您的阅读~

猜你喜欢

转载自blog.csdn.net/zll_0405/article/details/86683770