@Lenciel

构建 CI/CD 系统

对软件公司,特别是互联网软件公司来说,发布流程是企业的核心竞争力

那么什么是一个好的发布流程呢?Github(别忘了它本身也是一家软件公司)的 CTO 在介绍Boxen 的时候说过,他们公司新员工从拿电脑到可以开始编码只要 30 分钟,这给混过几家 10w+员工公司的我带来的震撼特别强烈。

所以我觉得,一个好的软件发布流程应该是:

  1. 新员工在第一天入职就能 push 改动到 production
  2. 新员工在第一天入职就能学会怎么从 production 撤销一个错误的改动
  3. 整个 deployment 流程是可预测的,也是可追溯的

那么,如果你到了一个新公司,推开门发现那是一个蛮荒之地,应该怎么办呢?这篇先理一下基本的概念,然后后面分节描述一下讲到的这些工具具体要怎么配置怎么用。

善其器

先 check 一下东西齐不齐活:

  1. 代码 repo 是放在哪里: (githg, …),
  2. hook 到 repo 的一套有 review 功能的管理系统: (ReviewBoard, Gitlab, gerritbitbucketgithub, …),
  3. hook 到 repo 的一套 CI 管理系统: (JenkinsTravis CI, …),
  4. 自动部署代码到服务器的系统 (Puppet, chefclusto, …).
Don't touch me

你选择的工具当然对后面的流程有很大的影响。我们公司是采用git+Gitlab+Reviewboard+Jenkins+fabric来做部署。在搭建这套东西之前我也试过很多其他的东西,有的东西我放弃了是因为太复杂不够轻量(比如 Puppet),有的东西我放弃了是因为,长得太丑(比如 Gerrit)。

开发者视角

假设你今天入职,写了段代码,从你的视角看到的 deployment 流程:

  1. 提交到本地 repo。
  2. 运行RBTools生成一个 Reviewboard 的review request
  3. 代码通过了 review 拿到提交许可后,把代码 merge 然后 push 到 Gitlab 上的alpha分支
  4. Jenkins 拿到 change 后做自动测试,然后部署到 test 服务器,发邮件通知 QA
  5. QA 或者是开发者自己玩一下 test 服务器,发现没有问题,手动运行 Jenkins 脚本。脚本会对代码打 tag,并部署改动到 staging 服务器,发邮件通知 QA 和 PO
  6. PO 确认某个版本的所有代码都到了 staging,QA 做回归测试
  7. 测试通过后,手动运行 Jenkins 脚本,脚本会部署某个 staging 服务器的版本到 production 服务器
  8. 部署完毕后,Jenkins 运行相应的冒烟测试,测试通过后邮件关键人士,表明 production 音容宛在

整个流程里面,如果你是一个靠谱的开发者,需要花时间参与的步骤很少。但是如果是一个习惯不好的开发者,可能被 review 代码的人,Jenkins 的自动测试,QA 的集成测试或者是回归测试不断修理,惨痛的教训一定会让你成长起来的。

机器视角

很多重复性的事情,都是机器在干:

  1. Reviewboard 上被通过的代码被 push 上 Gitlab 的alpha分支后,Jenkins 自动运行:
    1. 静态扫描工具
    2. 单元测试
    3. 有报错发邮件通知事主。没有报错, 部署alpha分支到 test 服务器
    4. 部署 test 服务器后,运行集成测试集
  2. 有人手工触发 staging 的 build:
    1. mergealpha分支到staging分支
    2. 部署staging分支到 staging 服务器
    3. 部署服务器后,运行集成测试集
  3. 有人手工触发 production 的 build:
    1. mergestaging分支到production分支
    2. 部署production分支到 production 服务器
    3. after deployment, runs integration tests against production

这里很多具体的步骤需要通过 Jenkins 和它的插件甚至是自己写的各种脚本来配合完成

考虑扩展性

未知的未来,你可能会发现项目换了开发语言,项目换了 JS 框架,项目自动化测试改成手动了…在架构整套部署系统的时候,要做好和具体语言具体流程的解耦。

一些可能会有用的思路:

  1. 项目组足够小,成员能力足够好,可以不用 review 代码直接 checkin 到公共 repo(成员能力足够好至少意味着,他有写靠谱的 UT)
  2. 你构建出来的系统,每个不同的 build 应该可以很容易的绑定不同的工具: 1. 静态扫描工具是很好 (比如 pylintpep8或者jshint),但最好项目一开始就用它们。如果是旧项目不要往上套,费时费力 2. 如果是用precommit的hook来跑测试,开发者本地可以不跑 3. 如果是有特别要求的项目(安全性,健壮性等),可以很容易绑定其他的工具
  3. 每个项目对应不同的 deployment 环境有不同的 build 配置
  4. 三驾马车的服务器配置 (test, staging, production)什么时候应该祭出?个人经验是,如果研发团队超过 3 人了,再怎么省也得有两个(test+production)。如果有专职的 QA 团队,并且希望有稳定的版本部署出去,那三种环境的配置几乎是必须的。
  5. 手动触发 test 到 staging 以及 staging 到 production 主要是为了手动测试的时间窗,让版本发布更可控。你也可以结合项目的具体情况决定要不要把这两步也自动化。

如果是用了 Jenkins,上面这些就非常方便了,因为说白了每个 build 不过就是当特定条件满足时执行的一堆特定脚本而已:当然,如果你发现公司还在用 Ubuntu 12.04 做 build server,可能也没有那么方便。

Rants

  1. 什么时候需要考虑上这种流程? 如果是三个人的车库队伍,然后就队伍里面又没人有兴趣做对运维,那就算了吧。如果是正经开门做生意的公司,都该上。
  2. 能不能允许”加急”? 和很多大公司比,这套流程虽然已经精简了,但是总有时候我们有非常”紧急的”改动,能不能不走这套流程直接上? 简单的回答就是,不能。如果你发现了有人要求加急,一定是目前的流程太慢。这种情况,一定是有什么东西坏掉了吧。比如之前的代码 check 不严格,很严重的错误很容易就到了 production,或者你的员工们写的 UT 跑一年都跑不完或者是在 build server 上根本没法跑。
  3. 为什么不自动部署? 是,这里描述的流程只有到 test 服务器是自动部署的,后面到 staging 和 production 都是手动部署。因为据说,把自动 merge 和自动测试的代码部署到 production 服务器,是一个很容易让你半夜接到电话的举动,而且很多 CEO 鬓角的白头发都是因为这样的部署长出来的。当然如果你的 manager 已经在他老板那里夸口说你来了整个手动测试 team 都可以解散了,我就只能祝你好运了。
  4. 静态扫描的工具(无论是 lint 还是 style 的检查),常常都会给团队带来比 UT 更好的提升:很多时候你在 review 的时候要不断告诉同事特别是新手同事你这段代码连 style 都不对,对两个人都是伤害…如果有个无情的机器用不妥协地负责做这件事情,嗯哼…

Hope you have fun when setting up the pipeline for your company.

Why look so sad

"Why do you look so sad?"
"Because you speak to me in words and I look at you with feelings."