云原生应用自动化管理套件、CNCF Sandbox 项目 -- OpenKruise,近期发布了 v1.3 版本。
OpenKruise 是针对 Kubernetes 的增强能力套件,聚焦于云原生应用的部署、升级、运维、稳定性防护等领域。 所有的功能都通过 CRD 等标准方式扩展,可以适用于 1.16 以上版本的任意 Kubernetes 集群。单条 helm 命令即可完成 Kruise 的一键部署,无需更多配置。
版本解析
在版本v1.3中,OpenKruise提供了新的CRD资源 PodProbeMarker
,改善了大规模集群的一些性能问题,Advanced DaemonSet支持镜像预热,
以及 CloneSet、WorkloadSpread、Advanced CronJob、SidecarSet一些新的特性。
1. 新增 CRD 和 Controller:PodProbeMarker
Kubernetes提供了三种默认的Pod生命周期管理:
- Readiness Probe 用来判断业务容器是否已经准备好响应用户请求,如果检查失败,会将该Pod从Service Endpoints中剔除。
- Liveness Probe 用来判断容器的健康状态,如果检查失败,kubelet将会重启该容器。
- Startup Probe 用来判断容器是否启动完成,如果定义了该Probe,那么Readiness Probe与Liveness Probe将会在它成功之后再执行。
所以Kubernetes中提供的Probe能力都已经限定了特定的语义以及相关的行为。除此之外,其实还是存在自定义Probe语义以及相关行为的需求,例如:
- GameServer定义 Idle Probe 用来判断该Pod当前是否存在游戏对局,如果没有,从成本优化的角度,可以将该Pod缩容掉。
- K8S Operator定义 main-secondary Probe 来判断当前Pod的角色(main or secondary),升级的时候,可以优先升级 secondary,进而达到升级过程只有一次选主的行为,降低升级过程中服务抖动时间。
OpenKruise提供了自定义Probe的能力,并将结果返回到Pod Status中,用户可以根据该结果决定后续的行为。
PodProbeMarker配置如下:
apiVersion: apps.kruise.io/v1alpha1
kind: PodProbeMarker
metadata:
name: game-server-probe
namespace: ns
spec:
selector:
matchLabels:
app: game-server
probes:
- name: Idle
containerName: game-server
probe:
exec:
command:
- /home/game/idle.sh
initialDelaySeconds: 10
timeoutSeconds: 3
periodSeconds: 10
successThreshold: 1
failureThreshold: 3
markerPolicy:
- state: Succeeded
labels:
gameserver-idle: 'true'
annotations:
controller.kubernetes.io/pod-deletion-cost: '-10'
- state: Failed
labels:
gameserver-idle: 'false'
annotations:
controller.kubernetes.io/pod-deletion-cost: '10'
podConditionType: game.io/idle
PodProbeMarker结果可以通过Pod对象查看:
apiVersion: v1
kind: Pod
metadata:
labels:
app: game-server
gameserver-idle: 'true'
annotations:
controller.kubernetes.io/pod-deletion-cost: '-10'
name: game-server-58cb9f5688-7sbd8
namespace: ns
spec:
...
status:
conditions:
# podConditionType
- type: game.io/idle
# Probe State 'Succeeded' indicates 'True', and 'Failed' indicates 'False'
status: "True"
lastProbeTime: "2022-09-09T07:13:04Z"
lastTransitionTime: "2022-09-09T07:13:04Z"
# If the probe fails to execute, the message is stderr
message: ""
2. 性能优化:大规模集群性能显著提升
- #1026 引入了延迟入队机制,大幅优化了在大规模应用集群下 kruise-manager 拉起时的 CloneSet 控制器工作队列堆积问题,在理想情况下初始化时间减少了 80% 以上。
- #1027 优化 PodUnavailableBudget 控制器 Event Handler 逻辑,减少无关 Pod 入队数量。
- #1011 通过缓存机制,优化了大规模集群下 Advanced DaemonSet 重复模拟 Pod 调度计算的 CPU、Memory 消耗。
- #1015, #1068 大幅降低了大规模集群下的运行时内存消耗。弥补了 v1.1 版本中 Disable DeepCopy 的一些疏漏点,减少 expressions 类型 label selector 的转换消耗。
3. SidecarSet 支持注入特定的历史版本
SidecarSet 通过 ControllerRevision 记录了关于 containers
、volumes
、initContainers
、imagePullSecrets
和 patchPodMetadata
等字段的历史版本,并允许用户在 Pod 创建时选择特定的历史版本进行注入。
基于这一特性,用户可以规避在 SidecarSet 灰度发布时,因Deployment 等 Workload 扩容、升级等操作带来的 SidecarSet 发布风险。如果不选择注入版本,SidecarSet 将对重建 Pod 默认全都注入最新版本 Sidecar。
SidecarSet 相关 ControllerRevision 资源被放置在了与 Kruise-Manager 相同的命名空间中,用户可以使用 kubectl get controllerrevisions -n kruise-system -l kruise.io/sidecarset-name=your-sidecarset-name
来查看。
此外,用户还可以通过 SidecarSet 的 status.latestRevision
字段看到当前版本对应的 ControllerRevision 名称,以方便自行记录。
通过 ControllerRevision 名称指定注入的 Sidecar 版本
apiVersion: apps.kruise.io/v1alpha1
kind: SidecarSet
metadata:
name: sidecarset
spec:
...
injectionStrategy:
revision:
revisionName: specific-controllerRevision-name
通过自定义版本标识指定注入的 Sidecar 版本
用户可以通过在发版时,同时给 SidecarSet 打上 apps.kruise.io/sidecarset-custom-version=your-version-id
来标记每一个历史版本,SidecarSet 会将这个 label 向下带入到对应的 ControllerRevision 对象,以便用户进行筛选,并且允许用户在选择注入历史版本时,使用该 your-version-id
来进行描述。
假设用户只想灰度 10%
的 Pods 到 version-2
,并且对于新创建的 Pod 希望都注入更加稳定的 version-1
版本来控制灰度风险:
apiVersion: apps.kruise.io/v1alpha1
kind: SidecarSet
metadata:
name: sidecarset
labels:
apps.kruise.io/sidecarset-custom-version: version-2
spec:
...
updateStrategy:
partition: 90%
injectionStrategy:
revision:
customVersion: version-1
4. SidecarSet 支持注入 Pod Annotations
SidecarSet支持注入Pod Annotations,配置如下:
apiVersion: apps.kruise.io/v1alpha1
kind: SidecarSet
spec:
containers:
...
patchPodMetadata:
- annotations:
oom-score: '{"log-agent": 1}'
custom.example.com/sidecar-configuration: '{"command": "/home/admin/bin/start.sh", "log-level": "3"}'
patchPolicy: MergePatchJson
- annotations:
apps.kruise.io/container-launch-priority: Ordered
patchPolicy: Overwrite | Retain
patchPolicy为注入的策略,如下:
- Retain: 默认策略,如果Pod中存在 annotation[key]=value ,则保留Pod原有的value。只有当 Pod中不存在 annotation[key] 时,才注入 annotations[key]=value。
- Overwrite: 与 Retain 对应,当 Pod 中存在 annotation[key]=value,将被强制覆盖为 value2。
- MergePatchJson: 与 Overwrite 对应,annotations value为 json 字符串。如果 Pod 不存在该 annotations[key],则直接注入。如果存在,则进行 json value合并。 例如:Pod中存在 annotations[oom-score]='{"main": 2}',注入后将 value json合并为 annotations[oom-score]='{"log-agent": 1, "main": 2}'。
注意: patchPolicy为Overwrite和MergePatchJson时,SidecarSet原地升级 Sidecar Container时,能够同步更新该 annotations。但是,如果只修改annotations则不能生效,只能搭配Sidecar容器镜像一起原地升级。 patchPolicy为Retain时,SidecarSet原地升级 Sidecar Container时,将不会同步更新该 annotations。
上述配置后,sidecarSet在注入sidecar container时,会注入Pod annotations,如下:
apiVersion: v1
kind: Pod
metadata:
annotations:
apps.kruise.io/container-launch-priority: Ordered
oom-score: '{"log-agent": 1, "main": 2}'
custom.example.com/sidecar-configuration: '{"command": "/home/admin/bin/start.sh", "log-level": "3"}'
name: test-pod
spec:
containers:
...
注意: SidecarSet从安全的考虑不应该注入或修改除 sidecar container 之外的 Pod 字段,所以如果想要使用该能力,首先需要配置 SidecarSet_PatchPodMetadata_WhiteList 白名单 或通过 Feature-gate SidecarSetPatchPodMetadataDefaultsAllowed=true 关闭白名单校验。
5. Advanced DaemonSet 支持镜像预热
如果你在安装或升级 Kruise 的时候启用了 PreDownloadImageForDaemonSetUpdate
feature-gate,
DaemonSet 控制器会自动在所有旧版本 pod 所在 node 节点上预热你正在灰度发布的新版本镜像。 这对于应用发布加速很有帮助。
默认情况下 DaemonSet 每个新镜像预热时的并发度都是 1
,也就是一个个节点拉镜像。
如果需要调整,你可以通过 apps.kruise.io/image-predownload-parallelism
annotation 来设置并发度。
apiVersion: apps.kruise.io/v1alpha1
kind: DaemonSet
metadata:
annotations:
apps.kruise.io/image-predownload-parallelism: "10"
6. CloneSet 扩缩容与 PreparingDelete
默认情况下,CloneSet 将处于 PreparingDelete
状态的 Pod 视为正常,意味着这些 Pod 仍然被计算在 replicas
数量中。
在这种情况下:
- 如果你将
replicas
从N
改为N-1
,当一个要删除的 Pod 还在PreparingDelete
状态中时,你重新将replicas
改为N
,CloneSet 会将这个 Pod 重新置为Normal
状态。 - 如果你将
replicas
从N
改为N-1
的同时在podsToDelete
中设置了一个 Pod,当这个 Pod 还在PreparingDelete
状态中时,你重新将replicas
改为N
,CloneSet 会等到这个 Pod 真正进入 terminating 之后再扩容一个 Pod 出来。 - 如果你在不改变
replicas
的时候指定删除一个 Pod,当这个 Pod 还在PreparingDelete
状态中时,CloneSet 会等到这个 Pod 真正进入 terminating 之后再扩容一个 Pod 出来。
从 Kruise v1.3.0 版本开始,你可以在 CloneSet 中设置一个 apps.kruise.io/cloneset-scaling-exclude-preparing-delete: "true"
标签,它标志着这个 CloneSet 不会将 PreparingDelete
状态的 Pod 计算在 replicas
数量中。
在这种情况下:
- 如果你将
replicas
从N
改为N-1
,当一个要删除的 Pod 还在PreparingDelete
状态中时,你重新将replicas
改为N
,CloneSet 会将这个 Pod 重新置为Normal
状态。 - 如果你将
replicas
从N
改为N-1
的同时在podsToDelete
中设置了一个 Pod,当这个 Pod 还在PreparingDelete
状态中时,你重新将replicas
改为N
,CloneSet 会立即创建一个新 Pod。 - 如果你在不改变
replicas
的时候指定删除一个 Pod,当这个 Pod 还在PreparingDelete
状态中时,CloneSet 会立即创建一个新 Pod。
7. Advanced CronJob Time zones
默认情况下,所有 AdvancedCronJob schedule 调度时,都是基于 kruise-controller-manager 容器本地的时区所计算的。
不过,在 v1.3.0 版本中我们引入了 spec.timeZone
字段,你可以将它设置为任意合法时区的名字。例如,设置 spec.timeZone: "Asia/Shanghai"
则 Kruise 会根据国内的时区计算 schedule 任务触发时间。
Go 标准库中内置了时区数据库,作为在容器的系统环境中没有外置数据库时的 fallback 选择。
8. 其他改动
你可以通过 Github release 页面,来查看更多的改动以及它们的作者与提交记录。
社区参与
非常欢迎你通过 Github/Slack/钉钉/微信 等方式加入我们来参与 OpenKruise 开源社区。 你是否已经有一些希望与我们社区交流的内容呢? 可以在我们的社区双周会上分享你的声音,或通过以下渠道参与讨论:
- 加入社区 Slack channel (English)
- 加入社区钉钉群:搜索群号
23330762
(Chinese) - 加入社区微信群(新):添加用户
openkruise
并让机器人拉你入群 (Chinese)