写点什么

探索 To-D, 落地好大夫效能平台

作者:方勇(gopher)
  • 2023-06-30
    北京
  • 本文字数:8060 字

    阅读完需:约 26 分钟

探索To-D,落地好大夫效能平台

喜欢造新概念的程序员又在扩散新名字了,To-D(To Developers),面向开发者,专注于研发提高开发者效能的产品,如 jenkins,gitlab 等。在企业内部越来越重视人效的当下,降本增效成为了大家研究的方向,同时促进了 To-D 产品线的整合,各种大厂商也在纷纷推出自己的云平台。但是还有相当一部分经历互联网十年浪潮洗礼的公司,很难一蹴而就全部迁移到公有云,再加上运营成本的升高,担心被云平台锁死等,近几年又有不少企业下公有云,采用混合云部署,甚至完全私有化部署也不在少数。这样很多公司内部,自建云平台,旨在保障稳定性和可用性,并提升研发测试的效能。


好大夫发展十多年,早年的异构体系对研发的心智考验也越发的大,提供给研发使用的平台也越来越笨重。为了提升效能,好大夫技术中心历时一年,重构了整个效能云平台,目前已交付使用,接下来我们一块聊一下这一年的心路历程。

从工具集到平台,提效使命从未更改


咱们知道,不会偷懒的程序员,不是好的程序员。十几年前,前辈们就在提效的道路上探索了,在那个莽荒世纪,各种工具层出不穷,各显神通,配支付,改密码,充余额,修数据齐齐上阵,是工具集爆发的大年份。


再后来随着研发、测试、运维等岗位的细化分工,工具集往平台化沉淀。迭代出了自动化测试平台,DevOPS 运维平台,各种中间件的 PaaS 平台。再加上第三方开源平台 sonar,sentry,elk 体系等等,诸多场景的选择,让研发测试使用成本剧增。


为了避免研发测试抓瞎,技术中心开始整合这些平台,最初的设想是联合所有内部平台,做一个大而全的网址导航,做好文档梳理,按场景化培训研发测试使用。然后这种浅层次的整合,并未提升多少用户体验。反而往往一个场景的处理会牵扯多个平台的交互。跳来跳去,频繁的上下文切换,加重了研发测试的心智成本。

To Die or Not to Die,这是一个永恒的话题


痛点太多,要不要改变?十几年的文化积淀和使用姿势,也许有些人早已习惯,也许有些人早已无力吐槽,也许是压死骆驼的最后一根稻草,也许是劝退新人的拦路虎。这些痛点,仿佛沉淀在时间长河里的泥沙,需要来一次彻底的清理才能奔赴向前。


在提效的大势之下,技术中心还是下定决心,改!不改就是等死,改了也许死的更快,也许能扭转乾坤。此时如何改,又成了各个方向争论的焦点。是延续前辈的智慧结晶,打补丁式整合,还是重新定义研发测试的使用场景,甚至重构研发测试的使用习惯。



深度整合各个已经存在的平台,打破康威定律,可以想象会遇到多大的阻力。这个时候需要从更大的目标上对齐,把蛋糕做大,模糊研发、测试、运维边界。做出来的产品令人向往,才能达成共识,实现持久共赢,整个事才能往预想的方向发展。


最后在多个小组,多轮碰撞之下,随着 CTO 的振臂一挥,效能平台开启了重构之旅。

不破不立,唯有涅槃方可重生

We have a dream


新版本的效能平台的目标:


围绕产品交付的整个生命周期展开,从研发阶段的代码到部署产线后的运营。是好大夫微服务的管家,保障服务的稳定性和可用性。是研发测试的工作台,整个产品形态需要和研发测试建连内核态连接,辅助研发测试做决策。将研发测试日常工作流式化,事件化,可视化,可量化,让提效看得见。



以服务运营为例,这是一个常见的场景,A 服务出现接口响应慢的告警(P99 波动,时延超过 1000ms),研发收到告警事件提醒后,打开我的工作台,他将看到到:


  • 实时告警事件

  • 历史流量同比环比

  • 给出历史告警操作记录

  • 给出最近该服务上线频次


研发就可以进行相应的常规操作,扩容,或限流,或调整告警阈值,抑或是回滚代码,当然部分操作还会发起工单审核。



告警处理只是产品持续交付整个生命周期的一个小环节,实时工作台,会整合了历史趋势,历史操作记录,历史上下游线上变更动作等。


根据经验,分析这些离散的事件,然后串联起来,形成一个个具象的场景,最后辅助研发测试做决策。这其实类似有监督的学习模式,随着数据的积累,学习研发操作行为,让一个个场景处理更加智能高效。

RoadMap 先行


经过上面场景的分析,我们是围绕产品的持续交付展开的,涉及质量,安全,成本,效率等方方面面。咱们不可能一口吃个胖子,需要慢慢来,一份好的 RoadMap,就像一盏指路明灯。


快速落地基建,打响 HUP 第一枪


为了提升信心,需要快捷完成基础组件建设。基建,决定了平台的上限,是场景化迭代的保障。团队在一定规模之后,丰富的技术栈保障了创新性,但在团队规模较小的时候,统一技术栈的收益还是相对高点。再加上我们经过两年的沉淀,积累了不少 Golang 体系的基础组件,同时为了更好地融于云原生,最终决定整个体系采用 Golang 架构。一起看看几个重要的基础组件。


单点登录(SSO)


之前各部门自研的 PaaS 平台,以及引入的第三方开源平台,大部分各自实现了一套用户管理模块。当有员工入职或者离职的时候,需要各个平台保障员工信息的同步,带来了额外的维护成本,以及安全风险问题。一般解决跨平台登录,都采用 SSO,实现共享用户。


SSO 原理



从图中可以看到,实现 SSO 的关键组件是 Authelia,我们采用的是共享顶级域的 Cookie 的模式来实现 SSO 的。


登入,基于顶级域 cookie 认证,必须要保证二级域名在一个域下,即*.example.net 全域互通。这些域名都需要经过 SSO 认证之后才能放行,二级域名首先会判断 SSO 特定 key 的 cookie 是否存在,是否过期,然后携带 cookie 去 Authelia 拉取用户信息。


登出,当任意一个二级域名登出的时候,调用 Authelia 销毁 Cookie 即可。


Authelia(SSO)优势和注意事项


  • 解决了跨平台频繁登录的问题。

  • 对接 LDAP 后,方便统一管理用户,控制权限,人员离职可一键锁定全平台的权限。

  • 目前主流的开源平台都适配了 LDAP,Authelia 也适配了大部分的开源平台,接入成本低,Authelia 还支持接入 OAuth 体系。

  • 丰富的路由访问策略,Authelia 支持免认证的白名单策略,以及针对高危操作配置动态二次验证等等,支持 GoogleAuth 和设备生物身份认证。

  • 由于实现了单点登录,带来了方便的同时,也引入了安全问题,为了避免设备被其他人操作,需要控制好 cookie 生命周期,失效长时间不活跃的 cookie,另外关键操作需要接入动态指令的二次验证。

  • 针对用户访问量大的时候,可以结合 JWT 使用,建设服务端认证的压力,Authelia 也是支持的。


我们服务都部署在 k8s 中,通过简单配置 ingress 策略即可实现 SSO。如果大家感兴趣。后续可以出一个单独的番外篇,详细介绍如何基于 Authelia 实现 SSO。


组织架构管理及权限控制



组织架构如果靠人力维护会非常的繁杂,我们基于钉钉花名册的信息,动态生成一系列关联关系。将现实中的部门与成员的关系,映射成不同场景的用户与分组的关联关系。人员的变更,自动维护整个体系信息的完整性。



权限控制,是各个平台的基本模块, 权限的统一管理是基建的重中之重。我们采用 RBAC 模式设计了权限管理,细化每一个请求的接口,并配置对应的菜单项,如一条告警规则的增,删,改,查,四个 api 对应四条菜单项。权限控制精准到具体的 api 对应的菜单项上,api 遵循 restful 规范,有 get 权限,未必有 post 权限。



除了 api 维度,还有页面维度,每个页面都配置一条路由规则,因此每个页面也对应一条菜单项,也就纳入到了权限控制中了。根据登录用户权限的不同,会动态渲染页面,显示可操作的菜单项,如研发能看中间件运营操作,而测试能操作发布到测试环境的任务。


RBAC 模式的不足


虽然我们已经按 api 的粒度去设计访问权限了,但有时候需要更细的粒度,需要细化到具体资源的所有者。比如对 k8s 资源 Pod 实例操作,我们期望研发只能操作自己负责的应用实例,但 RBAC 模式,要么能操作所有 pod,要么什么 pod 也操作不了。业内也有相应的解决方案,基于属性操作。简称 ABAC(Attribute-Based Access Control),已纳入 HUP 后续版本迭代规划。


另外整个权限管理,菜单配置,是基于低代码实现的,后面会介绍低代码的应用。



最后看一下组织架构设计的冰山一角,这也是首次尝试 DDD(领域驱动设计),去设计一个服务。



工单体系


做好权限控制,针对线上重要变更,就需要引入工单审核机制。工单审核,应该是一个高度抽象的模块,支持审核流的灵活配置,工单体系是场景化对接的重要基石。



工单体系需要解决以下几个问题:


  • 按场景生成工单审核流,每一步审核都支持回滚到上一级,并清晰记录操作流程

  • 审核环节支持动态和静态选择审核人,静态是明确审核人的情形,动态是指能主动选择合法的审核人,关键环节还可以支持加签,特殊情况还需要支持代批

  • 审核人是一个抽象概念,可以是单个的人,也可以是多个人组成的小组

  • 审核环节支持 hook 回调,可根据不同的审核行为触发不同的 hook 回调

  • 工单审核流程,需要支持拖拽配置审核流,支持移动端审核,并联动办公交流软件,通过消息推送提醒审核人


跨平台无缝融合



我们有很多开源的平台,如绘制看板的 Grafana,记录异常调用栈的 Sentry,代码质量检测的 SonarQube 等等,以及之前自研的内部平台。为了避免重复造轮子,在场景化改造的时候,需要想办法复用之前的技术成果,那就涉及到跨平台交互的改造。我们希望研发在使用 HUP 的时候,不要产生割裂感,不要感觉到在多个平台之间跳来跳去。于是我们开发了一个外壳,由左导航,上导航,主体三部分组成,跨平台以主体的结构嵌入进来。



在嵌入之前,很多第三方平台有自己的登录,及导航,需要改造一下,以实现无缝嵌入。由于我们打通了 SSO 单点登录,接入的平台就不需要再登录了,同时握有了登录的 cookie。我们在 SSO 登录的 cookie 里种上 HUP 标识,第三方平台植入一段通用 js,就能随意改变样式,并适配 hup 主题。这样第三方平台就能完美地嵌入进来了。


这种模式主要是为了嵌入第三方开源平台,或者嵌入改造成本比较高的老平台,如果已经是前后端分离,那只用将前端整体迁入到 HUP 前端工程即可。


在基建的过程中,我们也做了不少创新,从架构到产品形态,涉及诸多方便,我们致力于打造令人兴奋的现代化的产品,为后续扩展到其他业务团队做先锋。

孵化前沿创新,提升 HUP 影响力

开启云端开发



传统开发是基于本地研发调试,这比较适合单体服务,这种模式在微服务架构下会面临很多问题。


  • 微服务场景下,跨服务联调,需要启动多个服务,配置复杂度高,效率低。

  • 各个研发本地环境可能存在差异,如 node/npm 版本不一致,golang pkg 源设置不一致等等环境问题,干扰问题排查。

  • 有时候需要多版本对比测试,需要准备多套环境,部署和运维成本都很高。

  • 有时候需要 debug 模式启动实例,如果实例部署在 k8s 里,研发操作 pod 成本高,有些 pod 基础镜像甚至不支持 debug 能力,如果云端能和本地一样 debug 就方便了。


基于以上痛点,我们需要一个统一标准的开发环境,参数配置好,debug 工具也安装好,研发开箱即用。这样研发只用关心业务代码,屏蔽了环境差异,那会大大提高效率。调研后,发现 Nocalhost 完美地解决了我们问题。


整个流程,对研发来说几乎没有什么变化。


  • 研发在本地开发,文件变更后,通过 IDE Plugin 同步到云端为研发分配的工作空间上。

  • IDE 基于 kubeconfig,打通研发本地和云端的通信,云端会拉起统一标准的开发环境实例,并挂载研发云端的工作目录。云端监听文件变更,实时更新服务实例。

  • 云端工作空间采用共享存储,业务代码和第三方依赖分开,业务代码目录,以研发本地机器名为标识隔离存储,第三方依赖为整个工作空间全局共享。

  • 研发只用安装一个浏览器插件,修改 header 标识,即可将浏览器的请求劫持到云端自己的实例上,从而形成了一个闭环。


Nocalhost 将研发本地开发环境迁移到了云端,并实现流量分发的形成逻辑环。Nocalhost 内置了基于 k8s svc 模式的路由分发,但我们后端服务注册发现是基于 Eureka 的,只需简单扩展一下就可以了。


尝试 GitOPS



我们秉承着谁开发,谁治理的理念,hup 体系从 coding 到运维,都是我们一手操办的。接入云端开发后,我们也把整个部署流程迁移到 gitops。业务代码和部署的配置分开,整体依托于 gitlab pipeline。业务代码测试通过后,打上版本 tag,触发构建 job 和 sonar 扫描 job。镜像构建完成后,推送到 harbor,同时更新部署仓库的镜像版本。部署基于 argocd,监听部署仓库代码的变更,发布到相应的 k8s 集群。


看齐 DDD



基础模块,如用户中心,权限菜单管理等,属于关键支撑。在业内也形成了领域共识,这次设计的时候也采用 DDD(领域驱动设计),同时沉淀了 Golang 体系的 DDD 框架,尝试 CQRS,尝试聚合根,事件驱动等。领域内基于事件总线 EventBus 通信,领域间基于 gRPC 通信,异步操作基于消息发布订阅。积累 DDD 实战经验,为后续复杂的场景化改造提供理论样例。


尝鲜前端低代码




HUP 有很多场景提供的是管理能力,基本操作也是简单的增删改查。比如工单审核流程,列表页用表格展示待办的工单,再加一个详情页用于展示和操作。类似的场景还是很多,比如权限配置模块,菜单配置模块,消息管理模块等等都采用了低代码实现,方便后端研发快速搭建自己的应用。整个低代码体系是基于百度开源项目 amis 实现的,如果大家感兴趣,后续会输出相关的整合文档。

重构高频场景,提升 HUP 价值

随着基建的推进,HUPv1.0.0 完成了老平台的整合,但真正体现实质性价值的,还是一个个经验固化下来的场景。受二八规律影响,这些日常场景中,高频使用的,也就那么几个,将这些高频场景优化到极致,这时候谈论效能才更有意义。


我们复盘了一下,重构发布工程,提升发布效率,并打造成标杆的场景化范例,是首选项。


重构发布工程,一年前就有过多方讨论,每次都以激烈的争论收场,得不到实质性进展。发布工程涉及到三个小组协作,多个平台的交互。运维组研发负责发布到虚拟机,架构组研发负责发布到 k8s,测试阶段还对接了测试研发的自动化测试平台,中间还穿插着项目管理。整个发布工程,处于一种能用又不好用的状态。有时候发生点问题,需要三方协调排查,效率低。业务研发测试,完成一次从开发到产线的发布,需要在多个平台上操作,严重影响了效率。再加上整个发布工程,经历了十多年的积淀,一直在上面打补丁,很多逻辑异常的复杂,已经成为对维护人员的心智负担。


发布工程需要优化,但如何优化一直无法达成共识,有小改方案,又重构方案。其实这种项目改造属于,少做少错,多做多错,不做不错,很容易形成分歧。


这个时候自上而下的领导力就尤为关键,跨部门协作,需要以更高的维度对齐目标,将项目做大,就会产生虹吸现象,蛋糕大了,就会吸引大家主动参入进来。在 CTO 的号召下,重构发布工程正式启动。这个项目,涉及前端团队,运维团队,测试研发团队,系统架构团队多部门协作,为了保障质量和沟通效率,我们封闭开发了一个多月。整个发布工程。各个环节涉及的细节非常多,再上使用习惯的转变,刚开始试用那两周,是被吐槽最惨的时期。随着使用文档的丰富,以及宣讲,大家开始逐级适应新的发布体系。简单聊一下,改造后的发布工程。


简单介绍一下《SRE:google 运维解密》的发布工程哲学:


  • 自服务类型,业务团队能自给自足,自己控制发布流程,同时需要高度自动化,研发只用很少的干预。

  • 追求速度,敏捷开发模式,需要频繁构建,测完即能随时发布。

  • 密闭性,也就是构建的幂等性,不论何时何地,构建结果应该都相同。

  • 强调策略和流程,需要保障每次上线的版本,严格进行了 CodeReview,都被测试验证过。


接下来一起看一下。重构后的发布工程具备了哪些特性:


  • 不漏上不错上


一般发布只考虑代码变更的维度。



其实发布不只有代码,配置变更,线上运营操作等,都属于发布范畴。而这些操作,需要被记录跟踪到,在需要的时候,支持在开发环境,测试环境,和产线环境重现整个流程。改版的后的发布工程,将 Code 变更,Apollo 配置,RabbitMQ 配置,短信模板配置,脚本执行等等都纳入发布流程中。


  • 引入了工作流,将发布流程标准化、流程化,各个步骤支持可插拔




这部分挑战也是最大的,不仅需要和第三方开源平台做交互,还需要支持各个环节的热插拔。为了将第三方开源服务接入到 hup,我们开发了胶水层,封装成 api。特殊的第三方平台,直接采用嵌入的方式集成进来。为了支持可插拔,我们研发了 workflow-controller 用于组装工作流,为了减少耦合,研发了事件解释器 EventBus,用于处理工作流中的 hook 回调。工作流依托于开源项目,argo workflow,podman,argocd 等。



发布工程中采用模块化分解各个步骤,方便可插拔,也方便了职责分离,同时发布工程,支持多集群并行发布,支持幂等。线上有三套隔离的多活集群,一套虚拟机,两套 k8s。



  • 服务编排和配置编排虽然我们鼓励业务敏捷开发,随时测完随时上线,不要有依赖,但这会增加研发向下兼容的成本。有些时候,项目迭代涉及多个服务,需要集成到一起统一发布。因此发布工程,即需要支持业务自己独立发布,还需要支持服务编排发布的能力。针对集成发布,我们限制于晚上特定时间发布,按南北向流量分层发布,首先发布不依赖代码的 sql,apollo 配置,mq 配置,然后发布后端服务,再发布前端服务,最后发布脚本,同步 Kong 配置。

  • 多版本发布,及灰度发布支持


为了适配多版本发布,我们实现了一个流量分发的逻辑环,需要适配流量入口有,http 入口流量,mq 消息入口流量,以及脚本入口流量。这里给出的 mq 流量多版本示意。



截止目前为止灰度发布还是研发期,这里给出一个流程示意图。



经过几个版本的迭代,发布工程也逐渐接近毕业版本,为后续其他场景化的对接提供了可以参考的模板。篇幅有限,这里就不展开细说,当然大家感兴趣,后续可以出了一个番外篇详细聊一下发布工程。

超越技术范畴,传承 HUP 薪火

技术从来只是基石,持续发展,受影响因素很多,往往离成功也许只差一点点运气。静下心来,慢慢打磨,有时候做着做着,也许就水到渠成了。


效能,需要一杆称



场景化迭代,不只是功能实现,既要考虑用户使用体验,还需要考虑交付的产品质量,标准化流程,往往会牺牲一部分效率。


拿发布工程为例,服务上线必须经历开发环境,测试环境,甚至是灰度环境,最终才能全量发布到产线。早些时候,开发是能跳过所有环节,不用测试,直接发布到产线的,规范上线流程后,会延长上线时长,但为了交付质量,需要做平衡。像这样的场景还是挺多的,研发测试有自己的诉求,但平台亦背负着自己的使命,需要不断地调整,寻找平衡点,而这是一个长期的过程,也是目前吐槽最多的地方。


碰撞,真正的幕后推手


好产品是碰撞出来的,不是被设计出来的,需要多方不断讨论,不断吐槽,一版版的迭代。HUP 是研发测试的工作台,是好大夫服务的管家,涵盖服务的整个生命周期,从仓库代码到产线运行,以及服务治理。这是一个庞大的体系,很难穷举所有场景,很难以上帝的视角提前设计好各个环节。我们尽量做到扩展友好,将日常工作事件化,抽象成不同场景的工作流,配合工作流的钩子,动态调配日常工作,直到固化成一条工作经验。在这个过程中,需要放低姿态,去倾听研发测试的心声,千万不能闭门造车,否则很多功能的实现就变成了花架子,变成了自嗨的玩具。


MDD,让提效看得见


为了避免黑盒,我们借助于 MDD 思想(Metrics-Driven Development),要求各个组件提炼出健康指标和反映内在价值的指标,同时细化各个场景的指标。统计分析各个环节的耗时,失败率,使用频率等,为持续迭代场景提供数据支撑。



文化自信,持续发展之道


随着 HUP 一期期的迭代,伴随着大家的吐槽,伴随着大家的期许,HUP 快速成长着。作为 HUP 平台的研发的我们,也逐渐自觉了新的身份认同--HUPer,沉淀了番号--Thinking In SRE.


HUPer 做的不只是提升效能的平台,而是在做一种企业文化,将效能、SRE 等理念同步给更多的人。我们知道产品交付,发布产线不是终点,而这恰恰只是开始,HUP 作为研发测试工作台入口,势必承载了服务运营的职责,保障全站可用性和稳定性,即是职责,亦是使命。HUP 作为一种文化符号,在不知不觉中更新大家的认知,同时吸纳更多的人共建生态。HUPer 们也在不断布道,组建线下沙龙,宣讲 SRE 等理念。


每一期的 HUP 版本迭代我们都会取一个代号,并召开发布会,发放周边礼品,印有 logo 的文化衫,办公文具,书签等等。这是一种文化氛围,是一种文化传承,也是历史的见证。

Keep Running, Keep Thinking

提效是一个长期的过程,道阻且长,重构发布工程只是开端,我们还需要重新梳理 SRE 整个治理体系,缩短 MTTR(故障排查时长),保障稳定性和可用性。目前 HUP 是基于私有云场景展开的,后续也会考虑探索公有云和边缘计算的领域,为开源社区贡献一份自己的力量。


发布于: 2023-06-30阅读数: 25
用户头像

Dead or Alive. 生存战斗是知识的源泉! 2018-11-08 加入

我是一名SRE哨兵,目前是好大夫基础架构部高级工程师。专注于 SRE,微服务、中间件的稳定性和可用性建设,整体负责好大夫服务治理云平台的设计和搭建!

评论

发布
暂无评论
探索To-D,落地好大夫效能平台_DevOps_方勇(gopher)_InfoQ写作社区