共计 4756 个字符,预计需要花费 12 分钟才能阅读完成。
一、背景
现有的 ServiceMesh 框架有很多,如 Istio、linkerd 等。对于用户而言,在测试环境下,须要达到的成果是快、开箱即用。但在生产环境下,可能又有熔断、延时注入等需要。那么繁多的 ServiceMesh 框架无奈同时满足用户不同的需要。
在之前的 Rainbond 版本中,Rainbond 反对了多种不同的利用治理模式,作为利用级的插件,实现了 Istio 治理模式的切换。
本文将对 Rainbond 实现 Istio 治理模式进行原理解析。
二、基本原理
动静准入管制
首先咱们须要理解一个常识,Istio 是如何实现主动注入的。实际上,Istio、linkerd 等不同的 ServiceMesh 框架都应用到了 Kubernetes 中的一个十分重要的性能,叫作 Dynamic Admission Control,也叫作:Initializer。
这个性能会在 API 对象创立之后会被立即调用到。在 API 对象被正式解决前,实现一些初始化的筹备工作。所以在部署了 Istio 管制立体当前,当你提交了 API 对象的 Yaml 文件,会被 Istio 的准入控制器捕捉,实现一些 PATCH 操作,比方加上对应的 Sidecar 容器字段。最终将这个 PATCH 过后的 API 对象交给 Kubernetes 解决。接下来就具体介绍下 ServiceMesh 框架的注入机制。
如何主动注入
用户须要先在集群中部署 Istio 的管制立体。它会蕴含一个用来为 Pod 主动注入 Envoy 容器的 Initializer。
首先,Istio 会将 Envoy 容器自身的定义,以 ConfigMap 的形式保留在 Kubernetes 当中。当 Initializer 的控制器,通过 Admission-Webhooks 监听到合乎规定【此处指对应的 Annoations】的 API 对象被创立后,读取对应的 ConfigMap 获取到 Envoy 容器的配置。并将相干的字段,主动增加到用户提交的 Pod 的 API 对象里。详见下图和阐明。
上图为提交 yaml 文件到 Kubernetes 集群后,集群所做的解决,大略分为以下几步:
- Yaml 文件提交到 APIServer,APIServer 会过滤这个申请,并实现一些前置性的工作,比方受权、超时解决、审计等。
- APIServer 会找到该 Pod 对应的类型定义,如果存在,则会将这个 Pod 转换为对象。
- 接下来进行 Admission 操作,Admission 操作是在创立之后会被立即调用到的一组代码,它能够实现一些初始化操作,比方在对象创立前加上某些 Labels,然而因为它自身是被编译到 APIServer 中的,所以用户批改后,须要从新编译并重启 APIServer。侥幸的是:Kubernetes 提供了一种“热插拔”式的 Admission 机制,即 Initializer。
- 目前 istio、linkerd 等我的项目均实现了 Initializer 机制,也就是说,当提交的 Yaml 文件蕴含其指定的 Annoations 字段时,那么它们部署的准入控制器则会捕捉到对应的 API 对象,在这个阶段为 Pod 进行初始化操作,即增加上 Sidecar 容器的相干配置。
- 接下来会进行 Validation,验证 API 对象的字段是否非法。
- 验证结束后,会将对应的信息保留到 etcd 中,一次 API 对象的创立就此实现。
三、扩大利用治理模式
在理解了现有的 ServiceMesh 框架的注入机制后,咱们就能够基于此开发 Rainbond 的利用级插件,用于扩大利用的治理能力。咱们晓得因为现有的 ServiceMesh 框架大多采纳了规范的 Initializer 实现。所以咱们只须要实现以下两步即可。
- 部署对应 ServiceMesh 框架的 Initializer 控制器,通常状况下意味着部署它们的管制立体,此处基于 Rainbond 已有的对接 helm 商店的性能,能够不便的进行部署。
- 实现基于利用的数据立体的注入。
Istio 治理模式的开发
接下来以 Istio 治理模式的开发为例,具体介绍如何自行扩大利用的治理能力。
前端展现反对 Istio 利用治理模式:
Rainbond 次要分为两层,即业务层和数据中心层,具体可参考 Rainbond 技术架构。
rainbond-ui 为业务层的前端我的项目,首先须要反对 Istio 治理模式,因为 Rainbond 是以利用为核心的利用治理平台,所以 Istio 治理模式也是针对利用来说的。
如下图所示:在利用页面,能够切换治理模式。咱们须要在这里减少 Istio 治理模式。
治理模式有效性校验
Initializer 的机制决定了,须要有一个准入控制器,去解决符合条件的 API 对象。通常状况下准入控制器蕴含在对应 ServiceMesh 框架的管制立体中。
所以咱们在切换治理模式时,须要去校验集群中是否曾经部署过对应 ServiceMesh 框架的管制立体,这一步应该在切换时进行校验。如果未部署对应的管制立体,则不具备对应的治理能力。也就不能切换。
依据 Rainbond 技术架构,咱们能够晓得,rainbond-console 属于业务层的后端。它须要与数据中心端进行通信,能力获取集群的状态。因而在 rainbond-console 和 rainbond 这两个我的项目中,都须要对治理模式的有效性进行校验。
rainbond-console 对治理模式有效性的校验
参考如下代码,类 GovernanceModeEnum
定义了反对的治理模式。首先咱们须要在治理模式这里减少 ISTIO_SERVICE_MESH
,用于在业务层判断治理模式是否无效。当此处校验通过后,咱们须要申请数据中心端的接口,检测此种治理模式是否已装置了对应的管制立体。
/console/enum/app.py
class GovernanceModeEnum(AutoNumber):
BUILD_IN_SERVICE_MESH = ()
KUBERNETES_NATIVE_SERVICE = ()
ISTIO_SERVICE_MESH = ()
@classmethod
def choices(cls):
return [(key.value, key.name) for key in cls]
@classmethod
def names(cls):
return [key.name for key in cls]
rainbond 对治理模式有效性的校验
在接管到来自业务端的校验申请时,咱们须要检测在该集群是否已部署了对应的 ServiceMesh 框架的管制立体。参考如下代码,因为部署 Istio 管制立体后,在每个命名空间下都能够查看到 istio-ca-root-cert
这个 ConfigMap,所以咱们这里应用该 ConfigMap 作为判断 Istio 管制立体部署的根据。
当确认 Istio 管制立体已装置后,咱们返回给业务端后果。最终实现切换。
/api/handler/app_governance_mode/adaptor/istio.go
func (i *istioServiceMeshMode) IsInstalledControlPlane() bool {ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
cmName := os.Getenv("ISTIO_CM")
if cmName == "" {cmName = "istio-ca-root-cert"}
_, err := i.kubeClient.CoreV1().ConfigMaps("default").Get(ctx, cmName, metav1.GetOptions{})
if err != nil {return false}
return true
}
实现基于利用的数据立体的注入
仅仅实现治理模式的切换还不够,咱们须要让 Istio 的管制立体为指定的利用注入 Sidecar,即数据立体。Rainbond 本身通过 Worker 组件将 Rainbond-Application Model 进行实例化转化为 Kubernetes 资源模型。管制利用的生命周期。
因而,咱们须要在 Worker 组件转化资源时,主动为用户实现对利用的注入。参考 Istio 注入策略。咱们能够发现 Istio 依赖于 Label "sidecar.istio.io/inject": "true"
实现注入。而在 Rainbond 的代码中,咱们能够看到如下代码。这是将 Rainbond 的利用模型转化为 Deployment 的局部代码。在这里,咱们为 Deployment 增加了对应的 injectLabels。
有了这些初始化操作。当 API 对象被创立进去时,便会被 Istio 的准入控制器解决,实现数据立体的注入。
/worker/appm/conversion/service.go
func initBaseDeployment(as *v1.AppService, service *dbmodel.TenantServices) {
as.ServiceType = v1.TypeDeployment
... ...
injectLabels := getInjectLabels(as)
deployment.Labels = as.GetCommonLabels(
deployment.Labels,
map[string]string{
"name": service.ServiceAlias,
"version": service.DeployVersion,
},
injectLabels)
... ...
as.SetDeployment(deployment)
}
func getInjectLabels(as *v1.AppService) map[string]string {mode, err := governance_mode.NewAppGoveranceModeHandler(as.GovernanceMode, nil)
if err != nil {logrus.Warningf("getInjectLabels failed: %v", err)
return nil
}
injectLabels := mode.GetInjectLabels()
return injectLabels
}
对于不同的利用治理模式,咱们能够参考 利用治理模式扩大 的代码。实现如下接口,便能够实现利用下治理模式的切换和注入。
其中 IsInstalledControlPlane
这个接口的实现在后面曾经体现。它次要用于判断管制立体是否已实现装置,能够失常应用。而 GetInjectLabels
则次要用于 Worker 组件转化利用模型为 Kubernetes 资源时,增加上指定的 Labels,以便被部署的准入控制器解决。
/api/handler/app_governance_mode/adaptor/app_governance_mode.go
type AppGoveranceModeHandler interface {IsInstalledControlPlane() bool
GetInjectLabels() map[string]string
}
四、总结
本文咱们次要介绍了利用治理模式的注入机制和开发,用户能够通过查阅须要注入的 ServiceMesh 插件官网文档,通过以上两步实现利用下治理模式的切换。使利用取得不同的治理能力。
Reference Link
- Dynamic Admission Control
- Rainbond-UI 实现 Istio Commit
- Rainbond-Console 实现 Istio Commit
-
Rainbond 实现 Istio Commit:
- Istio.go
- service.go
- app_governance_mode.go
- Rainbond 技术架构
- Istio 注入策略