---
title: "基于 GitLab 实现 DevOps"
date: 2019-08-29T22:07:00.000Z
author: Z.SHINCHVEN
tags: [GitLab, pipeline, DevOps]
canonical: https://atlassc.net/2019/08/30/run-pipeline-w-gitlab
---
## GitLab是我们团队的核心协作平台

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

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

GitLab 有个扩展程序叫 [GitLab runner](https://docs.gitlab.com/runner/)，它与 GitLab 对接之后，GitLab 会将触发的 [Pipeline](https://docs.gitlab.com/ee/ci/pipelines.html) 任务推送到 runner 上执行。

Runner 上支持多种类型的 [executor](https://docs.gitlab.com/runner/executors/),我们选择的是 docker executor ，因为我们希望使用 docker 来部署程序，并且也希望服务器的环境相对干净且易于管理。

docker executor 在工作时会根据 [CI 配置文件](https://docs.gitlab.com/ee/ci/yaml/)中的镜像配置启动一个容器，并执行 CI 配置文件中的脚本。在任务完成后容器会自动销毁，非常干净。

当然你也可以通过[缓存路径配置](https://docs.gitlab.com/ee/ci/caching/)来重复利用某些文件，比如 node_modules 文件。我们利用这个特性和 [pipeline variables](https://docs.gitlab.com/ee/ci/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](https://docs.gitlab.com/ee/api/pipelines.html) 或者 [trigger api](https://docs.gitlab.com/ee/ci/triggers/) 触发另外一个工程师的 Pipeline 即可。

### 如何按需且分步进行编译？

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

#### 使用 cnpm 归档组件

- 使用私有部署 [cnpm](https://npm.taobao.org/) 将各个工程编译归档成package；
- 再在一个用作部署的工程中，从 cnpm 中获取各个组件的 package 来组装程序；

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

#### 使用 Pipeline variables 进行控制

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