Module Controller V2 设计 —— 低成本地让开源用户接入模块运维体系。 #8
CodeNoobKing
started this conversation in
Ideas
Replies: 2 comments
-
|
还需要考虑下
|
Beta Was this translation helpful? Give feedback.
0 replies
-
|
这个地方可以支持下 containers:
- name: ${MODULE_NAME}
image: ${MODULE_URL}
env:
- name: MODULE_VERSION
value: ${MODULE_VERSION}
resource:
requests:
cpu: 800m
mem: 1GI |
Beta Was this translation helpful? Give feedback.
0 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
架构设计
整体思路
整体思想是用 Mock 的方式复用 K8S 现有的的运维调度能力,保证稳定性,避免重复造轮子。
如何触发调度?
把基座 Pod mock 成一个 K8S 的 Node 节点,不妨称其为 VNode,把模块 mock 成 K8S 的一个 Pod,不妨称其为 VPod。当我们向 K
ube Apiserver 提交这两 mock 时,Kube Scheduler 会触发一轮调度,并且给 VPod 分配上一个合适的 VNode。我们可以通过给 VPod 加上对应的 tolerations 和 VNode 加上对应的 taints 来保证只有 VPod 会被调度到 VNode 上,以及 VPod 只会被调度到 VNode 上。
如何触发运维?
用户可以使用正常的 Deployment 或者是其他开源社区自定义的运维 Operator,只要保证其 Pod Template 的定义符合我们的 VPod 的定义规范即可。
如何执行模块安装?
可以使用社区的 Virtual Kubelet 框架,Virtual Kubelet 定义了一套 kubelet 的交互生命周期,预留了一些具体的接口点,如 CreatePod 等。开发者通过实现这些预留的接口,便可接入 K8S 的正常的调度周期。
架构图
通过架构图我们不难发现,仅仅通过 Virtual Kubelet 这一个简单的组件,我们就可以直接利用 K8S 实现三层调度。值得注意的事情是,VNode 对应的 Pod 元数据信息会存储在一个 Kube ApiServer 中,我们不妨称其为 ApiServerA。而 VPod 也会存储在一个 ApiServer 中,我们不妨称其为 ApiServerB。ApiServerA 不一定必须等于 ApiServerB,可以是彼此独立的。特别是在一些云托管的 K8s 场景下,由于云厂商对 ApiServer 的权限限制,用户可能必须独立部署一套 ApiServer。
举个模块发布上线的例子
安装 virtual-kubelet,映射出 virtual Node,virtual kubelet 将保持基座与 vNode 的状态同步

安装模块,创建模块的 Deployment(与原生k8s deployment 相同),此时k8s controller manager 会创建出模块的 pod(刚创建时还未调度到节点上,状态为 Pending)
Virtual Kubelet 发现 vNode 上有 vPod 调度上来,发起模块安装指令到基座上

安装成功后,保持模块与 vPod、pod 与 vNode 间的状态同步
完整的运维过程需要如下能力:
详细设计
VPod 定义规范
在 Koupleless 体系中,模块(模块组)是一个重要的抽象,其包含如下核心属性:
由于在 ModuleController V2 设计方案中,我们常使用 VPod(底层为 K8S 的 Pod)承载模块模型或模块组,因此,我们需要预先定义清楚相关模块配置到 Pod 属性的映射关系,本小结将探讨有关映射关系。
我们从元数据的映射开始讨论,其中,模块的元数据映射到 V1Pod 的 containers 字段下,由于 1 个 Pod 可以有 N 个 Containers,所以 V1Pod 模型天然地支持模块组的描述:
相应的,模块的安装情况也可以塞在对应的 containerStatus 中,映射关系如下:
除此之外,为了方便的能通过 kubectl 通过简单的表达是把有关的 pod 筛选出来,我们还应该在 labels 里加上 module.koupleless.io/${moduleName}:${version} 标签。
模块或模块组的运行期整体状态的映射关系如下:
上述介绍了模块的属性的配置,除此之外,为了和 k8s 的调度和生命周期体系融合,我们还需要配置一些高阶的运行期配置。
我们从调度开始介绍,为了保证 VPod 只会被调度到 VNode 上,我们需要添加对应的 Affinity 配置,如下所示:
除此之外,为了保证 VNode 只会被调度 VPod,所以 VNode 会有一些特殊的 Taints 标签,相应的,Pod 也必须添加上对应的 Tolerations,如下:
通过上述的 Affinity 和 Tolerations,我们可以保证 VPod 只会被调度到 VNode 上。
当然,我们还必须考虑这套模式和 k8s 原生流量的兼容性问题,我们可以通过 k8s 的 readinessGate 机制达到目的,添加如下配置:
通过这些关键的规范,我们不仅能用 k8s 的 pod 模型描述模块或模块组,还能和 k8s 的调度和流量体系结合起来。
一个完整的,可能的,描述了 2 个模块的样例 yaml 如下:
VNode 规范设计
第一小节我们完成了 VPod 的规范设计。接下来我们需要探讨 VNode 的细则设计。
首先,VNode 必须有特殊的 Taints,保证正常的 Pod 不可能被调度到对应的 VNode 上,对应配置如下:
除此之外,我们还必须保证 VPod 只会被调度到 VNode 上。为此,Node 必须提供对应 labels,保证 Pod 能够配置相应的亲和性调度,对应配置如下:
除此之外,node 还需要上报一些资源属性,如 capacity:
以及需要定期更新 allocatable 字段:
为了方便排障,即通过 vnode 直接找到对应的 pod,vnode 的命名规范如下:virtual-node-{stack}-{namspace}-{podname}
最后,VNode 的 ip 直接使用对应 pod 暴露的 ip。
一个可能的样例 VNode 如下:
自愈体系设计
VNode 需要自愈能力,原因如下。在 JVM 体系中,模块的反复安装会导致 metaspace 的使用率逐渐上涨。最终,metaspace 的使用率会达到某个阈值,过了这个阈值后模块再也无法被安装,会触发 OOM。由此,VNode 需要有一定的自愈能力,去应对这个情况。由于 Java 目前无法有效地通过 API 去完全清理干净 metaspace 中的类,因此我们将选择更简单的做法,对基座 pod 做替换,整体流程如下:
如此,便可以保证 Node 的可用性。
ROADMAP
Beta Was this translation helpful? Give feedback.
All reactions