StatefulSet
StatefulSet中的Stateful是有状态的意思。其中的状态即指:StatefulSet接管的每个Pod有稳定的网络标识(包括Pod的名称和主机名,是顺序索引值)、稳定的专属存储。进一步解释:
StatefulSet替换旧Pod时,新Pod与其有相同的名称、网络标识和状态;
StatefulSet管理的Pod可以有各自独立的存储卷;
StatefulSet创建的Pod的名字是有规律的,不是随机生成的;
StatefulSet接管下的Pod的架构可以用下图表示:

StatefulSet的at-most-one语义:StatefulSet必须保证不会有两个及两个以上的具有相同名称(和主机名)、绑定了相同PVC的Pod实例运行。原因可想而知。
StatefulSet与ReplicaSet对比
把StatefulSet比作宠物,ReplicaSet比作牛。
对于有状态应用,即StatefulSet接管的Pod,就像宠物一样,若一只宠物死掉,若要找一个替换它,除非找到完全一模一样的(现实中当然是不可能的),否则用户不可能感知不到。
对于无状态应用,即ReplicaSet接管的Pod,就像农场中的牛一样,若一只牛死掉,农场主完全可以找另一个牛来替代,不用一模一样,对于用户(食客)没有什么差别。
稳定的网络标识
在前面提到过,StatefulSet创建的Pod的名称和主机名都是固定的(因此称之为稳定的网络标识),因此在使用StatefulSet时通常都会创建一个用来记录每个Pod网络标识的headless Service(即Service资源的spec.clusterIP=None)。通过这个Service资源对象,每个Pod都有自己专属的DNS记录,这样分布式应用中的其他Pod可以方便的通过主机名找到该Pod。例如,一个Pod的名称(主机名)为A-0,Service的名字为foo,属于default这个命名空间,那么a-0.foo.default.svc.cluster.local就是这个Pod的专属域名。
紧跟着上面这个例子,我们通过访问foo.default.svc.cluster.local也可以获得其对应的所有SRV记录,从而获得了StatefulSet管理的所有Pod的名称和主机名。
稳定的专属存储
StatefulSet创建的Pod都有自己的专属存储,这是依赖PVC(持久卷声明)实现的,PVC与PV是一一对应的关系,而Pod与PVC是一一对应的关系,即PVC会在Pod创建之前创建出来,并绑定至Pod上。
当StatefulSet删除Pod时,会保留PVC和PV,当创建新的同规格的Pod时,会将该保留的PVC再绑定至该Pod上。
扩缩容
扩缩容的方式可见修改资源方式中的方式。
扩容
扩容一个StatefulSet会使用下一个还没用到的顺序索引值创建一个新的Pod。比如,现有2个Pod,它们的索引值为0和1,则新创建的Pod的索引值为2。
在扩容时,会根据Pod的PVC模板创建它专属的PV。
缩容
缩容一个StatefulSet会最先删除最高索引值,因此StatefulSet的缩容结果是可预见的。比如,现有3个Pod,则最先被删除的Pod的索引值为2。
StatefulSet的缩容是线性的(即删除完一个,再删下一个),所以在有Pod不健康的情况下,是不允许做缩容操作的。
在缩容时,Pod会被直接删除,但是PV和PVC不会被删除。
创建StatefulSet
通过StatefulSet部署应用时,总共需要部署两个(或三个)不同的资源类型对象:
持久卷(PersistentVolume):存储应用的数据文件(若集群不支持持久卷动态供应时,才需要手动创建)
headless Service:为Pod提供依靠主机名访问应用中其他Pod的能力(通常访问应用不会通过该Service,而是另外再建一个Service将应用的API接口地址暴露出去);
StatefulSet本身;
部署持久卷
部署headless Service
部署StatefulSet
部署结果
部署结果如下:
发现应用中其他Pod节点
在之前提到过,在部署StatefuSet资源对象时,需要创建一个headless Service资源对象,该对象可以为应用中的Pod提供发现其他Pod的能力。
假设在default命名空间中,有一个名为kubia的headless Service,那么应用中的其他Pod可以使用dig命令,访问kubia.default.svc.cluster.local就可以通过SRV记录,获得该Service的所有后端的Pod:
kubia-0.kubia.default.svc.cluster.local是一个Pod的DNS域名,其地址为172.17.0.8
kubia-1.kubia.default.svc.cluster.local是另一个Pod的DNS域名,其地址为172.17.0.9
通过该机制,可以得到一个简易的分布式数据存储服务的操作流程,如下图所示,图中的每一个Pod都有自己的存储空间,用户的请求会随机打到任意一个Pod上,该Pod会从其他Pod上获取数据,并与自己本地数据汇总,然后再返回给用户:

处理Node失效
由于StatefulSet需要保证不会拥有两个相同标记和存储的Pod同时运行,因此在明确知道一个Pod不再运行之前,它不会去创建一个替换Pod。
当Node失效时,需要管理员手动通知Kubernetes删除失效的Pod,StatefulSet才会去创建替换Pod。
若是因为网络问题导致Node失效,则失效Node上的kubelet无法收到API服务器的删除请求,因此失效Pod还会存在列表中(无论其状态是什么),此时StatefulSet是不会去创建替换Pod的,需要管理员强制删除该Pod才可以,令其从列表中消失。
Last updated
Was this helpful?