# StatefulSet
StatefulSet 是用来管理有状态应用的工作负载 API 对象。
StatefulSet 用来管理某 Pod 集合的部署和扩缩, 并为这些 Pod 提供持久存储和持久标识符。
和 Deployment 类似, StatefulSet 管理基于相同容器规约的一组 Pod。但和 Deployment 不同的是, StatefulSet 为它们的每个 Pod 维护了一个有粘性的 ID。这些 Pod 是基于相同的规约来创建的, 但是不能相互替换:无论怎么调度,每个 Pod 都有一个永久不变的 ID。
如果希望使用存储卷为工作负载提供持久存储,可以使用 StatefulSet 作为解决方案的一部分。 尽管 StatefulSet 中的单个 Pod 仍可能出现故障, 但持久的 Pod 标识符使得将现有卷与替换已失败 Pod 的新 Pod 相匹配变得更加容易。
# 一、StatefulSet 场景
StatefulSet 对于需要满足以下一个或多个需求的应用程序很有价值:
- 稳定的、唯一的网络标识符。
- 稳定的、持久的存储。
- 有序的、优雅的部署和缩放。
- 有序的、自动的滚动更新。
# 二、StatefulSet 限制
- 给定 Pod 的存储必须由 PersistentVolume 驱动 (opens new window) 基于所请求的
storage class
来提供,或者由管理员预先提供。 - 删除或者收缩 StatefulSet 并不会删除它关联的存储卷。 这样做是为了保证数据安全,它通常比自动清除 StatefulSet 所有相关的资源更有价值。
- StatefulSet 当前需要 无头服务 (opens new window) 来负责 Pod 的网络标识。你需要负责创建此服务。
- 当删除 StatefulSet 时,StatefulSet 不提供任何终止 Pod 的保证。 为了实现 StatefulSet 中的 Pod 可以有序地且体面地终止,可以在删除之前将 StatefulSet 缩放为 0。
- 在默认 Pod 管理策略时使用滚动更新,可能进入需要人工干预才能修复的损坏状态。
# 三、StatefulSet 模板
apiVersion: v1
kind: Service
metadata:
name: nginx
labels:
app: nginx
spec:
ports:
- port: 80
name: web
clusterIP: None
selector:
app: nginx
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: web
spec:
selector:
matchLabels:
app: nginx # has to match .spec.template.metadata.labels
serviceName: "nginx"
replicas: 3 # by default is 1
template:
metadata:
labels:
app: nginx # has to match .spec.selector.matchLabels
spec:
terminationGracePeriodSeconds: 10
containers:
- name: nginx
image: k8s.gcr.io/nginx-slim:0.8
ports:
- containerPort: 80
name: web
volumeMounts:
- name: www
mountPath: /usr/share/nginx/html
volumeClaimTemplates:
- metadata:
name: www
spec:
accessModes: [ "ReadWriteOnce" ]
storageClassName: "my-storage-class"
resources:
requests:
storage: 1Gi
上述例子中:
- 名为
nginx
的 Headless Service 用来控制网络域名。 - 名为
web
的 StatefulSet 有一个 Spec,它表明将在独立的 3 个 Pod 副本中启动 nginx 容器。 volumeClaimTemplates
将通过 PersistentVolumes 驱动提供的PersistentVolumes
来提供稳定的存储。
StatefulSet 的命名需要遵循 DNS 子域名 (opens new window) 规范。
# 四、StatefulSet 更新
在 Kubernetes 1.7 及以后的版本中,StatefulSet 的 .spec.updateStrategy
字段让 你可以配置和禁用掉自动滚动更新 Pod 的容器、标签、资源请求或限制、以及注解。
# 滚动更新
RollingUpdate
更新策略对 StatefulSet 中的 Pod 执行自动的滚动更新。 在没有声明 .spec.updateStrategy
时,RollingUpdate
是默认配置。 当 StatefulSet 的 .spec.updateStrategy.type
被设置为 RollingUpdate
时, StatefulSet 控制器会删除和重建 StatefulSet 中的每个 Pod。 它将按照与 Pod 终止相同的顺序(从最大序号到最小序号)进行,每次更新一个 Pod。 它会等到被更新的 Pod 进入 Running 和 Ready 状态,然后再更新其前身。
# 五、StatefulSet 删除
OnDelete
更新策略实现了 1.6 及以前版本的历史遗留行为。当 StatefulSet 的 .spec.updateStrategy.type
设置为 OnDelete
时,它的控制器将不会自动更新 StatefulSet 中的 Pod。 用户必须手动删除 Pod 以便让控制器创建新的 Pod,以此来对 StatefulSet 的 .spec.template
的变动作出反应。
# 六、StatefulSet 分区
通过声明 .spec.updateStrategy.rollingUpdate.partition
的方式,RollingUpdate
更新策略可以实现分区。 如果声明了一个分区,当 StatefulSet 的 .spec.template
被更新时, 所有序号大于等于该分区序号的 Pod 都会被更新。 所有序号小于该分区序号的 Pod 都不会被更新,并且,即使他们被删除也会依据之前的版本进行重建。 如果 StatefulSet 的 .spec.updateStrategy.rollingUpdate.partition
大于它的 .spec.replicas
,对它的 .spec.template
的更新将不会传递到它的 Pod。 在大多数情况下,你不需要使用分区,但如果你希望进行阶段更新、执行金丝雀或执行 分阶段上线,则这些分区会非常有用。
#
# 七、StatefulSet 回滚
在默认 Pod 管理策略下使用滚动更新,可能进入需要人工干预才能修复的损坏状态。
如果更新后 Pod 模板配置进入无法运行或就绪的状态(例如,由于错误的二进制文件 或应用程序级配置错误),StatefulSet 将停止回滚并等待。
在这种状态下,仅将 Pod 模板还原为正确的配置是不够的。由于已知问题,StatefulSet 将继续等待损坏状态的 Pod 准备就绪(永远不会发生),然后再尝试将其恢复为正常工作配置。
恢复模板后,还必须删除 StatefulSet 尝试使用错误的配置来运行的 Pod。这样, StatefulSet 才会开始使用被还原的模板来重新创建 Pod。