avatar

ShīnChvën ✨

Effective Accelerationism

Powered by Druid

基于 GitLab 实现 DevOps

Thu Aug 29 2019

GitLab是我们团队的核心协作平台

在过去4年里,我们团队的整个软件开发流程(代码版本控制、开发任务管理、缺陷管理和自动化部署)都在私有部署的社区版 GitLab 上面进行,它是我们的核心协作平台。配合上 docker 和 cnpm 仓库,我们基本上实现了 JavaScript/NodeJS 全栈的自动化 DevOps。

使用 GitLab runner 实现自动化部署的 Pipeline

GitLab 有个扩展程序叫 GitLab runner,它与 GitLab 对接之后,GitLab 会将触发的 Pipeline 任务推送到 runner 上执行。

Runner 上支持多种类型的 executor,我们选择的是 docker executor ,因为我们希望使用 docker 来部署程序,并且也希望服务器的环境相对干净且易于管理。

docker executor 在工作时会根据 CI 配置文件中的镜像配置启动一个容器,并执行 CI 配置文件中的脚本。在任务完成后容器会自动销毁,非常干净。

当然你也可以通过缓存路径配置来重复利用某些文件,比如 node_modules 文件。我们利用这个特性和 pipeline variables 实现了项目分包按需编译。

我们现在的 DevOps 流程是怎样的?

  • 开发:
    • 工程师在自己分支下编写代码;
    • 提交到远端后会触发代码检查的 Pipeline;
  • 测试:
    • 工程师在功能开发完毕后提交 merge request 到 test 分支;
    • 主管审查代码并合分支,后触发 test 分支的GitLab ci 脚本,
    • GitLab 将 Pipeline 任务推送到 测试服务器上的 runner;
    • Runner 根据 CI 脚本构建镜像并部署容器,供测试工程师测试;
  • 发布:
    • 主管在测试流程结束后将 test 分支合并到 master 分支,
    • GitLab 此时触发 master 分支的 Pipeline 任务,并推送给生产服务器上的 runner 执行(编译程序、构建镜像、部署容器);

在多工程的项目中实现 Pipeline 接力和按需执行

由于我们的项目一般都使用了前后端分离设计,前端有时候会分好几个工程,并且后端拆了微服务,因此在发布一个程序时,我们需要进行编译和组装。

这个时候会有两个问题:

各个工程的Pipeline如何实现接力?

Pipeline 接力很容易实现,在一个工程的 Pipeline 结束后通过 GitLab 的 Pipeline api 或者 trigger api 触发另外一个工程师的 Pipeline 即可。

如何按需且分步进行编译?

我们在发布一个多组件程序的时候,很多时候只需要更新它的一个组件。我们通过两个方式实了按需分步编译:

使用 cnpm 归档组件

  • 使用私有部署 cnpm 将各个工程编译归档成package;
  • 再在一个用作部署的工程中,从 cnpm 中获取各个组件的 package 来组装程序;

这样如果我们只需要更新组件A,那就只需要编译和归档组件A的新版本到 cnpm 中,在部署时,新版本的组件A会和其他未更新的组件被组装在一起。

使用 Pipeline variables 进行控制

  • 在部署专用工程的CI 脚本中根据 Pipeline 传入的 variable 来决定是否要编译某一个组件;
  • 编译完毕之后通过 CI 的 cache 配置缓存一份编译文件,如下次不再编译此组件,直接使用缓存;