字节跳动飞书为什么选择 Zadig 实现主干开发、主干发布

我们充分感受到 Zadig 的优秀设计思想是非常值得字节 DevOps 团队借鉴学习的,相信 Zadig 会有更美好未来!

KodeRover
KodeRover  

# 字节跳动飞书为什么选择 Zadig 实现主干开发、主干发布

「我们深度认同 Zadig的设计理念,并且认为 Zadig 真正意义上解决了微服务集成测试的痛点。Zadig 毫无疑问是业界优秀的 CI/CD 产品,它也是真正理解微服>务、重视微服务、解决微服务痛点的产品。我们充分感受到 Zadig 的优秀设计思想是非常值得字节 DevOps 团队借鉴学习的,相信 Zadig 会有更美好未来!」

-- 飞书高级 SRE 工程师:新之助

字节跳动的飞书是整合即时沟通、视频会议、日历、云文档、OKR、企业邮箱、服务台等功能于一体的新型办公软件。飞书设计理念先进,功能齐全,而且性能稳定:她不仅是字节跳动高效增长的引擎,也正成为越来越多优质企业的办公协同必备软件。你知道吗,飞书软件的快速迭代的神秘助手之一正是 Zadig!这篇文章,飞书 SRE 工程师新之助就来和大家分享飞书和 Zadig 当初是如何相中彼此的。

以下为「新之助」分享的案例,供大家参考

# 背景

飞书的整体技术架构承接字节基础架构,以微服务为核心,运行在大规模自研容器平台TCE(起源于Kubernetes)之上。飞书音视频部门成立于 2018 年中旬,早期的团队成员对 Go 语言和微服务的最佳实践在认知上有比较明显的不足。在经历了近一年半的迭代中,我们才逐步探索出一套勉强适用于团队的 Workflow,但与此同时也积累了较重的技术包袱。

首先需要声明的是,对于飞书这样一个 to B 的产品来说,质量和稳定性极为重要。因此数据监控和自动化测试是产品的生命线,本文不讨论数据监控的具体实践,主要是阐述自动化测试的演进之路。

在最早期从 0 到 1 的阶段,音视频服务端的业务侧实际上只有 1 个单体服务,该服务简单依赖少数外部的飞书 IM 服务(例如账号服务、卡片服务、消息服务等),存储也只包括 MySQL和 Redis。我们花费了一些时间讨论单元测试和功能测试的实现路径,并且快速得到了有效的反馈,这一切在只有1个单体服务的情况下非常简单。

最终方案概述起来大致是:Mock 外部 RPC 接口返回值,存储层 MySQL/Redis 使用 Docker 容器,通过原生的 go test 加上 assert 工具包辅助进行单元测试和功能测试。此处单元测试和功能测试的主要区别是:功能测试会要求该单体服务启动运行之后,模拟客户端请求发向服务,专注于测试接口级别的功能完整性。

进一步地,在定制了一套 CI 流水线之后,整个初步的 Workflow 便形成了。

然而由于对微服务的拆分原则缺乏系统性的认知,我们在接下来的一年中迎来了爆炸式的服务数量增长。这里面除了业务增长所必须要新增的服务之外,更多的是为了方便不同 Owner 维护而独立出来的“冗余”服务。但从长期来看,微服务数量增加是必然现象。

此时,早期设计的单元测试作用越来越小,功能测试更是已经名存实亡。由于每个服务都存在数量不小的外部依赖,尤其是需要多个 RPC 串联的时候,大量的 Mock 接口不仅脱离真实业务场景,而且维护 Mock 本身的逻辑也有非常高的成本。在业务的快速迭代中,外部接口同样日新月异,变化速度之快,使得编写功能测试用例几乎成为不可能的事情。

我们终于意识到需要彻底抛弃 Mock,提供一种能力串联所有的微服务,做端到端的集成测试,这才是未来的发展方向。

恰逢此时的飞书进入发展新阶段,在更大的战略方针上面首次提出所有飞书服务需要支持私有化部署。这是一个重要契机,让我们开始全面思考开源的技术方案。

因此,在私有化部署集成测试两重动力驱动之下,我们正式立项探索可行的解决方案。

# 探索期

2019 年底,在经过一轮简单的讨论之后,我们决定先从问题的简化版开始探索:搭建一个 All In One 的环境,将目前已经存在的音视频微服务全部部署在该环境中,并且彼此之间能够互相访问。我们后来将这个环境命名为 OneBox

OneBox 若能实现将会带来两个重要作用:

  • 理清字节云依赖。在 OneBox 的落地实践中,我们必然会逐步梳理清楚现有代码中哪些强依赖字节云上环境,从而在私有化部署的场景中改造或者移除。
  • 微服务集成测试。OneBox 真正搭建完成之后,我们可以利用整个环境当做微服务集成测试的基准环境,微服务的整体集成测试也就具备落地的可能性。

由于生产环境中的服务是运行在 TCE 上面的(字节自研 Kubernetes 引擎,但强依赖字节云上环境),因此我们第一直觉就是考虑基于原生 Kubernetes 的私有化部署方案

我们申请了一台配置优秀的物理机,快速搭建了 Rancher 和 Rancher Kubernetes 集群。然后 case by case 的分析每个音视频服务的依赖,进行逐步改造:例如将原本依赖于字节 debian 基础镜像改造成依赖于开源 debian 基础镜像、将原本依赖字节云 MySQL/Redis/ES/Kafka/RocketMQ 的 go-driver 改造降级成开源版本、服务之间的调用方式从原本字节统一的 Consul 改造成原生的 Kubernetes Service 等等。

我们迅速在原生 Kubernetes中 启动了一个又一个微服务,并且微服务之间完全互通。然而正当我们以为一切顺利的时候,却还是遇到了致命问题:存在某些字节自研的存储组件没有容器化,而服务却强依赖该存储组件

也正是这个原因最终影响了飞书私有化部署的整体方案,我们不可能完全改造成开源存储,而字节存储的云原生化还在逐步规划当中。

最终飞书的私有化部署方案基本如下(IaaS+PaaS+SaaS 一体化):

综上所述,飞书私有化部署的整体方案和产品形态都是非常重量级的。但是 OneBox 的探索之路仍然要继续下去,因为我们还需要 OneBox 来完成音视频微服务的集成测试。

不同于飞书私有化部署这个目标,我们还存在另一个致命的制约因素:飞书音视频业务本身无法闭环。我们的集成测试虽然是聚焦于音视频业务的,但飞书的业务本身是一体化无法分割的,因此我们必然要依赖飞书其它部门的微服务。

正是由于无法闭环,因此最早期设计功能测试框架的时候,我们以 Mock 作为解决方案。但正如我上面所说,Mock 接口返回值的做法在快速迭代的微服务架构中是 ROI 极低的做法

我们最终思考许久之后,做出了两大决策:

  • 对于飞书服务的外部依赖复用字节云上统一测试环境(该环境名为 staging,是在字节云上面飞书整体的测试环境,数据库与生产环境完全独立)。
  • 对于无法容器化的存储组件复用字节云上的存储,我们形象称之为外挂。

上图所示的 Staging 是字节云上面的飞书测试环境。而 OneBox 则是音视频业务的 All In One 环境。

OneBox 里面的计算层都是基于原生的 Kubernetes。常规服务指使用常见的开源存储组件,如:MySQL/Redis 的服务,可以通过部署 MySQL/Redis StatefulSet 到 Kubernetes。特殊服务指使用字节自研存储组件,只能通过外挂方式去访问。

对于 OneBox 依赖 Staging 飞书其它部门的服务,我们不通过 Mock 完成,而是直接发送真实的 RPC 请求。

决定 OneBox 架构之后,下一步要解决的核心问题就是工具选型,我们认为工具是非常重要的。我们需要快速复刻多个 OneBox 作为基准测试环境,对于每个服务代码仓库的每次改动提交去部署其中某一个基准环境,再发起上游的集成测试用例。

一开始我们在工具选型上面主要考虑的是:

  • Jenkins
  • Gitlab CI
  • Rancher CI

当时本人并不知道 KodeRover 的产品 Zadig(开源之后的名字,下文统一用 Zadig 这一名称),后来在同事的推荐之下也纳入调研范畴。不过我们几乎在理解 Zadig 之后就迅速敲定了它。

Zadig 最吸引我们的特性是:

  • 快速创建环境。Zadig 基于 Kubernetes Namespace 能够一键快速复刻环境,这一特性正是我们最需要的。
  • 微服务启动顺序。Zadig 允许我们为微服务指定启动顺序,解决了我们处理微服务之间依赖关系的问题。
  • 代码仓库集成。Zadig 同时支持 Gitlab 和 Gerrit,非常符合字节的技术栈。

相比之下无论是 Jenkins、GitLab 还是 Rancher 本身都不涉及微服务的概念,它们是面向更加通用的场景而设计的。

# 运行期

我们深度认同 Zadig 的设计理念,并且认为 Zadig 真正意义上解决了微服务集成测试的痛点。

但因为 TCE(字节自研 Kubernetes 引擎)和原生 Kubernetes 的差异巨大,我们无法通过 Zadig 来管理 TCE。因此,我们将 Zadig 定位成音视频微服务集成测试平台

飞书音视频服务端的整体发布模型是基于 Gitlab Flow:

对于非核心服务,我们采用单分支模型:master 发版。对于核心服务,我们采用双分支模型:master 发版测试环境和 online 发版生产环境。

Zadig 在飞书实践中的位置大致如下:

有了 Zadig 的集成测试能力,我们对进入 Master 分支的改动更加自信,整体带来的收益也比较大。另一方面,Zadig 简约清爽的 UI 设计让我们非常喜爱这个平台,因此我们在后续的工作中也接入了很多不包含服务部署只利用 Zadig 定时任务的一些工作流。

# 结语

Zadig 毫无疑问是业界优秀的 CI/CD 产品,它也是真正理解微服务、重视微服务、解决微服务痛点的产品。 我们充分感受到 Zadig 的优秀设计思想是非常值得字节 DevOps 团队借鉴学习的,相信 Zadig 会有更美好未来!

# 关于 Zadig

通过在包括头条、腾讯、七牛云、非码等企业的多年上千次迭代,今天的 Zadig 已经成为微服务 + Kubernetes 技术栈团队的最佳研发交付方案, 同时无缝兼容任何研发团队现有交付工具链和研发流程,无缝集成 GitHub/GitLab、Jenkins、多家云厂商,帮助团队一步到位打造强大的 DevOps 和 CI/CD 工程基建能力,变云原生为生产力。

Zadig 本身是基于 Kubernetes 设计、研发的开源分布式持续交付 (Continues Delivery) 产品,为开发者提供云原生运行环境,支持开发者本地联调、微服务并行构建和部署、集成测试等。Zadig 内置了面向 Kubernetes、Helm、云主机、大体量微服务等复杂业务场景的最佳实践,为工程师一键生成自动化工作流 。

# 欢迎参与开源

github.com/koderover/zadig | 源码 (opens new window)
gitee.com/koderover/zadig | 源码 (opens new window)
koderover.com | 官网 (opens new window)
space.bilibili.com/502473428 | Bilibili (opens new window)
my.oschina.net/koderover | 开源中国 博客 (opens new window)
blog.csdn.net/koderover | CSDN 博客 (opens new window)
zhihu.com/org/koderover | 知乎 (opens new window)

欢迎大家 Star、Fork、 Watch!和众多开发者一起探讨、交流,共建开源社区!

KodeRover 公众号

© 2021 筑栈(上海)信息技术有限公司 沪 ICP 备 19000177 号 - 1