增加statefulset的详细文档

pull/41/head
Jimmy Song 2017-08-02 17:52:23 +08:00
parent 835b38d360
commit 7b2c1be9f4
1 changed files with 155 additions and 10 deletions

View File

@ -1,5 +1,7 @@
# StatefulSet
StatefulSet 作为 Controller 为 Pod 提供唯一的标识。它可以保证部署和 scale 的顺序。
StatefulSet是为了解决有状态服务的问题对应Deployments和ReplicaSets是为无状态服务而设计其应用场景包括
- 稳定的持久化存储即Pod重新调度后还是能访问到相同的持久化数据基于PVC来实现
@ -19,7 +21,157 @@ StatefulSet中每个Pod的DNS格式为`statefulSetName-{0..N-1}.serviceName.name
- `0..N-1`为Pod所在的序号从0开始到N-1
- `statefulSetName`为StatefulSet的名字
- `namespace`为服务所在的namespaceHeadless Servic和StatefulSet必须在相同的namespace
- `.cluster.local`为Cluster Domain
- `.cluster.local`为Cluster Domain
## 使用 StatefulSet
StatefulSet 适用于有以下某个或多个需求的应用:
- 稳定,唯一的网络标志。
- 稳定,持久化存储。
- 有序,优雅地部署和 scale。
- 有序,优雅地删除和终止。
- 有序,自动的滚动升级。
在上文中,稳定是 Pod (重新)调度中持久性的代名词。 如果应用程序不需要任何稳定的标识符、有序部署、删除和 scale则应该使用提供一组无状态副本的 controller 来部署应用程序,例如 [Deployment](https://kubernetes.io/docs/concepts/workloads/controllers/deployment) 或 [ReplicaSet](https://kubernetes.io/docs/concepts/workloads/controllers/replicaset) 可能更适合您的无状态需求。
## 限制
- StatefulSet 是 beta 资源Kubernetes 1.5 以前版本不支持。
- 对于所有的 alpha/beta 的资源,您都可以通过在 apiserver 中设置 `--runtime-config` 选项来禁用。
- 给定 Pod 的存储必须由 [PersistentVolume Provisioner](http://releases.k8s.io/%7B%7Bpage.githubbranch%7D%7D/examples/persistent-volume-provisioning/README.md) 根据请求的 `storage class` 进行配置,或由管理员预先配置。
- 删除或 scale StatefulSet 将_不会_删除与 StatefulSet 相关联的 volume。 这样做是为了确保数据安全性,这通常比自动清除所有相关 StatefulSet 资源更有价值。
- StatefulSets 目前要求 [Headless Service](https://kubernetes.io/docs/concepts/services-networking/service/#headless-services) 负责 Pod 的网络身份。 您有责任创建此服务。
## 组件
下面的示例中描述了 StatefulSet 中的组件。
- 一个名为 nginx 的 headless service用于控制网络域。
- 一个名为 web 的 StatefulSet它的 Spec 中指定在有 3 个运行 nginx 容器的 Pod。
- volumeClaimTemplates 使用 PersistentVolume Provisioner 提供的 [PersistentVolumes](https://kubernetes.io/docs/concepts/storage/volumes) 作为稳定存储。
```yaml
apiVersion: v1
kind: Service
metadata:
name: nginx
labels:
app: nginx
spec:
ports:
- port: 80
name: web
clusterIP: None
selector:
app: nginx
---
apiVersion: apps/v1beta1
kind: StatefulSet
metadata:
name: web
spec:
serviceName: "nginx"
replicas: 3
template:
metadata:
labels:
app: nginx
spec:
terminationGracePeriodSeconds: 10
containers:
- name: nginx
image: gcr.io/google_containers/nginx-slim:0.8
ports:
- containerPort: 80
name: web
volumeMounts:
- name: www
mountPath: /usr/share/nginx/html
volumeClaimTemplates:
- metadata:
name: www
annotations:
volume.beta.kubernetes.io/storage-class: anything
spec:
accessModes: [ "ReadWriteOnce" ]
resources:
requests:
storage: 1Gi
```
## Pod 身份
StatefulSet Pod 具有唯一的身份,包括序数,稳定的网络身份和稳定的存储。 身份绑定到 Pod 上,不管它(重新)调度到哪个节点上。
### 序数
对于一个有 N 个副本的 StatefulSet没个副本都会被指定一个整数序数在 [0,N)之间,且唯一。
## 稳定的网络 ID
StatefulSet 中的每个 Pod 从 StatefulSet 的名称和 Pod 的序数派生其主机名。构造的主机名的模式是`$statefulset名称)-$(序数)`。 上面的例子将创建三个名为`web-0web-1web-2`的 Pod。
StatefulSet 可以使用 [Headless Service](https://kubernetes.io/docs/concepts/services-networking/service/#headless-services) 来控制其 Pod 的域。此服务管理的域的格式为:`$(服务名称).$(namespace).svc.cluster.local`,其中 “cluster.local” 是 [集群域](http://releases.k8s.io/%7B%7Bpage.githubbranch%7D%7D/cluster/addons/dns/README.md)。
在创建每个Pod时它将获取一个匹配的 DNS 子域,采用以下形式:`$(pod 名称).$(管理服务域)`,其中管理服务由 StatefulSet 上的 `serviceName` 字段定义。
以下是 Cluster Domain服务名称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} | |
注意 Cluster Domain 将被设置成 `cluster.local` 除非进行了 [其他配置](http://releases.k8s.io/%7B%7Bpage.githubbranch%7D%7D/cluster/addons/dns/README.md)。
### 稳定存储
Kubernetes 为每个 VolumeClaimTemplate 创建一个 [PersistentVolume](https://kubernetes.io/docs/concepts/storage/volumes)。上面的 nginx 的例子中,每个 Pod 将具有一个由 `anything` 存储类创建的 1 GB 存储的 PersistentVolume。当该 Pod (重新)调度到节点上,`volumeMounts` 将挂载与 PersistentVolume Claim 相关联的 PersistentVolume。请注意与 PersistentVolume Claim 相关联的 PersistentVolume 在 产出 Pod 或 StatefulSet 的时候不会被删除。这必须手动完成。
## 部署和 Scale 保证
- 对于有 N 个副本的 StatefulSetPod 将按照 {0..N-1} 的顺序被创建和部署。
- 当 删除 Pod 的时候,将按照逆序来终结,从{N-1..0}
- 对 Pod 执行 scale 操作之前,它所有的前任必须处于 Running 和 Ready 状态。
- 在终止 Pod 前,它所有的继任者必须处于完全关闭状态。
不应该将 StatefulSet 的 `pod.Spec.TerminationGracePeriodSeconds` 设置为 0。这样是不安全的且强烈不建议您这样做。进一步解释请参阅 [强制删除 StatefulSet Pod](https://kubernetes.io/docs/tasks/run-application/force-delete-stateful-set-pod)。
上面的 nginx 示例创建后3 个 Pod 将按照如下顺序创建 web-0web-1web-2。在 web-0 处于 [运行并就绪](https://kubernetes.io/docs/user-guide/pod-states) 状态之前web-1 将不会被部署,同样当 web-1 处于运行并就绪状态之前 web-2也不会被部署。如果在 web-1 运行并就绪后web-2 启动之前, web-0 失败了web-2 将不会启动,直到 web-0 成果重启并处于运行并就绪状态。
如果用户通过修补 StatefulSet 来 scale 部署的示例,以使 `replicas=1`,则 web-2 将首先被终止。 在 web-2 完全关闭和删除之前web-1 不会被终止。 如果 web-0 在 web-2 终止并且完全关闭之后,但是在 web-1 终止之前失败,则 web-1 将不会终止,除非 web-0 正在运行并准备就绪。
### Pod 管理策略
在 Kubernetes 1.7 和之后版本StatefulSet 允许您放开顺序保证,同时通过 `.spec.podManagementPolicy` 字段保证身份的唯一性。
#### OrderedReady Pod 管理
StatefulSet 中默认使用的是 `OrderedReady` pod 管理。它实现了 [如上](https://kubernetes.io/docs/concepts/workloads/controllers/statefulset.md#deployment-and-scaling-guarantees) 所述的行为。
#### 并行 Pod 管理
`Parallel` pod 管理告诉 StatefulSet controller 并行的启动和终止 Pod在启动和终止其他 Pod 之前不会等待 Pod 变成 运行并就绪或完全终止状态。
## 更新策略
在 kubernetes 1.7 和以上版本中StatefulSet 的 `.spec.updateStrategy` 字段允许您配置和禁用 StatefulSet 中的容器、label、resource request/limit、annotation 的滚动更新。
### 删除
`OnDelete` 更新策略实现了遗留1.6和以前)的行为。 当 `spec.updateStrategy` 未指定时,这是默认策略。 当StatefulSet 的 `.spec.updateStrategy.type` 设置为 `OnDelete`StatefulSet 控制器将不会自动更新 `StatefulSet` 中的 Pod。 用户必须手动删除 Pod 以使控制器创建新的 Pod以反映对StatefulSet的 `.spec.template` 进行的修改。
### 滚动更新
`RollingUpdate` 更新策略在 StatefulSet 中实现 Pod 的自动滚动更新。 当StatefulSet的 `.spec.updateStrategy.type` 设置为 `RollingUpdate`StatefulSet 控制器将在 StatefulSet 中删除并重新创建每个 Pod。 它将以与 Pod 终止相同的顺序进行(从最大的序数到最小的序数),每次更新一个 Pod。 在更新其前身之前,它将等待正在更新的 Pod 状态变成正在运行并就绪。
#### 分区
可以通过指定 `.spec.updateStrategy.rollingUpdate.partition` 来对 `RollingUpdate` 更新策略进行分区。如果指定了分区,则当 StatefulSet 的 `.spec.template` 更新时,具有大于或等于分区序数的所有 Pod 将被更新。具有小于分区的序数的所有 Pod 将不会被更新,即使删除它们也将被重新创建。如果 StatefulSet 的 `.spec.updateStrategy.rollingUpdate.partition` 大于其 `.spec.replicas`,则其 `.spec.template` 的更新将不会传播到 Pod。
在大多数情况下,您不需要使用分区,但如果您想要进行分阶段更新,使用金丝雀发布或执行分阶段发布,它们将非常有用。
## 简单示例
@ -318,13 +470,6 @@ kubectl create -f zookeeper.yaml
详细的使用说明见[zookeeper stateful application](https://kubernetes.io/docs/tutorials/stateful-application/zookeeper/)。
## StatefulSet注意事项
## 参考
1. 还在beta状态需要kubernetes v1.5版本以上才支持
2. 所有Pod的Volume必须使用PersistentVolume或者是管理员事先创建好
3. 为了保证数据安全删除StatefulSet时不会删除Volume
4. StatefulSet需要一个Headless Service来定义DNS domain需要在StatefulSet之前创建好
5. 目前StatefulSet还没有feature complete比如更新操作还需要手动patch。
更多可以参考[Kubernetes文档](https://kubernetes.io/docs/concepts/abstractions/controllers/statefulsets/)。
https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/