StatefulSet 是用来管理有状态应用的工作负载 API 对象。
Note:注意: StatefulSets 是在 1.9 版本中正式发布的。
StatefulSet 用来管理 Deployment 和扩展一组 Pod,并且能为这些 Pod 提供*序号和唯一性保证*。
和 DeploymentDeployment 是管理应用副本的 API 对象。 相同的是,StatefulSet 管理了基于相同容器定义的一组 Pod。但和 Deployment 不同的是,StatefulSet 为它们的每个 Pod 维护了一个固定的 ID。这些 Pod 是基于相同的声明来创建的,但是不能相互替换:无论怎么调度,每个 Pod 都有一个永久不变的 ID。
StatefulSet 和其他控制器使用相同的工作模式。你在 StatefulSet 对象 中定义你期望的状态,然后 StatefulSet 的 控制器 就会通过各种更新来达到那种你想要的状态。
StatefulSets 对于需要满足以下一个或多个需求的应用程序很有价值:
在上面,稳定意味着 Pod 调度或重调度的整个过程是有持久性的。如果应用程序不需要任何稳定的标识符或有序的部署、删除或伸缩,则应该使用一组无状态的副本控制器来部署应用程序,比如 Deployment 或者 ReplicaSet 可能更适用于您的无状态需要。
storage class
来提供,或者由管理员预先提供。下面的示例演示了 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
您必须设置 StatefulSet 的 .spec.selector
字段来匹配它的.spec.template.metadata.labels
标签。在 Kubernetes 1.8 版本之前,忽略.spec.selector
字段会提供默认设置。在 1.8 和以后的版本中,指定的 Pod 选择器匹配失败将在创建 StatefulSet 期间导致验证错误。
StatefulSet Pod 具有唯一的标识,该标识包括顺序标识、稳定的网络标识和稳定的存储。该标识和 Pod 是绑定的,不管它被调度在哪个节点上。
对于具有N个副本的 StatefulSet,StatefulSet 中的每个 Pod 将被分配一个整数序号,从 0 到 N-1,该序号在 StatefulSet 上是唯一的。
StatefulSet 中的每个 Pod 根据 StatefulSet 的名称和 Pod 的序号派生出它的主机名。组合主机名的格式为 $(statefulset name)-$(ordinal)
。上例将会创建三个名称为 web-0,web-1,web-2
的三个 Pod。
StatefulSet 可以使用 无头服务 控制它的 Pod 的网络域。管理域的这个服务的格式为:
$(service name).$(namespace).svc.cluster.local
, 其中 “cluster.local” 是集群域。
一旦每个 Pod 创建成功,就会得到一个匹配的 DNS 子域,格式为:$(podname).$(governing service domain)
,其中管理服务由 StatefulSet 的 serviceName
域来定义。
下面给出一些选择集群域、服务名、StatefulSet 名、及其怎样影响 StatefulSet 的 Pod 上的 DNS 名称的示例:
Cluster Domain | Service (ns/name) | StatefulSet (ns/name) | StatefulSet Domain | Pod DNS | Pod Hostname |
---|---|---|---|---|---|
cluster.local | default/nginx | default/web | nginx.default.svc.cluster.local | web-{0..N-1}.nginx.default.svc.cluster.local | web-{0..N-1} |
cluster.local | foo/nginx | foo/web | nginx.foo.svc.cluster.local | web-{0..N-1}.nginx.foo.svc.cluster.local | web-{0..N-1} |
kube.local | foo/nginx | foo/web | nginx.foo.svc.kube.local | web-{0..N-1}.nginx.foo.svc.kube.local | web-{0..N-1} |
Note:注意 集群域会被设置为
cluster.local
除非有其他配置。
Kubernetes 为每个 VolumeClaimTemplate 创建一个 PersistentVolume。在上面的 nginx 示例中,每个 Pod 将会得到基于 StorageClass my-storage-class
提供的 1 Gib 的 PersistentVolume。如果没有声明 StorageClass,就会使用默认的 StorageClass。当一个 Pod 被安排到节点上时,它的 volumeMounts
挂载了与其 PersistentVolumeClaims 相关联的 PersistentVolume。请注意,当 Pod 或者 StatefulSet 被删除时,与PersistentVolumeClaims 相关联的 PersistentVolume 并不会被删除。要删除它必须通过手动方式来完成。
当 StatefulSet 创建 Pod 时,它会添加一个标签 statefulset.kubernetes.io/pod-name
,该标签设置为 Pod 名称。这个标签允许您给 StatefulSet 中的特定 Pod 绑定一个 Service。
StatefulSet 不应该声明 pod.Spec.TerminationGracePeriodSeconds
为 0。这种做法是不安全的,要强烈阻止。更多的解释请参考 强制删除 StatefulSet Pods。
在上面的 nginx 示例被创建后,会按照 web-0、web-1、web-2 的顺序部署三个 Pod。在 web-0 进入Running 和 Ready状态前不会部署 web-1。在 web-1 进入Running 和 Ready 状态前不会部署 web-2。如果 web-1 已经处于 Running 和 Ready 状态,而 web-2 尚未部署,在此期间发生了 web-0 运行失败,那么 web-2 将不会被部署,要等到 web-0 部署完成并进入 Running 和 Ready 状态后,才会部署 web-2。
如果用户想将示例中的 StatefulSet 收缩为 replicas=1
,首先被终止的是 web-2。在 web-2 没有被完全停止和删除前,web-1 不会被终止。当 web-2 已被终止和删除、web-1尚未被终止,如果在此期间发生 web-0 运行失败,那么就不会终止 web-1,必须等到 web-0 进入 Running 和 Ready 状态后才会终止 web-1。
在 Kubernetes 1.7及以后的版本中,StatefulSet 允许您放松其排序保证,同时通过它的 .spec.podManagementPolicy
域保持其唯一性和身份保证。
有序的
Pod 管理是 StatefulSet 的默认功能。它实现了 上面描述的行为。
并行
Pod 管理让 StatefulSet 控制器并行的启动或终止所有的 Pod,启动或者终止其他 Pod 前,无需等待 Pod 进入 Running 和 ready 或者完全停止状态。
在 Kubernetes 1.7 及以后的版本中,StatefulSet 的 .spec.updateStrategy
字段让您可以配置和禁用掉自动滚动更新 Pod 的容器、标签、资源请求/限制、以及注解。
OnDelete
更新策略实现了 1.6 及以前版本的历史遗留行为。当 StatefulSet 的 .spec.updateStrategy.type
设置为 OnDelete
时,它的控制器将不会自动更新 StatefulSet 中的 Pod。用户必须手动删除 Pod 以便让控制器创建新的 Pod,以此来对 StatefulSet 的 .spec.template
的变动作出反应。
RollingUpdate
更新策略对 StatefulSet 中的 Pod 执行自动的滚动更新。在没有声明.spec.updateStrategy
时,RollingUpdate
是默认配置。
当 StatefulSet 的 .spec.updateStrategy.type
被设置为 RollingUpdate
时,StatefulSet 控制器会删除和重建 StatefulSet 中的每个 Pod。
它将按照与 Pod 终止相同的顺序(从最大序号到最小序号)进行,每次更新一个 Pod。它会等到被更新的 Pod 进入 Running 和 Ready状态,然后再更新其前身。
通过声明 .spec.updateStrategy.rollingUpdate.partition
的方式,RollingUpdate
更新策略可以实现分区。如果声明了一个分区,当 StatefulSet 的.spec.template
被更新时,所有序号大于等于该分区序号的 Pod 都会被更新。所有序号小于该分区序号的 Pod 都不会被更新,并且,即使他们被删除也会依据之前的版本进行重建。如果 StatefulSet 的 .spec.updateStrategy.rollingUpdate.partition
大于它的 .spec.replicas
,对它的 .spec.template
的更新将不会传递到它的 Pod。
在大多数情况下,您不需要使用分区,但如果您希望进行阶段更新、执行金丝雀或执行分阶段展开,则这些分区会非常有用。
此页是否对您有帮助?
Thanks for the feedback. If you have a specific, answerable question about how to use Kubernetes, ask it on Stack Overflow. Open an issue in the GitHub repo if you want to report a problem or suggest an improvement.