K8s[控制器]-StatefulSet
K8s[控制器]-StatefulSet
什么是StatefulSet
StatefulSet 顾名思义,用于管理 Stateful(有状态)的应用程序。
StatefulSet 管理 Pod 时,确保其 Pod 有一个按顺序增长的 ID。
StatefulSet 使用场景
对于有如下要求的应用程序,StatefulSet 非常适用:
- 稳定、唯一的网络标识(dnsname)
- 每个Pod始终对应各自的存储路径(PersistantVolumeClaimTemplate)
- 按顺序地增加副本、减少副本,并在减少副本时执行清理
- 按顺序自动地执行滚动更新
如果一个应用程序不需要稳定的网络标识,或者不需要按顺序部署、删除、增加副本,您应该考虑使用 Deployment 这类无状态(stateless)的控制器。
StatefulSet 的限制
- Pod 的存储要么由 storage class 对应的 PersistentVolume Provisioner (opens new window)提供,要么由集群管理员事先创建
- 删除或 scale down 一个 StatefulSet 将不会删除其对应的数据卷。这样做的考虑是数据安全
- 删除 StatefulSet 时,将无法保证 Pod 的终止是正常的。如果要按顺序 gracefully 终止 StatefulSet 中的 Pod,可以在删除 StatefulSet 前将其 scale down 到 0
- 当使用默认的 Pod Management Policy (OrderedReady) 进行滚动更新时,可能进入一个错误状态,并需要人工介入才能修复
创建StatefulSet
Example:
apiVersion: v1 |
标识一个StatefulSet的Pod
- 序号
- 稳定的网络标识
- 稳定的存储
序号
假设一个 StatefulSet 的副本数为 N,其中的每一个 Pod 都会被分配一个序号,序号的取值范围从 0 到 N - 1,并且该序号在 StatefulSet 内部是唯一的
稳定的网络标识
- StatefulSet 中 Pod 的 hostname 格式为 $(StatefulSet name)-$(Pod 序号)。上面的例子将要创建三个 Pod,其名称分别为: web-0,web-1,web-2。
- StatefulSet 可以使用 Headless Service 来控制其 Pod 所在的域。该域(domain)的格式为 $(service name).$(namespace).svc.cluster.local,其中 “cluster.local” 是集群的域。
- StatefulSet 中每一个 Pod 将被分配一个 dnsName,格式为: $(podName).$(所在域名)
需要自行为 StatefulSet 创建 Headless Service
稳定的存储
Kubernetes 为每一个 VolumeClaimTemplate 创建一份 PersistentVolume(存储卷)。在上面的例子中,每一个 Pod 都将由 StorageClass(存储类)my-storage-class
为其创建一个 1Gib 大小的 PersistentVolume(存储卷)。当 Pod 被调度(或重新调度)到一个节点上,其挂载点将挂载该存储卷声明(关联到该 PersistentVolume)。
- 当 Pod 或 StatefulSet 被删除时,其关联的 PersistentVolumeClaim(存储卷声明)以及其背后的 PersistentVolume(存储卷)仍然存在。
- 如果相同的 Pod 或 StatefulSet 被再次创建,则,新建的名为 web-0 的 Pod 仍将挂载到原来名为 web-0 的 Pod 所挂载的存储卷声明及存储卷。
- 这确保了 web-0、web-1、web-2 等,不管被删除重建多少次,都将 “稳定” 的使用各自所对应的存储内容
Pod name 标签
当 StatefulSet 控制器创建一个 Pod 时,会为 Pod 添加一个标签(label) statefulset.kubernetes.io/pod-name
且该标签的值为 Pod 的名字。您可以利用此名字,为 StatefulSet 中的某一个特定的 Pod 关联一个 Service。
实际操作中,无需为 StatefulSet 中的一个特定 Pod 关联 Service,可以直接通过该 Pod 的 DNS Name 访问到 Pod
StatefulSet 的部署和伸缩
- 在创建一个副本数为 N 的 StatefulSet 时,其 Pod 将被按 {0 … N-1} 的顺序逐个创建
- 在删除一个副本数为 N 的 StatefulSet (或其中所有的 Pod)时,其 Pod 将按照相反的顺序(即 {N-1 … 0})终止和删除
- 在对 StatefulSet 执行扩容(scale up)操作时,新增 Pod 所有的前序 Pod 必须处于 Running(运行)和 Ready(就绪)的状态
- 终止和删除 StatefulSet 中的某一个 Pod 时,该 Pod 所有的后序 Pod 必须全部已终止
StatefulSet 中 pod.spec.terminationGracePeriodSeconds
不能为 0.具体原因
StatefulSet 的更新策略
在 Kubernetes 1.7 及之后的版本中,可以为 StatefulSet 设定 .spec.updateStrategy
字段,以便您可以在改变 StatefulSet 中 Pod 的某些字段时(container/labels/resource request/resource limit/annotation等)禁用滚动更新。
On Delete
OnDelete 策略实现了 StatefulSet 的遗留版本(kuberentes 1.6及以前的版本)的行为。如果 StatefulSet 的 .spec.updateStrategy.type
字段被设置为 OnDelete,当您修改 .spec.template
的内容时,StatefulSet Controller 将不会自动更新其 Pod。您必须手工删除 Pod,此时 StatefulSet Controller 在重新创建 Pod 时,使用修改过的 .spec.template
的内容创建新 Pod
Rolling Updates
.spec.updateStrategy.type
字段的默认值是 RollingUpdate,该策略为 StatefulSet 实现了 Pod 的自动滚动更新。在用户更新 StatefulSet 的 .spec.tempalte
字段时,StatefulSet Controller 将自动地删除并重建 StatefulSet 中的每一个 Pod。处理顺序如下:
从序号最大的 Pod 开始,逐个删除和更新每一个 Pod,直到序号最小的 Pod 被更新
当正在更新的 Pod 达到了 Running 和 Ready 的状态之后,才继续更新其前序 Pod
Partitions
通过指定
.spec.updateStrategy.rollingUpdate.partition
字段,可以分片(partitioned)执行RollingUpdate 更新策略。当更新 StatefulSet 的.spec.template
时:- 序号大于或等于
.spec.updateStrategy.rollingUpdate.partition
的 Pod 将被删除重建 - 序号小于
.spec.updateStrategy.rollingUpdate.partition
的 Pod 将不会更新,及时手工删除该 Pod,kubernetes 也会使用前一个版本的.spec.template
重建该 Pod - 如果
.spec.updateStrategy.rollingUpdate.partition
大于.spec.replicas
,更新.spec.tempalte
将不会影响到任何 Pod
- 序号大于或等于