细说 kubernetes - 初识 statefulset
最近遇到一个问题:statefulset 部署能否只是升级部分的 pod?问题本身不难,但我发现没有说过有关 statefulset
的介绍,于是本文将介绍一些有关 statefulset 的点。
问题的答案则放在文章的最后,这也是 statefulset
一个很有用的特性。
statefulset 特点
首先让我们来简单说下 statefulset 的一些基本特点
特点
statefulset 顾名思义是有状态的,它与 deployment 最大的不同就是这个。
- 稳定的、唯一的网络标识符。
- 稳定的、持久的存储。
- 有序的、优雅的部署和扩缩。
- 有序的、自动的滚动更新。
由于特点是为了满足很多有状态的服务或者中间件:如 Zookeeper、Kafka 等,他们一般有一些数据是不希望随着服务的重启而消失的,所以就需要 statefulset 了。
顺序&唯一
在 statefulset 中每个 pod 会有一个唯一标识符,故这些 pod 之间是不一样的,也就是唯一的,所以 pod 在重启或者是调度后是没有办法互相替换的。
1 | ❯ kubectl get pods |
我们可以看到每个 pod 的名称后面还跟了一个递增的数字用于区分
- 创建的时候顺序是 0,1,2…. 5
- 终止的时候顺序是 5….2,1,0
- 并且前一个没有 running&ready 后一个是不会被创建的
数据持久化
由于 statefulset 的特性,我们往往需要持久化数据,也就是需要对应的 PV 和 PVC,当然与之更好的配合是 StorageClass,因为我们往往需要动态为每个 pod 去申请对应的资源,这部分详细可以参考:k8s StorageClass使用攻略
由于 statefulset 中每个 pod 都是唯一的,所以他们对应的持久化的 PV 和 PVC 也是一一对应的,pod-1 不会也不能用到 pod-2 所对应的 PV。
滚动更新
什么是滚动更新
当我们重启一个 deployment 的时候,或者是修改了 deployment 的时候,pod 会几个几个进行更新,它默认确保 75% 的处于可用状态。
而 statefulset 不一样,它一定是一个一个更新的,按照顺序(从最大序号到最小序号)进行,每次更新一个 Pod。
如何实现
其实实现方式和 deployment 一样,都是通过控制器模式来实现的,并且 k8s 中都运用到了状态维护的设计思想,也就是:描述我需要的状态,如果当前状态不是我需要的,则进行改变,直到成为我描述的状态。
1 | for { |
步骤
- 获取所有 pod 副本
- 进行分组,不需要的 pod 进入
condemned
- 需要的 pod 进入
replicas
- 根据规则顺序的序列好检查副本状态
- 按照降序删除
condemned
- 按照降序更新
replicas
具体代码在 updateStatefulSet
方法中:
https://github.com/kubernetes/kubernetes/blob/9f82d81e55cafdedab619ea25cabf5d42736dacf/pkg/controller/statefulset/stateful_set_control.go
能否只是升级部分的 pod?
我们经常会遇到需要蓝绿发布的场景,也就是说,我们只想升级一个应用中部分的 pod,保持新老版本共存,来验证一些业务或者升级所带来的影响,如果遇到问题可以快速相应。那么在 statefulset 中,实现起来很简单。
在 statefulset 的配置中有个 partition
1 | spec: |
你可以通过配置这个参数来实现升级部分的 pod
- 序号 >= partition 的 pod 会更新
- 序号 < partition 的 pod 不会被更新
然后当你验证业务通过后,可以跳转这个参数为 0,就可以将剩余的 pod 也更新完成了