简介
OpenKruise (官网: https://openkruise.io) 是CNCF(Cloud Native Computing Foundation) 的孵化项目。 它提供一套在 Kubernetes核心控制器 之外的扩展工作负载、应用管理能力。OpenKruise 提供的绝大部分能力都是基于 CRD 扩展来定义,它们不存在于任何外部依赖,可以运行在任意纯净的 Kubernetes 集群中。
核心能力
高级工作负载
通用工作负载能帮助你管理 stateless(无状态)、stateful(有状态)、daemon 类型和作业类的应用。它们不仅支持类似于 Kubernetes 原生 Workloads 的基础功能,还提供了如原地升级、可配置的扩缩容/发布策略、并发操作等。
其中,原地升级是一种升级应用容器镜像甚至环境变量的全新方式。它只会用新的镜像重建 Pod 中的特定容器,整个 Pod 以及其中的其他容器都不会被影响。因此它带来了更快的发布速度,以及避免了对其他 Scheduler、CNI、CSI 等组件的负面影响。
- CloneSet – 无状态应用
- Advanced StatefulSet – 有状态应用
- Advanced DaemonSet – daemon 类型应用
- BroadcastJob – 部署任务到一批特定节点上
- AdvancedCronJob – 周期性地创建 Job 或 BroadcastJob
Sidecar 容器管理
OpenKruise 提供了多种通过旁路管理应用 sidecar 容器、多区域部署的方式。比如通过SidecarSet简化了Sidecar的注入, 并提供了sidecar原地升级的能力。另外, Kruise提供了增强的sidecar启动、退出的控制。
- SidecarSet – 定义和升级你的 sidecar 容器
- Container Launch Priority 控制sidecar启动顺序
- Sidecar Job Terminator 当 Job 类 Pod 主容器退出后,Terminator Sidecar容器
多区域管理
它可以帮助你在一个 Kubernetes 集群中的多个区域上部署应用,比如不同的 node 资源池、可用区、机型架构(x86 & arm)、节点类型(kubelet & virtual kubelet)等。这里我们提供两种不同的方式:
- WorkloadSpread – 旁路地分发 workload 创建的 pods
- UnitedDeployment – 一个新的 workload 来管理多个下属的 workloads
增强运维能力
- 原地重启 pod 中的容器
- 指定的一批节点上拉取镜像
- ResourceDistribution 支持 Secret、Configmaps 资源跨 Namespace 分发
- PersistentPodState 保持Pod的一些状态,比如:"固定IP调度"
- PodProbeMarker 提供自定义Probe探测的能力
应用安全防护
- 保护 Kubernetes 资源及应用 pods 不被级联删除
- PodUnavailableBudget – 覆盖更多的 Voluntary Disruption 场景,提供应用更加强大的防护能力
架构
API
所有 OpenKruise 的功能都是通过 Kubernetes API 来提供,包括很多CRD,资源对象中的特定标识(labels, annotations, envs 等)。
apiVersion: v1
kind: Namespace
metadata:
labels:
# 保护这个 namespace 下的 Pod 不被整个 ns 级联删除
policy.kruise.io/delete-protection: Cascading
Manager
Kruise-manager 是一个运行 controller 和 webhook 中心组件,它通过 Deployment 部署在 kruise-system
命名空间中。Kruise-manager 会创建一些 webhook configurations 来配置哪些资源需要感知处理、以及提供一个 Service kruise-webhook-service
来给 kube-apiserver 调用。
Daemon
这是从 Kruise v0.8.0 版本开始提供的一个新的 daemon 组件。它通过 DaemonSet 部署到每个 Node 节点上,提供镜像预热、容器重启等功能。
安装
使用helm安装的v1.7.2稳定版本。支持很多个feature-gate
参数,详情请见:https://openkruise.io/zh/docs/installation 这里先默认安装。
helm repo add openkruise https://openkruise.github.io/charts/
helm repo update
# https://github.com/openkruise/charts/releases/download/kruise-1.7.2/kruise-1.7.2.tgz
helm install kruise openkruise/kruise --version 1.7.2 --set manager.image.repository=openkruise-registry.cn-shanghai.cr.aliyuncs.com/openkruise/kruise-manager
原地升级
原地升级是 OpenKruise 提供的核心功能之一。目前支持原地升级的 Workload:CloneSet
,Advanced StatefulSet
,Advanced DaemonSet
,SidecarSet
。SidecarSet
的原地升级流程和其他 workloads 不太一样,比如它在升级 Pod 之前并不会把 Pod 设置为 not-ready
状态。因此,下文的内容并不完全适用于 SidecarSet
。
什么是原地升级
通过上图可以看到原地升级和重建升级的区别:
重建升级 要删除旧 Pod、创建新 Pod:
- Pod 名字和 uid 发生变化,因为它们是完全不同的两个 Pod 对象(比如 Deployment 升级)
- Pod 名字可能不变、但 uid 变化,因为它们是不同的 Pod 对象,只是复用了同一个名字(比如 StatefulSet 升级)
- Pod 所在 Node 名字发生变化,因为新 Pod 很大可能性是不会调度到之前所在的 Node 节点的
- Pod IP 发生变化,因为新 Pod 很大可能性是不会被分配到之前的 IP 地址的
原地升级 仍然复用同一个 Pod 对象,只是修改它里面的字段:
- 可以避免如 调度、分配 IP、分配、挂载盘 等额外的操作和代价
- 更快的镜像拉取,因为开源复用已有旧镜像的大部分 layer 层,只需要拉取新镜像变化的一些 layer
- 当一个容器在原地升级时,Pod 中的其他容器不会受到影响,仍然维持运行
InPlaceIfPossible
这种 Kruise workload 的升级类型名为 InPlaceIfPossible
,它意味着 Kruise 会尽量对 Pod 采取原地升级,如果不能则退化到重建升级。
以下的改动会被允许执行原地升级:
- 更新 workload 中的
spec.template.metadata.*
,比如 labels/annotations,Kruise 只会将 metadata 中的改动更新到存量 Pod 上。 - 更新 workload 中的
spec.template.spec.containers[x].image
,Kruise 会原地升级 Pod 中这些容器的镜像,而不会重建整个 Pod。 - 从 Kruise v1.0 版本开始(包括 v1.0 alpha/beta),更新
spec.template.metadata.labels/annotations
并且 container 中有配置 env from 这些改动的 labels/anntations,Kruise 会原地升级这些容器来生效新的 env 值。
否则,其他字段的改动,比如 spec.template.spec.containers[x].env
或 spec.template.spec.containers[x].resources
,都是会回退为重建升级。
工作流程
- 更新pod,检查是否是原地升级。
- 如果是的话先更新pod
status.conditions.status
,把 Pod 设置为not-ready
状态。 - 在pod的annotation中记录更新信息。
- 看是否设置了
gracePeriodSeconds
,如果设置了就等待,没有设置就更新pod信息。 - 如果老的pod存在
preStop
hook脚本则执行该脚本。 - 停止老的容器。
- 拉取镜像,创建并启动新的容器,执行
preStart
hook脚本。 - 检查容器是否更新并运行。
- 在pod status中更新
InPlaceUpdate
conditions。 - 更新pod状态为ready。
- 其中5,6步中,如果是镜像更新则有kubelet执行;如果是从metadata中获取的env值更新则有
kruise-daemon
执行。 - 7,10步是由kubelet执行。
- 其余步骤由
kruise-manager
执行。
多容器升级顺序控制
当你同时原地升级多个具有不同启动顺序的容器时,Kruise 会按照相同的权重顺序来逐个升级这些容器。
- 对于不存在容器启动顺序的 Pod,在多容器原地升级时没有顺序保证。
- 对于存在容器启动顺序的 Pod:
- 如果本次原地升级的多个容器具有不同的启动顺序,会按启动顺序来控制原地升级的先后顺序。
- 如果本地原地升级的多个容器的启动顺序相同,则原地升级时没有顺序保证。
查看pod的 apps.kruise.io/inplace-update-state
这个annotation,只需要关注其中 containerBatchesRecord
来确保容器是被分为多批升级的。如果这个 Pod 在原地升级的过程中卡住了,你可以检查 nextContainerImages/nextContainerRefMetadata
字段,以及 preCheckBeforeNext
中前一次升级的容器是否已经升级成功并 ready 了。
使用要求
如果要使用 env from metadata 原地升级能力,你需要在安装或升级 Kruise chart 的时候打开 kruise-daemon
(默认打开)和 InPlaceUpdateEnvFromMetadata
(默认打开)两个 feature-gate。
virtual-kubelet
类型的 Node 节点,kruise-daemon 可能是无法在上面运行的,因此也无法使用 env from metadata 原地升级。