惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

aimingoo的专栏
aimingoo的专栏
S
Securelist
博客园 - Franky
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
IT之家
IT之家
GbyAI
GbyAI
Microsoft Azure Blog
Microsoft Azure Blog
The Cloudflare Blog
云风的 BLOG
云风的 BLOG
N
News and Events Feed by Topic
AI
AI
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
Schneier on Security
Schneier on Security
Attack and Defense Labs
Attack and Defense Labs
Vercel News
Vercel News
腾讯CDC
Google DeepMind News
Google DeepMind News
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
M
MIT News - Artificial intelligence
WordPress大学
WordPress大学
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
N
Netflix TechBlog - Medium
量子位
S
Schneier on Security
Hacker News: Ask HN
Hacker News: Ask HN
Cyberwarzone
Cyberwarzone
S
Security Affairs
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
N
News and Events Feed by Topic
T
Tenable Blog
PCI Perspectives
PCI Perspectives
MyScale Blog
MyScale Blog
L
Lohrmann on Cybersecurity
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
C
Cyber Attacks, Cyber Crime and Cyber Security
W
WeLiveSecurity
N
News | PayPal Newsroom
P
Proofpoint News Feed
O
OpenAI News
C
CERT Recently Published Vulnerability Notes
B
Blog
Cisco Talos Blog
Cisco Talos Blog
Microsoft Security Blog
Microsoft Security Blog
V
Visual Studio Blog
MongoDB | Blog
MongoDB | Blog
大猫的无限游戏
大猫的无限游戏
A
Arctic Wolf
Y
Y Combinator Blog
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Spread Privacy
Spread Privacy

Coding

请教一下各位佬 GPT 一直 401 是什么情况? - V2EX 天翼云 glm5.1 codingplan 官方玩不起,强制终止用户的包月续订 - V2EX 字节的 CodingPlan 实锤虚假宣传 - V2EX 现在有什么优雅的使用 ai 工具编程的方法? - V2EX MiniMax-M2 截到 11.07 限时免费 - V2EX VibeCoding 导致损失 1100 刀 - V2EX rpc 服务中,“业务错误”的返回应该如何设计? - V2EX 科班大学计算机专业主要课程有哪些呢 - V2EX 你们公司用上 ChatGPT 了吗?有哪些使用场景 - V2EX Cloud Studio 内核升级之专注体验 - V2EX 行云流水| CI 3.0 云原生构建全新上线 - V2EX ​Cloud Studio 云端开发保障企业源代码安全 - V2EX 更高效便捷的开发体验——Cloud Studio 编辑器命令行工具 - V2EX Cloud Studio 内核升级之持续优化 - V2EX Cloud Studio 有“新”分享 - V2EX 怎么设计面试题,能考查到实战能力? - V2EX 有奖征文丨 [玩转 Cloud Studio] 第二季来啦! - V2EX Cloud Studio 一个好用的在线编程工具 - V2EX 线上直播 | 未来金融研究所——以应用为中心,重塑金融研发效率 - V2EX 新一代 CI 即将到来! - V2EX 重磅发布! Orbit 云原生应用全生命周期管理工具上线啦! - V2EX 腾讯云, DevOps 领导者! - V2EX 各位是如何批量管理项目中的 shell 脚本的? - V2EX CODING DevSecOps 助力金融企业跑出数字加速度 - V2EX CODING 正式入驻腾讯会议应用市场! - V2EX CODING DevOps 助力中化信息打造新一代研效平台,驱动“线上中化”新未来 - V2EX 叮! Techo Day 腾讯技术开放日如约而至! - V2EX 程序员在公司该怎么保护自己的个人劳动成果? - V2EX Next.js 在 Serverless 中从踩坑到破茧重生 - V2EX [高效开发] 不止面对面, Cloud Studio 推出 MetaWork 云协作套件 - V2EX CODING 公开课火热报名中! - V2EX coding.net 502 - 2022 年 3 月 21 日 - V2EX 发现 coding.net 会对 1 年未登录用户删数据 - V2EX CODING 携手 Thoughtworks 助力老百姓大药房打造”自治、自决、自动”的敏捷文化 - V2EX 迷雾中的自动化测试体系建设 - V2EX Nocalhost:云原生开发新体验 - V2EX 使用 Nocalhost 开发 Kubernetes 中的 APISIX Ingress Controller - V2EX CODING x 百果园,水果零售龙头迈出 DevOps 体系建设第一步 - V2EX CODING 与悬镜安全达成战略合作,引领 DevOps 向 DevSecOps 创新模式升级 - V2EX Apache Log4j 2 报高危漏洞, CODING 联手腾讯安全护卫软件安全 - V2EX WePack —— 助力企业渐进式 DevOps 转型 - V2EX CODING 代码资产安全系列之 —— 构建全链路安全能力,守护代码资产安全 - V2EX 一页纸需求的应对方法 —— 五步法 - V2EX Nocalhost 为 KubeSphere 提供更强大的云原生开发环境 - V2EX 喜报! Nocalhost 成功加入 CNCF 沙箱 - V2EX Nocalhost —— 让云原生开发回归原始而又简单 - V2EX CODING 项目协同 2.0 —— 让协作有条不紊 - V2EX 赋能“数字金融”, CODING 再下数城 - V2EX 打造数字化软件工厂 —— 一站式 DevOps 平台全景解读 - V2EX 做云原生时代标准化工具,实现高效云上研发工作流 - V2EX
大型前端项目 DevOps 沉思录 —— CI 篇 - V2EX
CodingNET · 2021-12-03 · via Coding

本文作者:成龙 腾讯前端开发工程师,负责腾讯文档前端开发与研发效能提升,AlloyTeam 成员。

导语

本篇文章将着重探讨 DevOps 在持续集成阶段需要提供的能力,将对工作流的设计及流水线的优化思路做一个简要讲解。

DevOps 一词源于 Development 和 Operations 的组合,即将软件交付过程中开发与测试运维的环节通过工具链打通,并通过自动化的测试与监控,减少团队的时间损耗,更加高效稳定地交付制品。

随着腾讯文档的项目规模越来越大,功能特性与维护人员越来越多,特性交付频率与软件质量之间的矛盾日渐尖锐,如何平衡两者成为了目前团队亟需关注的一个重点,于是,落地一个完善的 DevOps 工具链便被提上日程。

CI ( Continuous Integration ),即持续集成,指频繁地(一天多次)将代码集成到主干的行为。

注意,这里既包含持续将代码集成到主干的含义,也包含持续将源码生成可供实际使用的制品的过程。因此,我们需要通过 CI ,自动化地保证代码的质量,并对其构建产物转换生成可用制品供下一阶段调用。

因此,在 CI 阶段,我们至少有如下阶段需要实现:

1. 静态代码检查

这其中包括,ESLINT/TSLINT 静态语法检查,验证 git commit message 是否符合规范,提交文件是否有对应 owner 可以 review 等等。这些静态检查不需要编译过程,直接扫描源代码就可以完成。

2. 单元测试 /集成测试 /E2E 测试

自动化测试这一环节是保障制品质量的关键。测试用例的覆盖率及用例质量直接决定了构建产物的质量,因此,全面且完善的测试用例也是实现持续交付的必备要素。

3. 编译并整理产物

在中小型项目中,这一步通常会被直接省略,直接将构建产物交由部署环节实现。但对于大型项目来说,多次频繁的提交构建会产生数量庞大的构建产物,需要得到妥善的管理。产物到制品的建立我们接下来会有详细讲解。

利于集成的工作流设计

在正式接入 CI 前,我们需要规划好一种新的工作流,以适应项目切换为高频集成后可能带来的问题与难点。这里涉及到的改造层面非常多,除了敦促开发人员习惯的转变以及进行新流程的培训外,我们主要关心的是源码仓库的更新触发持续集成步骤的方式。

1. 流水线的组织形式

我们需要一个合适的组织形式来管理一条 CI 流水线该在什么阶段执行什么任务。

市面上有非常多的 CI 工具可以进行选择,仔细观察就会发现,无论是 Drone 这样的新兴轻量的工具,亦或是老牌的 Jenkins 等,都原生或通过插件方式支持了这样一个特性:Configuration as Code ,即使用配置文件管理流水线。

这样做的好处是相当大的。首先,它不再需要一个 web 页面专门用于流水线管理,这对于平台方来说无疑减少了维护成本。其次对于使用方来说,将流水线配置集成在源码仓库中,享受与源码同步升级的方式,使得 CI 流程也能使用 git 的版本管理进行规范与审计溯源。

确立了流水线的组织形式后,我们还需要考虑版本的发布模式以及源码仓库的分支策略,这直接决定了我们该以什么样的方式规划流水线进行代码集成。

2. 版本发布模式的取舍

在《持续交付 2.0 》一书中提到,版本发布模式有三要素:交付时间、特性数量以及交付质量

这三者是相互制衡的。在开发人力与资源相对固定的情况下,我们只能对其中的两个要素进行保证。

传统的项目制发布模式是牺牲了交付时间,等待所有特性全部开发完成并经历完整人工测试后才发布一次新版本。但这样会使得交付周期变长,并且由于特性数量较多,在开发过程中的不可控风险变高,可能会导致版本无法按时交付。不符合一个成熟的大型项目对于持续交付的要求。

对于持续集成的思想来说,当我们的集成频率足够高,自动化测试足够成熟且稳定时,完全可以不用一股脑地将特性全堆在一次发布中。每开发完成一个特性就自动进行测试,完成后合入等待发布。接下来只需要在特定的时间周期节点自动将已经稳定的等待中的特性发布出去即可。这对于发布频率越来越高,发布周期越来越短的现代大型项目中无疑是一个最优解

3. 分支策略

与大部分团队一样,我们原有的开发模式也是分支开发,主干发布的思想,分支策略采用业界最成熟也是最完善的 Git-Flow 模式。

可以看出,该模式在特性开发,bug 修复,版本发布,甚至是 hotfix 方面都已经考虑到位了,是一个能应用在生产环境中的工作流。但整体的结构也因此变得极为复杂,不便管理。例如进行一次 hotfix 的操作流程是:从最新发布前使用的主干分支拉出 hotfix 分支,修复后合入到 develop 分支中,等待下一次版本发布时拉出到 release 分支中,发布完成后才能合回主干。

此外,对于 Git-Flow 的每一个特性分支来说,并没有一个严格的合入时间,因此对于较大需求来说可能合入时间间隔会很长,这样在合入主干时可能会有大量的冲突需要解决,导致项目工期无端延长。对此,做大型改造与重构的同学应该深有体会。

针对这一点,我们决定大胆采用主干开发,主干发布的分支策略

我们要求,开发团队的成员尽量每天都将自己分支的代码提交到主干。在到达发布条件时,从主干直接拉出发布分支用于发布。若发现缺陷,直接在主干上修复,并根据需要 cherry pick 到对应版本的发布分支。

这样一来,对于开发人员来说需要关注的分支就只有主干和自己 working 的分支两条,只需要 push 与 merge 两条 git 命令就能完成所有分支操作。同时,由于合入频率的提高,平均每人需要解决的冲突量大大减少,这无疑解决了很多开发人员的痛点。

需要说明的是,分支策略与版本发布模式没有银弹。我们采用的策略可能并不适合所有团队的项目。提高合入频率尽快能让产品快速迭代,但无疑会让新开发的特性很难得到充分的手工测试及验证。

为了解决这一矛盾点,这背后需要有强大的基础设施及长期的习惯培养做支持。这里将难点分为如下几个类型,大家可以针对这些难点做一些考量,来确定是否有必要采用主干开发的方式。

1 )完善且快速的自动化测试。只有在单元测试、集成测试、E2E 测试覆盖率极高,且通过变异测试得出的测试用例质量较高的情况下,才能对项目质量有一个整体的保证。但这需要团队内所有开发人员习惯 TDD (测试驱动开发)的开发方式,这是一个相当漫长的工程文化培养过程。

2 ) Owner 责任制的 Code Review 机制。让开发人员具有 Owner 意识,对自己负责的模块进行逐行审查,可以在代码修改时规避许多设计架构上的破坏性修改与坑点。本质上难点其实还是开发人员的习惯培养。

3 )大量的基础设施投入。高频的自动化测试其实是一个相当消耗资源的操作,尤其是 E2E 测试,每一个测试用例都需要启动一个无头浏览器来支撑。另外,为了提升测试的效率,需要多核的机器来并行执行。这里的每一项都是较大的资源投入。

4 )快速稳定的回滚能力和精准的线上及灰度监控等等。只有在高度自动化的全链路监控下,才能保证该机制下发布的新版本能够稳定运行。这里的建设我会在之后的文章里详细介绍。

大型项目中产物->制品的建立

对于大多数项目来说,在代码编译完成生成产物后,部署项目的方式就是登录发布服务器,将每一次生成的产物粘贴进发布服务器中。生成的静态文件由于 hash 不同可以同时存放,html 采用直接覆盖的方式进行更新。

直接使用复制粘贴的方式来操作文件的更新与覆盖,这样既不方便对更新历史的审计与追溯,同时这样的更改也很难保证正确性。

除此之外,当我们需要回滚版本时,由于服务器上并没有存放历史版本的 html ,因此回滚的方式其实是重新编译打包生成历史版本的产物进行覆盖。这样的回滚速度显然不是令人满意的。

一个解决方法是,不要对文件进行任何的覆盖更新,所有的产物都应该被上传持久化存储。我们可以在请求上游增设一个流量分发服务,来判断每一条请求应该返回哪一个版本的 html 文件。

对于大型项目来说,返回的 html 文件也不一定不是一成不变的。它可能会被注入渠道、用户自定义等标识,以及 SSR 所需要的首屏数据,从而改变其代码形式。因此,我们认为 html 文件的制品提供方应该是一个单独的动态服务,通过一些逻辑完成对模板 html 的替换并最终输出。

总结一下,在每次编译完成后,产物将会进行如下的整理以生成最终的前端制品:

  1. 针对静态文件,如 CSS 、JS 等资源将会发布到云对象存储中,并以此为源站同步给 CDN 做访问速度优化。

  2. 针对 HTML 制品,需要一个直出服务做支撑,并打包成 docker 镜像,与后端的微服务镜像同等级别,供上游的流量分发服务(网关)根据用户请求选择调起哪些服务负载进行消费。

速度即效率,流水线优化思路

对于一个好的工具来说,内部设计可以很复杂,但对于使用者来说必须足够简单且好用。

在主干开发这样高频的持续集成下,集成速度即效率,流水线的执行时间毫无疑问是开发人员最关心的,也是流水线是否好用的决定性指标。我们可以从几个方面着手,提高流水线执行效率,减少开发人员的等待时间。

1. 流水线任务编排

对流水线各个阶段需要执行的任务我们需要遵循一定的编排原则:无前置的任务优先,执行时间短的任务优先,无关联的任务并行。

根据这一原则,我们可以通过分析流水线中执行的各个任务,对每一个任务做一次最短路径依赖分析,最终得出该任务的最早执行时机。

2. 巧用 Docker Cache

Docker 提供了这样一个特性:在 Docker 镜像的构建过程中,Dockerfile 的每一条可执行语句都会构建出一个新的镜像层,并缓存起来。在第二次构建时,Docker 会以镜像层为单位逐条检查自身的缓存,若命中相同镜像层,则直接复用该条缓存,使得多次重复构建的时间大大缩短。

我们可以利用 Docker 的这一特性,在流水线中减少通常会重复执行的步骤,从而提高 CI 的执行效率。

例如前端项目中通常最耗时的依赖安装 npm install ,变更依赖项对于高频集成来说其实是一个较小概率的事件,因此我们可以在第一次构建时,将 node_modules 这个文件夹打包成为镜像供下次编译时调用。Dockerfile 示例编写如下:

FROM node:12 AS dependenciesWORKDIR /ciCOPY . .RUN npm installENV NODE_PATH=/ci/node_modules

我们给流水线增加一条检查缓存命中的策略:在下次编译之前,先查找是否有该镜像缓存存在。并且,为了保证本次构建的依赖没有更新,我们还必须比对本次构建与镜像缓存中的 package-lock.json 文件的 md5 码是否一致。若不一致,则重新安装依赖并打包新镜像进行缓存。若比对结果一致,则从该镜像中直接取到 node_modules 文件夹,从而省去大量依赖安装的时间。

流水线拉取镜像文件夹的方法示例如下,其中 --from 后跟的是之前缓存构建镜像的别名:

COPY --from=dependencies node_modules/ .# 其他步骤执行

同理,我们也可以将这一特性扩展到 CI 过程中所有更新频率不高,生成时间较长的任务中。例如 Linux 中环境依赖的安装、单元测试每条用例运行前的缓存、甚至是静态文件数量极多的文件夹的复制等等,都能利用 Docker cache 的特性达到几乎跳过步骤,减少集成时间的效果。由于原理大致相同,在此就不赘述了。

3. 分级构建

众所周知,流水线的执行时间一定会随着任务数量的增多而变慢。大型项目中,随着各项指标计算的接入,各项测试用例的数量逐渐增多,运行时间迟早会达到我们难以忍受的地步。

但是,测试用例的数量一定程度上决定着我们项目的质量,质量检查决不能少。那么有没有一种方法既可以让项目质量得到持续保障的同时,减少开发者等待集成的时间呢?答案就是分级构建。

所谓分级构建,就是将 CI 流水线拆分为主构建和次级构建两类,其中主构建需要在每次提交代码时都要执行,并且若检查不通过无法进行下一步操作。而次级构建不会阻塞工作流,通过旁路的方式在代码合入后继续执行。但是,一旦次级构建验证失败,流水线将会立即发出通知告警,并阻塞其他所有代码的合入,直到该问题被修复为止。

对于某任务是否应放入次级构建过程,有如下几点原则:

1 )次级构建将包含执行时间长(如超过 15 分钟)、耗费资源多的任务,如自动化测试中的 E2E 测试。

2 )次级构建应当包含用例优先级低或者出错可能性低的任务,尽量不要包含重要链路。如果自动化测试中的一些测试用例经过实践发现失败次数较高,应当考虑增加相关功能单元测试,并移入主构建过程。

3 )若次级构建仍然过长,可以考虑用合适的方法分割测试用例,并行测试。

总结

我们认为,从代码集成、功能测试,到部署发布、基础设施架构管理,每一个环节都应该有全面且完善的自动化监控手段,并尽量避免人工介入。只有这样,软件才能同时兼顾质量与效率,在提高发布频率的情况下保证可靠性。这是每一个成功的大型项目最终一定要实现的目标。

参考资料

  1. 《持续交付 2.0 》—— 乔梁 著

  2. https://www.redhat.com/zh/topics/devops/what-is-ci-cd

  3. https://www.36kr.com/p/1218375440667012

立即开启高效云端研发工作流