StatefulSet
Deployment、DaemonSet都是面向无状态的服务,它们管理Pod的IP、名字、启停顺序等都是随机的。如果要部署一个Redis、MySQL、MongoDB集群就不太合适了,Pod会飘来飘去、数据也会错乱,这个时候继续用用到StatefulSet了,顾名思义,StatefulSet是指有状态的集合,它是针对有状态的应用设计的。
StatefulSet 的特点:
- 稳定的网络标识
- 稳定的持久存储
- 有序的部署与扩展
- 有序的自动滚动更新
一个典型的 StatefulSet 应用一般包含三个组件:
- headless service(无头 service)
- StatefulSet(控制器)
- volumeClaimTemplate(存储卷申请模板)
与Deployment的差别
在 Kubernetes 里,Deployment 是使用 Service 来做负载均衡和流量分发的,CoreDNS 将 Service name 解析成Cluster IP,Cluster IP 通过负载均衡把流量分布到各个POD上面,这样就可以对外暴露统一的 endpoint。
而 StatefulSet 需要使用 Headless Service 的服务,也被称为”无头服务”,Headless Service 没有统一的 endpoint, 它后面的每个 Pod 都会被分配一个稳定的域名,Pod 之间也可以互相访问。
你可以这么理解:Deployment 对应的是 Service, 而与 StatefulSet 对应的就是 Headless Service。
创建 Headless Service
在 Service 声明中通过指定 Cluster IP(spec.clusterIP)的值为 “None” 就可创建 Headless Service:
1
2
spec:
clusterIP: None
Kubernetes 对 Handless Service 并不会分配 Cluster IP,kube-proxy 不会处理它们, 也不会对它们进行负载均衡和路由。对于 Service 进行 dns 查询时只会返回Service的Cluster IP。而对于 Handless Service, dns查询会返回每一个后端的Pod地址, FQDN 为:
1
<pod-name>.<service-name>.<namespace-name>.svc.cluster.local
StatefulSet还会为关联的Pod保持名称不变, 并且是有序的命名, 这样它就具有了稳定的网络标识, 如果 StatefulSet 的 name 是 web, 那么Pod的名称就是这样的:
1
2
3
4
web-0
web-1
web-2
...
部署与扩缩
部署 StatefulSet 的时候, Pod 也是有序启动的。而且在节点的分配上 Pod 也总是被调度到一开始调度到的节点上,除非你去手动指定它。
- 有序部署:对于包含 N 个 副本的 StatefulSet,当部署 Pod 时,它们是依次创建的,顺序为 0到N-1。在下一个Pod运行之前,所有之前的Pod必须都是Running和Ready状态。
- 有序删除:当删除 Pod 时,它们是逆序终止的,顺序为 N-1到0。
- 有序缩放:在将缩放操作应用到 Pod 之前,与部署一样,它前面的所有 Pod 必须是 Running 和 Ready 状态。
Kubernetes 1.7 版本以后,可以通过参数.spec.podManagementPolicy 调整Pod启动顺序:
- OrderedReady 默认值,有序模式
- Parallel 并行模式,某些Pod启动或终止的同时,其它Pod也可以并行操作。在启动或终止另一个 Pod 前,不必等待这些 Pod 变成 Running 和 Ready 或者完全终止状态。
持久化存储
我们使用 StatefulSet 就是需要持久化存储的,不随着 Pod 的删除而删除。 VolumeClaim 和 Volume 是 Kubernetes 用来做数据持久化的对象,Volume 通过 CSI 抽象接口对接真实的存储(如宿主机磁盘、公有云存储、网络存储、分布式存储等)。VolumeClaimTemplates 是 VolumeClaim 的模版。
StatefulSet一般会搭配共享存储使用,这样也会带来性能问题。
注意事项
在 StatefulSet 的正常操作中,永远不需要强制删除 StatefulSet 管理的 Pod。StatefulSet 不应将 pod.Spec.TerminationGracePeriodSeconds 设置为 0。 这种做法是不安全的,要强烈阻止。
如果你的Pod通常需要超过30秒才能关闭,请确保增加优雅终止宽限期。您可以通过在Pod YAML中设置 terminationGracePeriodSeconds 选项来实现。