Rainbond插件体系设计简介

过去几年,利用容器打包和部署代码的方式日益流行,越来越多企业开始测试或是已经在生产环境中运行了微服务架构应用,开始直接面对和解决分布式服务化架构演变中出现的各种问题。
在这样的趋势和大环境下,无服务器PaaS Rainbond围绕着服务的拓展、监控、治理等角度,进行了一系列思考和尝试,插件体系正是其中的重要一环。

Rainbond的插件体系抽象集中在平台的业务层面,理论基础源于Kubernetes的pod机制和一部分容器概念。针对平台业务层面对kubernetes容器编排进行抽象,转变为一个对用户体验友善的Rainbond插件产品的过程,方便用户在不需要懂Kubernetes原理的情况下使用。

设计原则

Rainbond插件体系的设计遵循易于理解和易于使用的原则:

易于理解

在Rainbond插件体系中,插件使用的过程即主容器与init或sidecar等容器结合的过程,原理是将插件容器以sidecar容器(大部分)的形式编排至主应用的pod中,共享主应用容器的网络和环境变量,因此可以插件化实现某些附加功能,例如对主应用进行流量分析等。

Pod

Pod是Kubernetes中模块化容器服务的实例,由一个或多个共享资源的容器组合而成,共享包括文件系统、内核命名空间和IP地址等资源。它是Kubernetes集群中调度的原子单元,通过提供更高层次的抽象,实现灵活的部署和管理模式。

在以下Rainbond(www.rainbond.com)部署pod描述文件片段中,我们可以看到该pod中包含两个containers:394d2f238a603bf01eb5215e23237691(主容器)与22dc8b12aeaf417fa7bd6466c136b9f4(副容器),两者通过pod机制捆绑在一起,共同完成该server提供的服务。
kubectl describe pod -n b314b3e7e44e45a082a0d00e125e88bf b314b3e7e44e45a082a0d00e125e88bf
Containers: 394d2f238a603bf01eb5215e23237691: Container ID: docker://44018fa19a268c1f9ea5b20e9793290cbd89b167bd1fc9017a04ecbd9606d379 Image: goodrain.me/tomcat:latest_gr237691 Image ID: docker-pullable://goodrain.me/tomcat@sha256:701d36cde0b55d07f59a65e525e258523aae46b033297f80b44b0b6c07fc0277 Port: 8080/TCP State: Running Started: Sun, 21 Jan 2018 14:56:35 +0800 Ready: True Restart Count: 0 Limits: cpu: 640m memory: 512Mi Requests: cpu: 120m memory: 512Mi 22dc8b12aeaf417fa7bd6466c136b9f4: Container ID: docker://4c8bd31c2ec2200ee323fb1abdd7b652544ce3d110b1621c36acab4bae434c77 Image: goodrain.me/tcm_20180117175939 Image ID: docker-pullable://goodrain.me/tcm_20180117175939@sha256:d2b20d7eec4da05d953fb7862b9c9ead76797ea5542bff4b93cf2bc98331d279 Port: State: Running Started: Sun, 21 Jan 2018 14:56:36 +0800 Ready: True Restart Count: 0 Limits: memory: 64Mi Requests: memory: 64Mi

init容器

一个pod可以封装多个容器,应用运行在这些容器之中;同时,pod可以有一个或者多个init容器,init容器在应用容器启动之前启动。如果某个pod的init容器启动运行失败,Kubernetes将不断重启pod,直到init容器启动运行成功为止。当然,我们可以设定pod restartPolicy值为Never,阻止它重复启动。

sidecar容器

利用pod中容器可以共享存储和网络的能力,sidecar容器得以扩展并增强“主要”容器,与之共存并使其工作得更好。在上面pod描述文件片段中,22dc8b12aeaf417fa7bd6466c136b9f4就是一个sidecar类型的容器,用来协助分析主容器的一些性能指标。

易于使用

Rainbond插件体系易于使用的原则体现在类应用化、绑定使用、独有的变量作用域等方面。

类应用化

Rainbond插件体系为插件设计了与应用类似的生命周期,包含创建、启用、关闭等模式,与Rainbond平台用户操作应用的习惯保持一致。同时,Rainbond插件体系简化了插件创建类型,支持基于docker image和dockerfile创建,创建插件比创建应用更加简单。 插件创建流程设计如下图所示:

需要注意的是,当一个插件版本固定后,其内存、版本信息、插件变量无法再做修改,这些元素仅作用于当前插件版本。需要修改插件变量等元素时,对插件进行重新构建,重复创建流程即可。

绑定使用 插件的创建和使用过程步骤相对独立,用户可以使用当前租户下创建的插件和其他团队(或租户)分享到云市的插件(初期Rainbond将陆续为用户提供数款插件)。 如果用户没有创建自己的插件,在使用插件前,需要先将他人分享在云市的插件安装至本地。这个过程会将分享出来的插件元数据存储至用户租户下,相当于用户“创建”了这个插件(并没有耗时的构建过程)。 创建完成后,用户可以对插件进行针对性设置,目前可以设置变量和插件生效与否(后续会增加内存设定,满足主应用复杂情况下附加功能对应内存的需求)。内存的限制将在pod创建时进行限制,插件变量生效与实时修改在下文中会继续介绍。

独有的变量作用域

注入到容器内的变量设计为有两类:共用变量与插件变量。

共用变量就是主容器的变量,为使插件参与甚至扩展主应用的功能,在pod创建过程中将主应用的环境变量注入到了插件容器中;插件变量则仅作用在该插件容器内部,防止插件间的变量重复与混用。

Rainbond插件体系的工作过程

Rainbond目前默认为用户提供性能分析和服务治理两款插件,详情访问http://www.rainbond.com/docs/stable/user-app-docs/myapps/myapp-platform-plugin.html 查看。
以下我们以网络代理插件为例,介绍Rainbond插件体系的工作过程。

插件的构建生成

用户填入插件相关信息后,Rainbond将根据这些信息生成插件创建任务,发送至Rainbond消息组件中,由任务发现器处理该任务消息。Rainbond的builder组件接受任务后,将会对插件进行构建,生成插件容器镜像。一个插件容器镜像对应一个构建版本,关联其相应的功能特色。在Rainbond中,插件将以一个构建完成后的镜像来进行流通。类似于应用,插件也可以在Rainbond及云市中进行分享。

插件与应用关联及生效过程

参照插件使用文档,在应用的插件tab中点击安装后,会对插件的当前最新版本与应用标记为关联。此时重启应用,在pod创建时,会对插件进行判断,若存在插件,则进行PluginContainerCreate,pod的container list中将会包含主容器与插件容器。

代理网络

网络代理插件在Rainbond中又名servicemesh, 是一个功能增强容器,在pod中与主容器共享网络。

网络代理插件要完成其功能需要完全代理主容器的网络, 接管主容器的出入口。结构如图:


网络代理分为出口网络模式、入口网络模式两种。

出口网络模式

出口网络模式(示意图中访问tomcat应用为出口网络模式),图中service mesh1 plugin通过discover_service获取tomcat应用的网络信息,包括listen ports,routers,endpoints等。这些信息由discoverservice通过watching kubernetes集群中tomcat应用的services和endpoints资源获取。discover_service API相关请查看相关代码 _https://github.com/goodrain/rainbond/blob/master/pkg/node/api/router/discoverRouter.go
在service mesh1 plugin获取所需的下游应用信息后则开始监听本地对应tomcat的端口,代理当前应用访问tomcat的请求,例如curl http://tomcat。 为何上述请求可以由pod内的容器代理呢?这是由于dns_service将tomcat这类规则域名解析至本地,路由及负载均衡则全权交由service mesh1 plugin进行,即客户端负载均衡的模式。

入口网络模式

入口网络模式较之于出口模式类似(示意图中由外网访问进入main container为入口网络模式),复杂之处在于是对当前应用用户设置端口的转发,由于本地监听所以无法和主容器监听相同的端口。

在处理这种场景时,将service mesh1 plugin的监听端口进行了转化,在开启插件时会随机生成一个不重复的端口port_outer1供给外层监听,service mesh1 plugin继续转发主应用的原端口,在生成k8s的service和pod资源时由新端口替代原端口,并标注对应关系。

在外网负载均衡注册这个应用的外网端口访问时会使用port_outer1来进行注册。分配给用户使用的域名则基于原端口与新端口的映射规则保持不变,用户并无感知

动态配置与资源发现

相关组件discover_service

下图为Rainbond提供的服务治理插件配置:

用户在控制台将应用与插件首次关联(安装)后,插件就会对应当前应用产生配置。经由region端存储至数据中心的etcd中。修改配置相应的设置,进行更新操作,则会修改对应服务的插件资源。
分布式服务化架构面临的问题很多,想要实现服务化,服务治理是一个比较关键的点。在提供治理服务的基础上,配置则需要实现实时生效和联动。因此在rainbond设计中将插件的配置资源放置在了discover_service中,由该发现服务来支持动态配置。

在Kubernetes创建pod时,插件容器的env中注入了一个相关的环境变量DISCOVER_URL,该变量的值为插件可以通过GET请求获取资源的url。后续用户在使用平台创建自己所需的功能插件时,这个变量也是你的插件获取资源所必须的。
相关代码请查看 https://github.com/goodrain/rainbond/blob/master/pkg/worker/appm/pod.go

关于Rainbond

Rainbond是国内首个开源的无服务器PaaS,深度整合基于Kubernetes的容器管理、多类型CI/CD应用构建与交付、多数据中心的资源管理等技术,提供云原生应用全生命周期解决方案,构建应用与基础设施、应用之间及基础设施之间的互联互通生态体系。

点击查看Rainbond项目源码文档,欢迎Watch、STAR、FORK、参与贡献!

K8S中文社区微信公众号

评论 抢沙发

登录后评论

立即登录