藏书馆App基于 Rainbond 实现云原生DevOps的实践
info
我们需要的不是精通 Kubernetes 的工程师,我们需要一款小白都能用好的管理工具。 -- 郭传壕
大家好,我是厦门正观易知科技有限公司运维负责人郭传壕。
藏书馆是一个专注用户自我成长的云端私人图书馆,集电子书的读、荐、借、购、存和知识管理功能于一体,致力于用户的认知赋能,通过读书习惯的养成,达成自我成长。目前累计注册用户已达 1500W ,平台图书资源超过 200W 册。
我们使用 Rainbond 已经有 2 年,我把我们的使用经验分享给大家。
以前的困局
处于云原生时代中的藏书馆的起点很高,我们一开始就选定了微服务架构、Kubernetes、容器化等符合时代潮流的技术体系。然而原生的 kubernetes 管理平台提供的功能并不完全符合我们的预期,二次开发的巨大技术成本也是我们负担不起的。
在了解到 Rainbond 之前,处于创业初期的我们一直受困于产品迭代变更频繁所带来的琐事之中。我所说的琐事包含微服务架构下 50 个服务的版本管理、构建产物的更替、线上环境的发布以及围绕着应用从开发到上线再到运维的种种繁琐工作。
我们希望可以从这些琐事中跳脱出来,专注于业务本身,探索出一条适合 kubernetes 环境下持续开发、持续交付的简捷之路。
鉴于此,我们开始积极的寻找一款开源且易用的应用管理平台。
初识 Rainbond
在 Rainbond 之前,我们已经尝试过了 Rancher 等产品,但产品功能和我们的预期有很大差距。
2 年前,我们通过 Github 第一次了解到了 Rainbond 这款产品,惊喜于功能非常契合藏书馆的需求。列举几个令人印象深刻的能力:
应用架构的整体拓扑图
以上帝视角,一览无余的观测到所有服务组件的运行状态与依赖关系。强迫症会逼着我们的工程师消灭红色的异常状态,而体现运行状态的绿色真的令人感到安心。
可视化的资源占用情况
资源占用情况是体现可观测性很重要的指标。对于初创公司而言,了解资源分配是否合理,杜绝资源浪费是很重要的。Rainbond 从团队到服务组件的每个维度都提供了良好的可观测性。团队级别的资源限额能力非常实用,解决了运维团队无法有效掌控资源分配的难题。
自动伸缩
藏书馆是一个典型的 2C 场景,如何利用好云计算提供的弹性,灵活的应对流量高峰呢?答案就是使用自动伸缩功能。Rainbond 提供的自动伸缩功能,突出了简单易配置的特点。自动伸缩能力极大的解放了运维团队的工作压力,从此远离兴师动众和严阵以待。关键业务会随着我们的心意,自动扩张,直到能够吞吐所有流量。
集中式的网关策略管理
2C 场景下的服务发布,是无论如何也绕不过去的坎儿。无论是蓝绿发布、灰度发布抑或是 A/B 测试,这服务发布相关的十八般武艺多少都会碰到。原生的 Kubernetes Ingress 的确可以实现这些发布策略,但是我们更希望得到一个产品化的集中式管理页面来处理这些问题,而不是去麻烦运维工程师们去碰那些格式严苛的 Yaml 文件。Rainbond 网关策略管理完美的实现了我们的需求。
应用复制快速生成环境
在藏书馆的开发流程中,我们时常需要搭建各种环境,来区分开发、测试、预发布场景,分别对应不同版本的微服务组件,比如 Dev、Prod 之类的。但如果每次生成环境都要手动创建服务组件,那真的太低效了。应用复制功能在这个场景下非常有用,它帮助我快速复制出一套环境出来。复制过程中自助选择构建源的版本,对我而言是镜像的 Tag。复制后的新环境,保留了所有的服务组件元信息以及依赖关系。
在逐步的探索过程中,和官方团队在社区中进行的互动,让我们少走了很多弯路。一款开源产品如果伴随着有生命力的社区,将会是非常令人安心的。
开发测试环境部署
第一步,部署微服务
上手 Rainbond ,是从部署单个微服务开始的,这个过程非常简单,不需要学习 Kubernetes 的 Yaml 。开发环境中的组件是基于镜像构建完成的,只需要按界面的引导填写好镜像地址及相关信息就可以了。
我们用的是 Spring Cloud 微服务框架,在 Rainbond 体系下可以很好的运行,我在部署过程中受到了一系列文档的影响,这里分享给大家:
第二步,通过可视化的方式服务编排
在编排微服务的过程中,基于图形化编辑组件依赖关系这个功能,着实惊艳了我。这种编排方式和其他平台基于复杂 Yaml 文件进行编排的方式有极大的不同。感兴趣的小伙伴们可以阅读下服务编排相关的描述,这的确是一种小白都可以掌控的微服务编排方式。
第三步,对接外部的服务
对于我们这样一个初创公司而言,将数据库等服务托管给云服务商,直接使用 RDS 服务是个既经济又稳健的选择。在 Rainbond 体系中,我通过添加第三方组件的方式将位于云端的 RDS 服务纳入管理之中。这种纳入让第三方服务也像部署在平台之中一样,可以被其他微服务组件所依赖。
至此,我的开发环境就已经部署完成了。
第四步,复制出了测试环境、预发布环境和生产环境
在以往的开发过程中,搭建环境是一个很繁琐的事情。对一个处于快速迭代过程中的产品而言,我们至少需要开发环境、测试环境、生产环境,在我们自己的实际场景中,还引入了预发布环境。对于代码而言,我仅需要 Fork 出多个分支,来区分不同环境即可。通过定义流水线,我们也已经完成了不同代码分支打包镜像的不同 tag。但是到了搭建环境这一步,难道就只能根据不同的镜像 tag ,手动一点点的创建组件?想到藏书馆业务的近 50 个微服务组件,和彼此间的依赖关系,我的头就很大,IT 从业者最不能忍受的就是重复工作。
在探索 Rainbond 使用方法的过程中,快速复制这个功能一下子抓住了我的眼球。快速复制功能可以检出所有组件的构建源信息,对于源码构建的组件,构建源就是它的代码仓库地址、编程语言、代码分支;而对于镜像构建的组件,构建源则对应了镜像地址和 tag。在这样一个界面下,我可以选择需要被复制的组件,修改其 tag 版本。这样的复制能力可以实现环境在不同集群、不同团队下的复制。新的环境继承了原环境中除镜像 tag 以外的所有设定:依赖关系、组件名称、环境变量配置、持久化设置等等。
利用这个能力,我基于开发环境,像 Fork 一份代码一样,通过修改 tag 的方式复制出了测试环境、预发布环境和生产环境。
这一能力极大的节约了我们使用 Rainbond 时,部署各种环境的时间成本。目前,我们也把这一功能用于新人的开发环境搭建,以前手把手教新人如何搭建自己的开发环境是很费心费力的事情。
串通持续交付流程
早前,我们已经借助 Jenkins ,自定义了一套完整的流水线,来实现所有微服务组件的构建。最终的构建产物会被定制为镜像推送到镜像仓库中去。我们对这一部分的工作是比较满意的,我们希望 Rainbond 能够在镜像仓库之后集成进来,完成微服务组件的持续构建与部署。
Rainbond 在这一部分是非常开放的,提供了接口来实现与第三方 CI 工具的对接。我们只需要在 Jenkins 的流水线完成镜像推送后,添加一个步骤简单的调用下 Rainbond 提供的接口,对应的微服务组件就会自动拉取最新的镜像,完成上线操作。到目前为止,整个技术团队都已经适应了这种使用方式。
实际上这是一个很通用的接口调用方式,无论对接哪一种第三方 CI 工具,都可以很方便的调用。
每一个运行在 Rainbond 上的微服务组件,在构建源处都可以打开自动构建的设置。自动构建设置有三种实现:
- 基于 Git-Webhook ,针对基于源代码构建的微服务组件,可以借助代码仓库的 Webhook 能力,实现代码一推送,就触发该服务组件自动构建并上线的效果。支持的代码仓库类型比较广泛,GItlab、Github、Gitee、Gitea 等代码仓库都支持。
- 基于镜像仓库 Webhook ,针对基于镜像构建的微服务组件,可以借助镜像仓库的 Webhook 能力,实现镜像一推送,就触发该服务组件自动构建并上线的效果。Harbor、Dockerhub 等镜像仓库都支持 Webhook 功能。
- 自定义 API,这是最通用的接口调用方式,用户只需要基于 Http 协议调用,即可触发该服务组件的自动构建并上线。
触发上图中的自动构建 API,最简单的方式是在命令行中执行一条命令:
curl -d '{"secret_key":"6GvowlHX"}' -H "Content-type: application/json" -X POST https://<Rainbond控制台地址>/console/custom/deploy/c4e7b60bd800986df940d8103f22d271
目前,我们已经可以做到以很简单的方式,精确触发到指定的流水线,完成对应微服务组件的更新上线。
其他通过 Rainbond 解决的问题
随着对 Rainbond 这款产品认识的不断加深,我们开始不断抛却一些琐事,一些传统部署模式下难以规避的问题,借助 Rainbond 的能力都得以很好的解决:
内部依赖配置无法查询
传统部署模式下,所有组件之间的相关依赖,都是写在配置文件中的一系列配置。对产品整体没有足够了解的工程师很难掌握所有依赖项的引用地址,写错 IP 导致调用不通的失误时有发生。借助应用拓扑图的展现,现在每一个新手工程师,在看到拓扑图之后,都会立刻对产品的整体结构产生直观认识。
多实例部署异常后排查不便
传统部署模式下,每个微服务组件如果需要多实例部署,都需要工程师们手动操作服务器上传 jar 包进行配置。如果遇到升级调整,偶尔还会错漏。一旦出现问题需要排查,如何定位正确的实例就已经很麻烦了。Rainbond 环境下,每个微服务组件的多实例版本一致性不需要关心,而出问题排查时,实时日志推送和 Web 控制台都帮了大忙。
服务器资源不能共享
传统部署模式下,我们通过划分虚拟机来避免计算资源的浪费,然而这还不够。我们希望计算资源能够完全池化,面向每个微服务组件来划分。这一点所有基于 Kubernetes 实现的应用管理平台都可以实现。而 Rainbond 的伸缩设置,是我见过产品化做的最好,最易用的。Rainbond 平台上线后缩减了三分之二的服务器资源。
相同监听端口不能同台部署
端口其实也是一种重要的资源,同个操作系统下,端口的占用是不可以冲突的。这个问题在大规模微服务组件部署时显得尤为突出。Rainbond 这一点做的很好,每个微服务不会直接占用服务器端口,我们的开发人员可以更自由的定义组件监听了。
开发人员权限管理
真实的业务场景下,软件系统本身的问题并非都由运维人员处理,更多的情况下需要开发者本人排查和处理。而权限管理则要求开发人员尽可能不具备登录生产服务器的权限。这就导致了一个两难的问题,快速解决问题还是严格管控权限?这是开发人员和运维人员容易产生冲突的点。引入 Rainbond 之后,这个问题得到了很好的解决,开发人员的所有操作都是在 Rainbond 管理界面进行的,即使需要通过命令行排查问题,也可以通过 Web 控制台登录容器环境,而不是宿主机服务器。目前,我们已经形成了应用开发人员基于 Rainbond 运维自己开发微服务组件的模式。
应用版本回滚
传统模式下,微服务组件的部署有多复杂,那么回滚到上一个版本就只会更复杂。Rainbond 这款产品非常贴心的提供了服务组件级别的一键回滚,管理人员可以在版本列表之中随意选择需要的版本,进行一键回滚,这真的太方便了。
写在最后
和使用其他产品一样,深入使用 Rainbond 也是需要一些磨合过程的。令我印象深刻的一个情况,是 Rainbond 使用的 Glusterfs 分布式文件系统,在经过很长一段时间的使用之后,存储容量被用尽,导致了一系列问题。我们的运维人员缺少对 Glusterfs 的了解,对 Rainbond 如何与 Glusterfs 相互作用更是一知半解。无奈之下求助官方,出乎意料的是官方的工程师非常热心的支持我们解决了问题,并贴心的留下了操作文档。
我对 Rainbond 最大的感触是其易用性做的很好。希望 Rainbond 团队可以将这一点贯彻到底,提供更多能够解决实际问题的实用特性。我们了解到 Rainbond 的 Service Mesh 下一步可以支持 istio,下一阶段我们打算尝试一下。