Kubernetes:Deployment与StatefulSet的区别

Kubernetes

Deployment适合无状态的应用;StatefulSet适合有状态的应用。

1. 什么是无状态服务

① 数据方面:无状态服务不会在本地存储持久化数据,多个实例可以共享相同的持久化数据。

② 结果方面:多个服务实例对于同一个用户请求的响应结果是完全一致的。

③ 关系方面:这种多服务实例之间是没有依赖关系的。

④ 影响方面:在k8s控制器中,动态启停无状态服务的pod不会对其它的pod产生影响。

⑤ 示例方面:web应用,nginx实例,tomcat实例。

⑥ 创建方式:Deployment被设计用来管理无状态的pod,每个pod完全一致,原因如下:

  • 无状态服务内的多个pod创建的顺序是没有顺序的。
  • 无状态服务内的多个pod的名称是随机的,pod被重新启动调度后,它的名称与IP都会发生变化。
  • 无状态服务内的多个pod背后是共享存储的。

⑦ 缩容方式:随机缩容。由于是无状态服务,所以这些控制器创建的pod序号都是随机值。并且缩容也是随机,并不会明确缩容某个pod,因为所有实例得到的返回值都是一样的,所以缩容任何一个pod都可以。

2. 什么是有状态服务

① 数据方面:有状态服务需要在本地存储持久化数据,典型的是分布式数据库的应用。

② 结果方面:实例之间,请求结果可能存在不一致。

③ 关系方面:分布式节点实例之间有依赖的拓扑关系,比如,主从关系。

④ 影响方面:如果k8s停止分布式集群中任何一实例pod,就可能导致数据丢失或者集群的crash。

⑤ 示例方面:mysql数据库,kafka,zookeeper,Redis主从架构。

⑥ 创建方式:statefulSet管理。pod的特点:

  • 唯一性:每个pod会被分配一个唯一序号。
  • 顺序性:pod启动、更新、销毁是线性的,按顺序进行。
  • 稳定的网络标识:pod主机名、DNS地址不会随着pod被重新调度而发生变化。
  • 稳定的持久化存储:pod被重新调度后,仍然能挂载原有的PV,从而保证了数据的完整性和一致性。

⑦ 缩容方式:有顺序的缩容。statefulset缩容只会操作一个pod实例,因此有状态应用的缩容相对于无状态的缩容速度会慢。举例来说,一个分布式存储应用若同时下线多个节点,则可能导致其数据丢失,比如,一个数据项副本数为2的数据存储应用,若同时有两个节点下线,如果一份数据正好保存在这两个节点上,这份数据就会丢失。因此缩容是线性的,则分布式存储应用需要时间把丢失的副本复制到其他节点,从而保证数据不会丢失。

3. 访问方式

Deployment

StatefulSet

4. 比较Deployment和StatefulSet

特性DeploymentStatefulSet
是否暴露到外网可以一般不
请求面向的对象serviceName指定pod的域名
灵活性只能通过service/serviceIP访问到k8s自动转发的pod可以访问任意一个自定义的pod
易用性只需要关心Service的信息即可需要知道要访问的pod启动的名称、headlessService名称
PV/PVC绑定关系的稳定性(多replicas)(pod挂掉后重启)无法保证初始的绑定关系可以保证
pod名称稳定性不稳定,因为是通过template创建,每次为了避免重复后缀都是一个随机数稳定,每次都一样
启动顺序
(多replicas)
随机启动,如果pod宕掉重启,会自动分配一个node重新启动pod按app-0、app-1、……、app-(n-1),如果pod宕掉重启,还会在之前的node上重新启动
停止顺序(多replicas)随机停止倒序停止
集群内部服务发现只能通过service访问到随机的pod可以打通pod之间的通信(主要是被发现)
性能开销无需维护pod与node、pod与PVC等关系比deployment类型需要维护额外的关系信息

综上所述:

  • 如果不需额外数据依赖或者状态维护的部署,或者replicas是1,优先考虑使用Deployment;
  • 如果单纯的要做数据持久化,防止pod宕掉重启数据丢失,那么使用PV/PVC;
  • 如果要打通app之间的通信,而又不需要对外暴露,使用headlessService即可;
  • 如果需要使用service的负载均衡,不要使用StatefulSet,尽量使用clusterIP类型,用serviceName做转发;
  • 如果是有多replicas,且需要挂载多个PV且每个PV的数据是不同的,因为pod和PV之间是一一对应的,如果某个pod挂掉再重启,还需要连接之前的PV,不能连到别的PV上,考虑使用StatefulSet;
  • 能不用StatefulSet,就不用。

注意:

如果使用StatefulSet,spec.serviceName需要指向headlessServiceName,且不能省略指定步骤,官方文档要求headlessService必须在创建StatefulSet之前创建完成,如果没有也不会影响pod运行(pod还是running状态),只是不能拥有一个stable-network-id 集群内部不能访问到这个服务(如果这个服务不需要被发现,只需要去发现其他服务,则serviceName随便写一个也行),官方要求要在创建StatefulSet之前创建好headlessService,是为了让pod启动时能自动对应到service上。

之所以要指定一个headlessService,是因为admin可以给StatefulSet创建多个、多种类型的service,k8s不知道要用哪个service的名称当作集群内域名的一部分。

5. 小结

Deployment特点:

  • pod之间没有顺序;
  • 所有pod共享存储;
  • pod名字包含随机数;
  • service都有clusterIP,可以负载均衡。

StatefulSet特点:

  • 部署、扩展、更新、删除都要有顺序;
  • 每个pod都有自己存储,所以都用volumeClaimTemplates,为每个pod都生成一个自己的存储,保存自己的状态;
  • pod的名字始终是固定的;
  • service没有clusterIP,是headlessService,所以无法负载均衡,返回的都是pod名,因此pod名字都必须固定,StatefulSet在headlessService的基础上,又为StatefulSet控制的每个pod副本创建了一个DNS域名:$(podName).$(headlessServiceName).$(namespace).svc.cluster.local。

参考链接:

https://zhuanlan.zhihu.com/p/248405724

https://blog.csdn.net/nickDaDa/article/details/90401635

https://blog.csdn.net/weixin_36755535/article/details/127652695

Related Posts

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注