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