在 Kubernetes 中,StatefulSet 被用来管理有状态应用的 API 对象。StatefulSets 在 Kubernetes 1.9 版本才稳定。StatefulSet 管理 Pod 部署和扩容,并为这些 Pod 提供顺序和唯一性的保证。与 Deployment 相似的地方是,StatefulSet 基于 spec 规格管理 Pod;与 Deployment 不同的地方是,StatefulSet 需要维护每一个 Pod 的唯一身份标识。这些 Pod 基于同样的 spec 创建,但互相之间不能替换,每一个 Pod 都保留自己的持久化标识。
1、使用 StatefulSet 的场景
对于下面的应用场景,StatefulSets 是有价值的:
稳定、唯一的网络标识
稳定、持久的存储
按照顺序、优雅的部署和扩容
按照顺序、优雅的删除和终止
按照顺序、自动滚动更新
上述的稳定是持久的同义词,如果应用不需要稳定的标识或者顺序的部署、删除、扩容,则应该使用无状态的副本集。Deployment 或者 ReplicaSet 的控制器更加适合无状态业务场景。
2、StatefulSet 的限制
在 Kubernetes 1.9 版本之前是 beta 版本,在 Kubernetes 1.5 版本之前是不提供的。
Pod 存储由 PersistentVolume(storage 类或者管理员预先创建)提供。
删除或者缩容 StatefulSet 不会删除与 StatefulSet 关联的数据卷,这样能够保证数据的安全性。
当前的 StatefulSets 需要一个 Headless 服务来为 Pod 提供网络标识,此 Headless 服务需要通过手工创建。
3、组件
下面是一个 StatefuleSet 组成的示例:
一个名称为 nginx 的 Headless 服务,用来控制网络域。
一个名称为 web 的 statefulSet,它拥有 nginx 容器(在唯一的 Pod 启动)的 3 个副本集。
使用 PersistenVolumes(由 PersistentVolume Provisioner 提供)提供稳定 存储 的 volumeClaimTemplates。
4、Pod 选择器
必须设置 StatefulSet 的 sepc.selector,以匹配.spec.template.metadata.labels。在 Kubernetes 1.8 之前,spec.selector 是可以忽略的,它被设置一个默认值。在 1.8 或者后续的版本,如果不设置 sepc.selector,则会导致创建 StatefulSet 失败。
5、Pod 身份标识
StatfuleSet Pod 拥有一个唯一的身份标识,它由顺序、稳定的网络标识和稳定的存储所组成。此身份标识一直跟随着 Pod,不过它被调度到那个 Node 上。
5.1 序数索引(Ordinal Index)
对于拥有 N 个副本集的 StatefulSet,在 StatefulSet 中的每一个 Pod 都会被指派一个整型的序数,此序数在 0 和 N 之间,在整个集合中是唯一的。
5.2 网络 ID(Stable Network ID)
在 StatefulSet 中,每一个 Pod 的主机名称都由 StatefulSet 的名称和序数所组成。Pod 的主机名称的格式:$(statefulset name)-$(ordinal)
。如果创建了三个 Pod,这他们的主机名称为 web-0,web-1,web-2。StatefulSet 能够使用 Headless 服务来控制 Pod 的域。Service 管理的域的格式为:$(service name).$(namespace).svc.cluster.local
,cluster.local
是集群域。对于每一个被创建的 Pod,它将得到一个 DNS 子域,格式为: $(podname).$(governing service domain)
,这里的管理服务在 StatefulSet 中,通过 serviceName 设置。
下面是 StatefulSet 中 Pod 在 DNS 中的名称:
5.3 稳定的存储
kubernetes 为每一个 VolumeClaimTemplate 创建一个对应的 PersistentVolume。在前面的 nginx 实例中,每一个 Pod 将会 my-storage-class 存储类型的 PersistenVolume 单一实例和 1Gib 的存储空间。
如果没有指定存储类,则会使用默认的存储。但一个 Pod 被调度到 Node 上,它的 volumeMounts 将会挂接 PersistentVolumes,并将其与 PersistentVolumeClaims 进行关联。需要注意的是,即使在 Pod 被删除,PersistentVolumes 与 PersistentVolumeClaims 之间的关联关系也不会被删除。
5.4 Pod 命名标签
当 StatefulSet 控制器创建了 Pod,它将会添加一个标签,为此 Pod 名称的集合。此标签将能够管理服务到指定的 Pod。
6、部署和扩容保证
对于一个带有 N 个副本集的 StatefulSet,当 Pod 被部署,它们将按 0 到 N-1 的顺序被创建。
当一 Pod 被删除时,它们将按照 N-1 到 0 的倒序被终止。
在进行 Pod 扩容前,所有依赖的 Pod 应该都已在运行和准备好。
在 Pod 被终止前,所有的依赖它的 Pod 都必须完全停止。
在前文创建的 nginx 例子中,将按照顺序部署 web-0,web-1 和 web-2。web-1 只能在 web-0 运行和准备好以后才能够被部署,web-2 只能在 web-1 运行和准备好以后才能够被部署。如果 web-0 失败,就算 web-1 正在运行,web-2 也是不能正常启动的,除非 web-0 被重启,并正常运行。
如果缩容上述例子,设置 replicas=1,则 web-2 首先被终止,接着是 web-1。如果在 web-2 被终止后,但在 web-1 被终止前,web-0 失败了,web-1 将不能被终止,除非 web-0 处于正常运行状态。
6.1 Pod 管理策略
在 Kubernetes 1.7 以后,StatefulSet 的唯一性标识可以通过.spec.podManagementPolicy 的值进行保证。
6.1.1 OrderedReady Pod 管理
OrderedReady pod 管理是 StatefulSets 默认的管理模式,此模式安装顺序启动或者终止 Pod。
6.1.2 并行 Pod 管理
并行 Pod 管理告诉 StatefulSet 控制器以并行的方式启动或者终止所有的 Pod。
7、更新策略
在 Kubernetes 1.7 之后,运行通过配置 StatefulSet 的.spec.updateStrategy,实现 Pod 的容器、标签、资源请求/限制和注释自动更新。
7.1 On Delete 策略
OnDelete 更新策略是 1.6 之前版本的行为。当 StatefulSet 的.spec.updateStrategy.type 被设置为 OnDelete,则 StatefulSet 控制器将不会知道更新 Pod。
7.2 Rolling Updates 策略
RollingUpdate 更新策略将实现 StatefulSet 中 Pod 的自动滚动更新,这是 StatefulSet 的默认更新模式。如果.spec.updateStrategy.type 设置为 RollingUpdate,则 StatefulSet 控制器将会删除和重建 StatefulSet 中的每一 Pod。它将会按照从最大到最小的序数终止 Pod,并按照从小到大顺序重建 Pod。
7.3 Partitions
RollingUpdate 更新策略能够通过指定.spec.updateStrategy.rollingUpdate.partition 进行分隔。当分隔被指定,所有序数大于或等于分隔的 Pod 将会被更新,其它的 Pod 将被不会进行更新。在大部分的情况下,不会使用分隔;当希望进行金丝雀发布,或者执行阶段发布时,分隔是很有用的。
作者简介:
季向远,北京神舟航天软件技术有限公司产品经理。本文版权归原作者所有。
评论