StatefulSet
StatefulSet(有状态集,缩写为 sts)常用于部署有状态的且需要有序启动的应用程序,比如在进行Spring Cloud 项目容器化时,Eureka 的部署是比较适合用 StatefulSet 部署的,可以给每个 Eureka 实例创建一个唯一且固定的标识符,并且每个 Eureka 实例无须配置多余的 Service,其余 Spring Boot 应用可以直接通过 Eureka 的 Headless Service 进行注册。
简介
在 Kubernetes 系统中,Pod 的管理对象 RC、Deployment、DaemonSet 和 Job 都面向无状态的服务。但现实中有很多服务是有状态的,特别是一些复杂的中间件集群,例如 MySQL 集群、MongoDB 集群、Akka 集群、ZooKeeper 集群等,这些应用集群有 4 个共同点:
每个节点都有固定的身份 ID,通过这个 ID,集群中的成员可以相互发现并通信。
集群的规模是比较固定的,集群规模不能随意变动。
集群中的每个节点都是有状态的,通常会持久化数据到永久存储中。
如果磁盘损坏,则集群里的某个节点无法正常运行,集群功能受损。
如果通过 RC 或 Deployment 控制 Pod 副本数量来实现上述有状态的集群,就会发现第 1 点是无法满足的,因为 Pod 的名称是随机产生的,Pod 的 IP 地址也是在运行期才确定且可能有变动的,事先无法为每个 Pod 都确定唯一不变的 ID。
另外,为了能够在其他节点上恢复某个失败的节点,这种集群中的 Pod 需要挂接某种共享存储。
为了解决这个问题,Kubernetes 从 1.4 版本开始引入了 PetSet 这个新的资源对象,并且在 1.5 版本时更名为 StatefulSet,StatefulSet 从本质上来说,可以看作 Deployment/RC 的一个特殊变种,它有如下特性:
StatefulSet 里的每个 Pod 都有稳定、唯一的网络标识,可以用来发现集群内的其他成员。假设StatefulSet 的名称为 kafka,那么第 1 个 Pod 叫 kafka-0,第 2 个叫 kafka-1,以此类推。
StatefulSet 控制的 Pod 副本的启停顺序是受控的,操作第 n 个 Pod 时,前 n-1 个 Pod 已经是运行且准备好的状态。
StatefulSet 里的 Pod 采用稳定的持久化存储卷,通过 PV 或 PVC 来实现,删除 Pod 时默认不会删除与 StatefulSet 相关的存储卷(为了保证数据的安全)。
Headless Service
StatefulSet 除了要与 PV 卷捆绑使用以存储 Pod 的状态数据,还要与 Headless Service 配合使用,即在每个 StatefulSet 定义中都要声明它属于哪个 Headless Service。
Headless Service 与普通 Service 的关键区别在于,它没有 Cluster IP,如果解析 Headless Service 的 DNS 域名,则返回的是该 Service 对应的全部 Pod 的 Endpoint 列表。Headless Service 使用 Endpoint 进行互相通信。
StatefulSet 在 Headless Service 的基础上又为 StatefulSet 控制的每个 Pod 实例都创建了一个 DNS 域名,这个域名的格式为:${podName}.${serviceName}.${namespace}.svc.cluster.local。
其中:
podName=${statefulSetName}-number
statefulSetName 是 StatefulSet 的名称
number 是一个整数,表示 Pod 的序号,以 0 作为起始值
serviceName 是 Headless Service 的名字,创建 StatefulSet 时必须指定 Headless Service 名称
namespace 是服务所在的命名空间。
如果访问的 Pod 位于同一命名空间下,可以省略不写
cluster.local 为 Cluster Domain(集群域)
假如公司某个项目需要在 Kubernetes 中部署一个主从模式的 Redis,此时使用 StatefulSet 部署就极为合适,因为 StatefulSet 启动时,只有当前一个容器完全启动时,后一个容器才会被调度,并且每个容器的标识符是固定的,那么就可以通过标识符来断定当前 Pod 的角色。
比如用一个名为 redis-cluster 的 StatefulSet 部署主从架构的 Redis:
第一个容器启动时,它的标识符为 redis-cluster-0,并且 Pod 内主机名也为 redis-cluster-0。
将主机名为 redis-cluster-0 的容器作为 Redis 的主节点,其余为从节点,那么从节点连接 主节点时就可以使用不会更改的 Master 的 Headless Service。
此时 Redis 从节点(Slave)配置文件如下:
其中 redis-cluster-0.redis-ms.public-service.svc.cluster.local 是 Redis Master 的 Headless Service。
在同一命名空间下只需要写 redis-cluster-0.redis-ms 即可,后面的 public-service.svc.cluster.local 可以省略。
最后更新于
这有帮助吗?