
控制器 - StatefulSets
目标
StatefulSets 的使用场景 StatefulSets 基本信息 StatefulSets 部署与伸缩 StatefulSets 更新策略
StatefulSets 的使用场景
StatefulSets 概述
StatefulSets 顾名思义,是管理 Stateful(有状态的)应用程序
StatefulSets 管理 Pod 时,确保 Pod 有一个按照顺序增长的 ID
与 Deployment 相似,StatefulSets 基于一个 Pod 模板管理其 Pod,与 Deployment 最大的不同在于 StatefulSets 始终将一系列的名字分配给其 Pod ,这些 Pod 从同一个模板创建,但是并不能相互替换,每个 Pod 都对应一个特有的持久化标识
同其他的控制器一样,StatefulSets 也使用相同的模式运作,用户在 StatefulSets 中定义好期待的状态,StatefulSets 控制器执行需要的操作,达成最终的效果
StatefulSets 的使用场景
对于如下要求的应用程序,StatefulSets 非常合适
稳定,唯一的网络标识(dnsname) 每个 Pod 始终对于着各自的存储路径(PersistantVolumeClaimTemplate) 按顺序的执行增加副本,减少副本,在减少副本时执行清理 按顺序自动的执行滚动更新
如果一个应用程序不需要稳定的网络标识,或者不需要按顺序部署、删除、增加副本,您应该考虑使用 Deployment 这类无状态(stateless)的控制器
StatefulSets 限制
Pod 的存储要么由 storage class 对应的 PersistantVolumeClaimTemplate 提供,要么由管理员事先创建好 删除或scale down 一个 StatefulSets 将不会对其数据卷进行清理,原因是保证数据的安全 删除 StatefulSets 时,将无法保证 Pod 的终止是正常的,如果要按顺序优雅的终止 StatefulSets 的 Pod 可以在删除 StatefulSets 前将其 scale down 到 0 当使用默认更新策略进行滚动更新时,可能进入一个错误的状态,需要人工介入才能修复
StatefulSets 基本信息
创建 StatefulSets
下面是个 StatefulSets 的例子,由如下的内容组成:
一个名为 nginx 的 无头服务,用于控制网络域 一个名为 web 的 StatefulSets 副本为 3 volumeClaimTemplates 提供稳定的存储(每一个 Pod ID 对应自己的存储卷,且 Pod 重连后,仍然可以找到对应的存储卷)
名为nginx-statefulsets.yaml
配置文件如下:
apiVersion: v1
kind: Service
metadata:
name: nginx
labels:
apps: nginx
spec:
ports:
- port: 80
name: web
clusterIP: None
selector:
apps: nginx
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: web
spec:
selector:
matchLabels:
apps: nginx
serviceName: "nginx"
replicas: 3
template:
metadata:
labels:
apps: nginx
spec:
terminationGracePeriodSeconds: 10
containers:
- name: nginx
image: nginx:1.18.0
ports:
- containerPort: 80
name: web
volumeMounts:
- name: www
mountPath: /usr/share/nginx/html
volumeClaimTemplates:
- metadata:
name: www
spec:
accessModes: ["ReadWriteOne"]
storageClassName: "my-storage-class"
resources:
requests:
storage: 1Gi
Pod 标识
StatefulSets 中的 Pod 具有唯一的标识,该标识由以下部分组成
序号 稳定的网络标识 稳定的存储
该标识始终与 Pod 绑定,无论 Pod 被调度到那个节点
序号
假设一个 StatefulSets 的副本数是 N,其中每一个 Pod 都会被分配到一个序号,序号的范围是从 0 到 N-1,并且该序号在 StatefulSets 内部是唯一的
稳定的网络标识
StatefulSets 中 Pod 的 hostname 格式为 $(StatefulSets name)-$(Pod 序号)
,上面的例子将要创建三个 Pod ,分别是 web-0,web-1,web-2StatefulSets 可以用无头服务来控制其 Pod 所在的域,该域的格式为 $(servicename).$(namespace).svc.cluster.local
,其中 “cluster.local”是集群的域StatefulSets 中的每个 Pod 都会被分配一个 dnsname 格式为: $(podname).$(所在域)
❝你需要自行为 StatefulSets 创建无头服务
❞
下表列出了不同的 集群域、Service name、StatefulSet name 的情况下,对应的 StatefulSet 中 Pod 的 DNS 名字
| 字段名 | 组合一 | 组合二 | 组合三 |
|---|---|---|---|
| Cluster Domain | cluster.local | cluster.local | kube.local |
| Service(ns/name) | default/nginx | foo/nginx | foo/nginx |
| StatefulSets(ns/name) | default/web | foo/web | foo/web |
| StatefulSets Domain | nginx.defalut.svc.cluster.local | nginx.foo.svc.cluster.local | nginx.foo.svc.kube.local |
| Pod DNS | web-{0..N-1}.nginx.defalut.svc.cluster.local | web-{0..N-1}.nginx.foo.svc.cluster.local | web-{0..N-1}.nginx.foo.svc.kube.local |
| Pod Hostname | web-{0..N-1} | web-{0..N-1} | web-{0..N-1} |
稳定的存储
Kubernetes 为每一个 VolumeClaimTemplate 创建一份 PersistentVolume(存储卷)在上面的例子中,每一个 Pod 都将由 StorageClass(存储类)my-storage-class
为其创建一个 1Gib 大小的 PersistentVolume(存储卷)当 Pod 被调度(或重新调度)到一个节点上,其挂载点将挂载该存储卷声明(关联到该 PersistentVolume)
❝❞
当 Pod 或者 StatefulSets 被删除时,其关联的 PersistentVolumeClaim (存储卷声明) 以及其背后的 PersistentVolume (存储卷)仍然存在 如果相同的 Pod 和 StatefulSets 被再次创建,则新建的名为 web-0 的 Pod 仍然挂载到原来名为 web-0 所挂载的存储卷声明及存储卷 这个确保了 Pod 无论被删除重建多少次,都将稳定的使用各自对应的存储内容
Pod name 标签
当 StatefulSets 控制器创建一个 Pod 时,会为 Pod 添加一个标签 (label) statefulset.kubernetes.io/pod-name
且标签的值为 Pod 的名字,你可以利用这个名字,为 StatefulSets 中的某一个特定的 Pod 关联 Service
❝实际操作中,你无需为 StatefulSet 中的一个特定 Pod 关联 Service,因为你可以直接通过该 Pod 的 DNS Name 访问到 Pod
❞
StatefulSets 部署与伸缩
部署和伸缩 StatefulSets 时的执行顺序
在创建一个副本为 N 的 StatefulSets 时,其 Pod 将被按照 {0..N-1}的顺序逐个创建 在删除一个副本为 N 的 StatefulSets 时,其 Pod 将被按照 {N-1..0}的顺序逐个删除 在对 StatefulSets 进行扩容(scale up)时,新增加的 Pod 必须在前面的所有的 Pod 都处于 Running(运行) 和 Ready(就绪)状态,才会创建 终止和删除 StatefulSets 中的某一个 Pod 时,该 Pod 所有后面的 Pod 必须全部已终止
StatefulSets 中 pod.spec.terminationGracePeriodSeconds
不能为 0 ,这个字段的意思是终止 Pod 的宽限时间,如果为 0 将不会优雅的删除 Pod
上面的例子中,nginx 的 StatefulSets 被创建时:
Pod web-0、web-1、web-2 将被按顺序部署 web-0 处于 Running 和 Ready 状态之前,web-1 不会创建;web-1 处于 Running 和 Ready 状态之前,web-2 不会创建 如果 web-1 已处于 Running 和 Ready 的状态,web-2 尚未创建,此时 web-0 发生了故障,则在 web-0 成功重启并达到 Running 和 Ready 的状态之前,web-2 不会创建 如果用户对这个 StatefulSet 执行缩容(scale down)操作,将其副本数调整为 1,则: web-2 将被首先终止;在 web-2 已终止并删除之后,才开始终止 web-1 假设在 web-2 终止并删除之后,web-1 终止之前,此时 web-0 出现故障,则,在 web-0 重新回到 Running 和 Ready 的状态之前,kubernetes 将不会终止 web-1
Pod 管理策略
在 kubernetes 1.7及以后的版本中,可以为 StatefulSets 设定 .spec.podManagementPolicy
字段,使用 StatefulSets 唯一 ID 的特性禁止有序创建和删除 Pod
「OrderedReady」
OrderedReady 是
.spec.podManagementPolicy
字段的默认值,对 Pod 的管理就是上面介绍的有序创建「Parallel」
.spec.podManagementPolicy
字段设置为 Parallel 后,则 StatefulSets Controller 将同时并行的创建和删除 Pod,此时 StatefulSet Controller 将不会逐个创建 Pod,等待 Pod 进入 Running 和 Ready 状态之后再创建下一个 Pod,也不会逐个终止 Pod
❝此选项只会影响伸缩 (scale up / scale down)操作,更新操作不影响
❞
StatefulSets 更新策略
在 kubernetes 1.7 及以后的版本中,可以是 StatefulSets 设定 .spec.updateStrategy
字段,以便你可以在改变 StatefulSets 中的 Pod 的某些字段时 (container/labels/resource request/resource limit/annotation等)禁止滚动更新
On Delete
On Delete 策略实现了 StatefulSets 的遗留版本(kubernetes 1.6及以前的版本)的行为,如果 StatefulSets 的 .spec.updateStrategy.type
字段被设置为 OnDelete,当你修改.spec.template
内容时 StatefulSets Controller 将不会更新其 Pod ,你需要手动删除,此时 StatefulSets Controller 在创建新的 Pod 时,使用修改过的 .spec.template
内容创建
Rolling Update
.spec.updateStrategy.type
字段为 Rolling Update 时,改策略为 StatefulSets 的 Pod 实现的自动滚动更新,在用户更新 StatefulSets 的.spec.template
字段时,StatefulSets Controller 将自动的删除并重建,处理顺序如下:
从序号大的开始,逐步的删除更新每个 Pod,直到序号最小的被更新
当正在更新的 Pod 达到 Runing 和 Ready 时,才继续更新其前序的 Pod
「Partitions」
通过指定
.spec.updateStrategy.rollingUpdate.partition
字段,可以分片执行 RollingUpdate 更新策略,当 StatefulSets 的.spec.template
字段被更改时执行预发布 执行金丝雀更新 执行按阶段更新 序号大于或者等于
.spec.updateStrategy.rollingUpdate.partition
的 Pod 将会被删除重建序号小于
.spec.updateStrategy.rollingUpdate.partition
的 Pod 不会更新,即使手工删除该 Pod kubernetes 也会使用前一个版本的.spec.template
重建该 Pod如果
.spec.updateStrategy.rollingUpdate.partition
大于.spec.replicas
将不会影响到任何的 Pod❝
大部分情况下,不需要使用
❞.spec.updateStrategy.rollingUpdate.partition
,除非碰到下面情况:「Forced Rollback」
当使用 StatefulSets 默认的更新策略(OrderedReady),有可能会进入一种卡住的状态,需要人工修复
如果更新 Pod Template 后,该 Pod 始终不能进入到 Runing 和 Ready 状态(例如:镜像或者配置错误),StatefulSets 将停止滚动更新并一直等待
此时,你仅仅将 Pod Template 回退到一个正常的配置是不够的,由于一个已知的问题,StatefulSets 将继续等待出错的 Pod 进入就绪状态 (该状态永远无法实现) 才尝试将该 Pod 回退到正确的配置
在修复 Pod template 以后,你还必须删除掉所有已经尝试使用有问题的 Pod template 的 Pod,StatefulSet此时才会开始使用修复了的 Pod template 重建 Pod





