Advanced StatefulSet
Advanced StatefulSet
控制器基于原生 StatefulSet
上增强了发布能力,比如 maxUnavailable
并行发布、原地升级等。
注意 Advanced StatefulSet
是一个 CRD
,kind
名字也是 StatefulSet
,但是 apiVersion
是 apps.kruise.io/v1alpha1
和 apps.kruise.io/v1beta1
。这个 CRD
的所有默认字段、默认行为与原生 StatefulSet
完全一致,除此之外还提供了一些 optional
字段来扩展增强的策略。
因此,用户从原生 StatefulSet
迁移到 Advanced StatefulSet
,只需要把 apiVersion
修改后提交即可:
- apiVersion: apps/v1
+ apiVersion: apps.kruise.io/v1beta1
kind: StatefulSet
metadata:
name: sample
spec:
#...
注意从 Kruise 0.7.0 开始,Advanced StatefulSet
版本升级到了 v1beta1
,并与 v1alpha1
兼容。对于低于 v0.7.0 版本的 Kruise,只能使用 v1alpha1
。
MaxUnavailable 策略
Advanced StatefulSet
在 RollingUpdateStatefulSetStrategy
中新增了 maxUnavailable
策略来支持并行 Pod
发布,它会保证发布过程中最多有多少个 Pod
处于不可用状态。注意,maxUnavailable
只能配合 podManagementPolicy
为 Parallel
来使用。
这个策略的效果和 Deployment
中的类似,但是可能会导致发布过程中的 order
顺序不能严格保证。如果不配置 maxUnavailable
,它的默认值为 1,也就是和原生 StatefulSet
一样只能 one by one
串行发布 Pod
,即使把 podManagementPolicy
配置为 Parallel
也是这样。
apiVersion: apps.kruise.io/v1beta1
kind: StatefulSet
spec:
# ...
podManagementPolicy: Parallel
updateStrategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 20%
比如说,一个 Advanced StatefulSet
下面有 P0 到 P4 五个 Pod
,并且应用能容忍 3 个副本不可用。当把 StatefulSet
里的 Pod
升级版本的时候,可以通过以下步骤来做:
-
设置
maxUnavailable=3
; -
(可选) 如果需要灰度升级,设置
partition=4
。Partition
默认的意思是order
大于等于这个数值的Pod
才会更新,在这里就只会更新 P4,即使我们设置了maxUnavailable=3
; -
在 P4 升级完成后,把
partition
调整为 0。此时,控制器会同时升级 P1、P2、P3 三个Pod
。注意,如果是原生StatefulSet
,只能串行升级 P3、P2、P1; -
一旦这三个
Pod
中有一个升级完成了,控制器会立即开始升级 P0。
In-Place Pod Update Strategy
Advanced StatefulSet
增加了 podUpdatePolicy
来允许用户指定重建升级还是原地升级。
ReCreate: 控制器会删除旧 Pod 和它的 PVC,然后用新版本重新创建出来
InPlaceIfPossible: 控制器会优先尝试原地升级 Pod,如果不行再采用重建升级。目前,只有修改 spec.template.metadata.* 和 spec.template.spec.containers[x].image 这些字段才可以走原地升级
InPlaceOnly: 控制器只允许采用原地升级。因此,用户只能修改上一条中的限制字段,如果尝试修改其他字段会被 Kruise 拒绝
当一个 Pod
被原地升级时,控制器会先把 Pod status
中修改为 not-ready
状态,然后再更新 Pod spec
中的 image
字段来触发 Kubelet
重建对应的容器。不过这样可能存在的一个风险:有时候 Kubelet
重建容器太快,还没等到其他控制器如 endpoints-controller
感知到 Pod not-ready
,可能会导致流量受损。
因此又在原地升级中提供了 graceful period
选项,作为优雅原地升级的策略。用户如果配置了 gracePeriodSeconds
这个字段,控制器在原地升级的过程中会先把 Pod status
改为 not-ready
,然后等一段时间(gracePeriodSeconds
),最后再去修改 Pod spec
中的镜像版本。这样,就为 endpoints-controller
这些控制器留出了充足的时间来将 Pod
从 endpoints
端点列表中去除。
apiVersion: apps.kruise.io/v1beta1
kind: StatefulSet
spec:
# ...
podManagementPolicy: Parallel
updateStrategy:
type: RollingUpdate
rollingUpdate:
podUpdatePolicy: InPlaceIfPossible
inPlaceUpdateStrategy:
gracePeriodSeconds: 10
更重要的是,如果使用 InPlaceIfPossible
或 InPlaceOnly
策略,必须要增加一个 InPlaceUpdateReady
readinessGate
,用来在原地升级的时候控制器将 Pod
设置为 NotReady
。
一个完整的原地升级 StatefulSet
例子如下:
apiVersion: apps.kruise.io/v1beta1
kind: StatefulSet
metadata:
name: sample
spec:
replicas: 3
serviceName: fake-service
selector:
matchLabels:
app: sample
template:
metadata:
labels:
app: sample
spec:
readinessGates:
# A new condition that ensures the pod remains at NotReady state while the in-place update is happening
- conditionType: InPlaceUpdateReady
containers:
- name: main
image: nginx:alpine
podManagementPolicy: Parallel # allow parallel updates, works together with maxUnavailable
updateStrategy:
type: RollingUpdate
rollingUpdate:
# Do in-place update if possible, currently only image update is supported for in-place update
podUpdatePolicy: InPlaceIfPossible
# Allow parallel updates with max number of unavailable instances equals to 2
maxUnavailable: 2
升级顺序
Advanced StatefulSet
在 spec.updateStrategy.rollingUpdate
下面新增了 unorderedUpdate
结构,提供给不按 order
顺序的升级策略。 如果 unorderedUpdate
不为空,所有 Pod
的发布顺序就不一定会按照 order
顺序了。注意,unorderedUpdate
只能配合 Parallel
podManagementPolicy
使用。
目前,unorderedUpdate
下面只包含 priorityStrategy
一个优先级策略。
- 优先级策略:
这个策略定义了控制器计算 Pod
发布优先级的规则,所有需要更新的 Pod
都会通过这个优先级规则计算后排序。 目前 priority
可以通过 weight
(权重) 和 order
(序号) 两种方式来指定。
weight
: Pod
优先级是由所有 weights
列表中的 term
来计算 match selector
得出。如下:
apiVersion: apps.kruise.io/v1beta1
kind: StatefulSet
spec:
# ...
updateStrategy:
rollingUpdate:
unorderedUpdate:
priorityStrategy:
weightPriority:
- weight: 50
matchSelector:
matchLabels:
test-key: foo
- weight: 30
matchSelector:
matchLabels:
test-key: bar
order
: Pod
优先级是由 orderKey
的 value
决定,这里要求对应的 value
的结尾能解析为 int 值。比如 value “5” 的优先级是 5,value “sts-10” 的优先级是 10。
apiVersion: apps.kruise.io/v1beta1
kind: StatefulSet
spec:
# ...
updateStrategy:
rollingUpdate:
unorderedUpdate:
priorityStrategy:
orderPriority:
- orderedKey: some-label-key
发布暂停
用户可以通过设置 paused
为 true
暂停发布,不过控制器还是会做 replicas
数量管理:
apiVersion: apps.kruise.io/v1beta1
kind: StatefulSet
spec:
# ...
updateStrategy:
rollingUpdate:
paused: true
序号保留(跳过)
从 Advanced StatefulSet
的 v1beta1
版本开始(Kruise >= v0.7.0),支持序号保留功能。
通过在 reserveOrdinals
字段中写入需要保留的序号,Advanced StatefulSet
会自动跳过创建这些序号的 Pod
。如果 Pod
已经存在,则会被删除。 注意,spec.replicas
是期望运行的 Pod
数量,spec.reserveOrdinals
是要跳过的序号。
apiVersion: apps.kruise.io/v1beta1
kind: StatefulSet
spec:
# ...
replicas: 4
reserveOrdinals:
- 1
对于一个 replicas=4, reserveOrdinals=[1]
的 Advanced StatefulSet
,实际运行的 Pod
序号为 [0,2,3,4]
。
如果要把 Pod-3 做迁移并保留序号,则把 3 追加到 reserveOrdinals
列表中。控制器会把 Pod-3 删除并创建 Pod-5(此时运行中 Pod
为 [0,2,4,5]
)。
如果只想删除 Pod-3,则把 3 追加到 reserveOrdinals
列表并同时把 replicas
减一修改为 3。控制器会把 Pod-3 删除(此时运行中 Pod
为 [0,2,4]
)。