Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
从零搭建一个高性能的前端CI服务器

从零搭建一个高性能的前端CI服务器

本系列教程介绍如何从零搭建一个前端CI服务器,以及如何优化其性能。

本系列教程均基于Gitlab CI,其它系统的酌情参考。

准备材料

在开始之前,你需要准备如下的基本材料:

  1. 一个有管理权限的Gitlab项目,可以是Gitlab.com上的,也可以是私有化Gitlab服务上的。
  2. 一台服务器,使用服务器、vps甚至自己的笔记本电脑等也可以,最好能满足一定的性能要求。2核4G以上吧。需要能访问到上面提到的Gitlab项目。

储备知识

如果能有以下方面的知识,会比较容易理解此系列教程。没有经验的话也可以,但需要通过文章中的各种外链,掌握一些相关知识。

  1. Linux系统结构与基本的Shell使用,可参考 Bash 脚本教程
  2. Docker相关知识,可参考 Docker入门教程
  3. YAML文件格式,可参考 YAML 语言教程
  4. Gitlab相关知识

目录结构

安装Linux服务器,配置Docker服务

前言

搭建一个CI服务器,并不一定需要一个Linux操作系统,甚至有些场景中还必须使用Mac/Windows等系统,但是Linux是最常用的。所以这个教程也会以Linux作为载体去讲解整个搭建流程。

如果已经有现成的Linux服务器了,或者已经有可用的Docker服务了,视各自的情况,可跳过这节教程。

安装Linux操作系统

选择发行版

Linux是一个开源的操作系统内核,我们常说的Linux操作系统,是GNU/Linux的各种发行版。它的发行版非常多,比如说有 Debian/Ubuntu系列,RedHat/CentOS/Fedora系列等,甚至Windows 10中内置的WSL也算。

因为Debian/Ubuntu系列和RedHat/CentOS/Fedora系列等都算是常用的发行版本,所以后面介绍的时候会尝试将二者都覆盖到,不过主要还是基于Ubuntu系统来讲。

下载安装镜像(ISO文件)

Ubuntu: https://ubuntu.com/download/server

CentOS: https://www.centos.org/download/

选择一个自己喜欢的发行版,一般下载最新的稳定版即可。

刻录USB安装盘

需要有一个U盘或移动硬盘,使用一些USB启动记录工具制作即可。

可以考虑使用Rufus、UltraISO、Unetbootin等工具。网络上较多此类教程,可参考Ubuntu官方文档:https://ubuntu.com.cn/tutorials/create-a-usb-stick-on-windows#1-overview

安装

具体安装步骤,网上也有很多。搜索"Ubuntu安装"或"CentOS安装"就会得到许多类似的结果。

举例来说,UbuntuServer-18.04 U 盘安装教程

设置软件源

主流的Linux发行版中,一般都会有软件仓库。它是一个集中的查询和下载软件包,以及解决软件依赖关系的仓库。

系统中自带的软件源地址一般是国外的,在国内访问国外的镜像时,速度一般都不太理想。所以会需要换成国内的软件源。常见的软件源有清华、网易、阿里云等。

以Ubuntu为例,更新软件源需要编辑/etc/apt/sources.list文件。写上更新后的地址。

具体的地址各大镜像源都会提供,如清华源有提供Ubuntu 镜像使用帮助

设置好软件源之后,运行sudo apt update更新仓库,apt是Debian系列的软件管理工具。

CentOS中对应于apt的命令是yum,对应的设置说明可参考:CentOS 镜像使用帮助

yum的大部分命令都会自动更新源信息,不需要主动执行apt update类似的操作。

安装Docker服务

Docker在CI中有比较大的作用,主要是以下三个方面:

  1. 隔离性,能保护host的安全。
  2. 稳定性,每次提供的都是干净的环境,不受上次CI的状态影响。
  3. 性能:活用Docker Cache,可以达到不错的优化效果。

所以在继续后面的操作之前,先安装下Docker服务。

关于Docker的安装,其官网是有文档的:Install Docker Engine on Ubuntu

这里复现下文档中的操作步骤:

删除旧的安装

如果之前没安装过,可以忽略这个步骤

$ sudo apt-get remove docker docker-engine docker.io containerd runc

添加Docker源

$ sudo apt-get update

$ sudo apt-get install \
    apt-transport-https \
    ca-certificates \
    curl \
    gnupg-agent \
    software-properties-common
    
$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -

$ sudo add-apt-repository \
   "deb [arch=amd64] https://download.docker.com/linux/ubuntu \
   $(lsb_release -cs) \
   stable"

安装Docker

 $ sudo apt-get update
 $ sudo apt-get install docker-ce docker-ce-cli containerd.io

如果是用的Windows或Mac,也可以使用Docker Desktop

启动Docker服务

$ sudo systemctl start docker

设置Docker源

Docker同样有一个仓库,它的官方地址是 https://hub.docker.com/,和其它常见镜像源类似,它在国内的访问速度也不佳。

为了能够正常地使用Docker源,我们需要把它设置成国内的镜像源,如网易源。

修改文件/etc/docker/daemon.json,如果没有则新建:

{
  "registry-mirrors": ["http://hub-mirror.c.163.com"]
}

测试拉取镜像

前端CI一般都会用到node相关的镜像,可以测试下拉取node的镜像,测试速度。

$ docker pull node:12-alpine

这里稍微解释下node:12-alpine的含义

docker pull 用来拉取镜像,冒号前面的是镜像名称,后面的是版本。如果不提供版本,默认为latest。这个方式和npm dist-tag很像。

下面是https://hub.docker.com/中node的版本列表:

node版本列表

虽然版本tag是随便定义的,但是也大概能看出维护node Docker镜像的团队,采用的命名方式为:<版本号>-<操作系统>的方式。12-alpine的含义即为 Node.js v12的最新版本 + alpine 操作系统。alpine是一个极简的Linux操作系统镜像,体积比较小。

如果能拉取成功,则说明Docker已经配置成功,本节就结束了。

下节我们讲下Gitlab CI的机制,以及基本的.gitlab-ci.yml的配置语法。

Gitlab CI的机制及配置文件写法

gitlab-ci-infograph

图片来自https://www.onyxpoint.com/account-level-ci-access-management-with-gitlab-setuid-runners/

Gitlab CI的基本原理

机制

对于Gitlab仓库中的每一次Push(注意不是每一次Commit),Gitlab系统都会尝试去执行CI。

它会做如下的判断:

  1. 当前分支中有无 .gitlab-ci.yml 配置文件?有则继续,无则退出
  2. .gitlab-ci.yml中有无命名当前分支的job,或者提交信息中有无 skip-ci?有则继续,无则退出
  3. 创建pipeline,通知Gitlab Runner
  4. .gitlab-ci.yml中有无语法错误?有则显示 invalid-yaml并退出,无则继续
  5. 根据job中配置的runner tag,可否找到匹配的Runner?有则继续,无则显示 stuck
  6. 通知Runner执行任务,并获取结果

流程图

image-20201231143017218

Runner机制

不同于Travis CI等公网的CI服务,自建的Gitlab CI更类似于Jenkins,需要自己提供CI/CD服务运行环境。

它可以是一个Linux服务器,也可以是一个PC机,或者一个笔记本电脑,甚至一个树莓派。只要能运行gitlab提供的Runner程序,即可注册到Gitlab项目中,成为一个Runner。

Runner的注册机制

每个Gitlab项目,都会有一个自己的Gitlab CI设置Token。在你运行起gitlab-runner之后,可使用它的register命令将自身注册到Gitlab中,需要提供的参数有gitlab host地址,项目token,runner名称,tag列表等。

每个Runner注册之后,都会出现在Gitlab CI的Runner列表中,并带有如下的属性:

image-20201231135403848

这些属性中比较重要的就是Tags了,它规定了这个Runner能执行哪些任务。

Runner的Tags

每个Gitlab Runner,都可以配置一系列的tags,当然也可以只配置一个。

它与.gitlab-ci.yml文件中,job的tag相对应。一个job指定了其tag之后,Gitlab就会尝试为其寻找一含有可用tag的空闲Runner,如果有可用Runner且符合一定的其它条件,就会使用指定的Runner运行这个CI任务。

这个对应关系是Job维度的,而不是Pipeline维度。所以一个Pipeline很可能会利用到多个不同的runner。

.gitlab-ci.yml文件的写法

讲完了Gitlab CI的大概运行机制,下面再来说下它的配置文件写法。

这个文件是Gitlab CI的核心配置文件,存储在代码仓库中,文件采用YAML文件格式,可参考YAML 语言教程

先看下它的基本写法:

stages:
  - build
  - test

windows job:
  stage:
    - build
  tags:
    - windows
  script:
    - echo Hello, %USERNAME%!

osx job:
  stage:
    - build
  tags:
    - osx
  script:
    - echo "Hello, $USER!"

test job:
  stage:
    - test
  tags:
    - test
  script:
    - echo "Test"

从示例中可以看出,它的最基本写法是先有stages,划定有哪些执行阶段。

Pipeline graph

每个stage,对应于图中的一个列。

然后下面是job列表,windows job,osx job以及test job等都是可随意起的名字,绕开保留关键字,以及不要重名即可。

每个job中都可以配置stagetagsscript参数,分别用于指定其执行阶段,需要使用的Runner选择器、需要执行的命令等。

script需要与runner配套,比如说要运行Shell脚本,那多半要选择Linux环境,要使用nodejs,则最好选一个预置好Node.js的运行时。

Gitlab官方也有关于.gitlab-ci.yml的入门教程:Get started with GitLab CI/CD

另外也有官方提供的完全手册GitLab CI/CD pipeline configuration reference,注意里面的各项配置有区分版本,部分配置只在新版本中可用。

安装和配置Gitlab Runner

前言

上节中提到了Gitlab CI执行过程中需要寻找匹配的Runner,这里我们就动手配置下Gitlab Runner。

在开始之前,假设你已经有了:

  1. 一台Linux服务器,已经安装好Docker服务。
  2. 一个有管理权限的Gitlab工程。

如果英文水平不错的话,可参考官方文档:

  1. Install GitLab Runner
  2. Configuring runners in GitLab

下面我讲下我安装和配置Gitlab Runner时的过程:

安装Gitlab Runner

选择安装方式

安装方式有多种,比如使用deb包、rpm包,或者直接下载二进制文件。

为了简便,我用的直接下载二进制包的做法。

一般现在用的都是x64的机器,所以直接下载amd64版本的可执行文件即可。如果是其他架构的,可对应选择其它的版本。

amd64版本的gitlab-runner下载地址为:https://s3.amazonaws.com/gitlab-runner-downloads/master/binaries/gitlab-runner-linux-amd64

可选的其它版本还有:

下载下来之后,会得到一个gitlab-runner-linux-amd64的文件,为它添加可执行权限,并将其移动到一个系统目录中:

chmod a+x ./gitlab-runner-linux-amd64
sudo mv ./gitlab-runner-linux-amd64 /usr/local/bin/gitlab-runner

# 添加gitlab runner用户
sudo useradd --comment 'GitLab Runner' --create-home gitlab-runner --shell /bin/bash

# 安装
sudo gitlab-runner install --user=gitlab-runner --working-directory=/home/gitlab-runner

# 启动
sudo gitlab-runner start

之后就可以运行gitlab-runner来测试下效果了。

配置Gitlab Runner

注册Runner到Gitlab项目中

Gitlab服务器与Runner之间的通信,是通过Runner建立的长连接。首先Runner将自身注册进Gitlab服务器中,填好相应的配置,然后在它启动时,会主动地与Gitlab服务器建立连接。Gitlab后续派发任务时,就是通过这个长连接进行。

这个模式的好处是不需要Runner有公网地址,因为它是作为一个客户端的角色存在的,而不是一个服务端。

这个模式会要求Runner将自身的信息注册给Gitlab服务器,下面我们就讲下注册的过程。

打开Gitlab项目控制端,找到CI/CD。

打开项目中的"Settings->CI/CD",一般对应的URL是 <Git服务地址>/<组或用户名>/<项目名>/settings/ci_cd。会看到一个如下的页面:

image-20210104105717232

左侧部分,给出了注册的流程,右侧部分是共享的runner,一般由git管理员指定,设定一个或多个通用的Runner,共享给不同的项目,这里可以忽略。

记住这个图里面的2、3两个步骤中的URL和Token,后面会用到。

在服务器中注册信息

继续回到刚安装好 gitlab-runner 的服务器上,运行下面的命令:

sudo gitlab-runner register

image-20210104111852520

这时会出现一个提示框Please enter the gitlab-ci coordinator URL,输入上面复制的Git服务器地址,回车即可。

接下来会提示Please enter the gitlab-ci token for this runner:,输入上面复制的Token,回车即可。

接下来就会询问名称Please enter the gitlab-ci description for this runner,随便起一个名字或直接回车均可。

再接下来会提示Please enter the gitlab-ci tags for this runner (comma separated):,这里要输入tag列表,英文逗号分隔,如 build,test,deploy 或 foo,bar等均随意定义即可。这里的tag列表要和.gitlab-ci.yml文件中的tags保持匹配,后面也可以改,这里不确定的话,随便填一两个就行了。

再接下来会让选择runner执行器的类型Please enter the executor: docker, docker-ssh, ssh, docker-ssh+machine, kubernetes, custom, parallels, shell, virtualbox, docker+machine:,可选值就是上面列出的这些。

关于各种executor的区别,可查看官方文档:Executors

简单来说,最常用的executor是docker和shell。它俩的区别是docker类型依赖docker服务,shell直接用服务器当前系统。docker类型的好处是比较安全,shell类型的不安全,相当于在服务器上开了后门,.gitlab-ci.yml中就算配置了rm -rf,也会照单接收,执行不误的。

这里我选择的是docker,这也是为什么一开始配置服务器那里,要安装好docker service。

选择docker之后,还会让输入基础镜像,即每次执行CI任务时,以哪个镜像作为基础镜像,这个就完全看个人需求了。比如说执行环境需要有node.js,那可以使用node镜像,需要python,可用python镜像,需要有docker,可选docker镜像等。比较常见的情况,还是自定义一个镜像,安装上自己需要的各种软件。

到这个步骤之后,Runner就注册成功了,可以在 "Settings->CI/CD"中看到它了。

image-20210104113304896

配置Runner属性

Tags

在上图中,小锁按钮旁边有个编辑按钮。点击它就会进入到这个Runner的详细配置页面。

image-20210104133113393

图中的"Tags"中可以随时更改这个Runner关联的Tag。使它能匹配到不同的job。

Active

同样是在上图中,Active是个复选框,勾除它可以暂时禁用这个Runner。

其它比较重要的属性,就需要在运行Runner的服务器上,修改它的配置文件了。

配置文件路径一般为/etc/gitlab-runner/config.toml,访问它需要提升权限,示例内容为:

concurrent = 3
check_interval = 0

[session_server]
  session_timeout = 1800

[[runners]]
  name = "foo"
  limit = 1
  url = "http://git.mycompnay.com/"
  token = "af95bc59242a89b4efe24c66332a57"
  executor = "docker"
  [runners.custom_build_dir]
  [runners.docker]
    tls_verify = false
    image = "docker"
    privileged = false
    disable_entrypoint_overwrite = false
    oom_kill_disable = false
    disable_cache = false
    volumes = ["/cache", "/var/run/docker.sock:/var/run/docker.sock"]
    shm_size = 0
  [runners.cache]
    [runners.cache.s3]
    [runners.cache.gcs]

[[runners]]
  name = "bar"
  limit = 1
  url = "http://git.mycompany.com/"
  token = "eeee0ae4851d71fda2fb9d4354fff6"
  executor = "docker"
  [runners.custom_build_dir]
  [runners.docker]
    tls_verify = false
    image = "docker"
    privileged = false
    disable_entrypoint_overwrite = false
    oom_kill_disable = false
    disable_cache = false
    volumes = ["/cache", "/var/run/docker.sock:/var/run/docker.sock"]
    shm_size = 0
  [runners.cache]
    [runners.cache.s3]
    [runners.cache.gcs]

这里面的关键属性解释一下:

  1. concurrent是并发数量,代表能并发运行的最大job数量。一般需要限制concurrent的场景,是为了限制资源占用率、或为了保证顺序性。它是一个全局控制。
  2. [[runners]] 每运行一次gitlab-runner register并成功注册,就会在[[runners]]中生成一项记录。代表此runner的配置。
  3. limit是runner内部的并发限制,只有同时满足limit限制和全局concurrent限制时,才能够分配资源给job。
  4. executor、url、token等是注册时就配置的信息,不再赘述。token是处理过的token,和gitlab项目中显示的token不是同一个。
  5. [runners.docker] 当executor是docker的时候,这项配置会生效,代表对Docker runner的配置
  6. [runners.docker] 中的 image 属性是基础镜像
  7. [runners.docker] 中的volumes可用来挂载运行时volume,默认只有"/cache",多加了一个"/var/run/docker.sock"是为了能够在Docker容器内部再继续调用Docker服务。

关于更高级的配置细节,检阅Gitlab的官方文档:https://docs.gitlab.com/runner/configuration/advanced-configuration.html

前端CI中的性能优化

前言

前端CI中的一个很难绕过的问题,是node_modules的处理。现在的前端生态建立在npm之上,而npm有黑洞之称,相信这个图大家都不陌生。

npm 黑洞

当然除了node_modules以外,还会有一些其它的性能瓶颈,这些问题都会逐渐地吞噬掉CI的时间,使的一次pipeline的时间越来越久,阻塞开发部署等流程。

常见的性能问题

在实际工作中,我遇到过一些影响性能的问题,这里和大家分享一下。

  1. node_modules的安装问题
  2. docker镜像拉取速度问题
  3. gitlab cache加载和保存缓慢问题
  4. runner性能跑满,服务器压力过高,导致整体变慢问题
  5. eslint等执行过慢问题
  6. 磁盘读写过慢问题
  7. 磁盘占用过多问题

常见的解决方案

一句话总结:缓存解万愁(当然缓存也带来新的烦恼,此处暂且不提)。

具体的策略包括但不限于如下范围:

  1. Gitlab CI中的Cache机制
  2. 镜像加速
  3. Gitlab Runner中docker executor的缓存
  4. Docker cache
  5. Yarn、npm 等cache
  6. ESLint Cache(针对eslint过慢的问题)
  7. BCache(混合SSD加速)
  8. 定期清理磁盘空间

实例分享与原理剖析

node_modules的优化

node_modules的体积比较大,涉及到的磁盘I/O和网络I/O比较多,再加上国内访问npm的速度不佳,很容易成为性能瓶颈。

对它的优化主要是如下几种思路:

  1. 最彻底的,能不安装就不安装。可使用基础镜像全局安装、Docker Cache等手段
  2. 次之的,在不得不安装node_modules的时候,缓存上一次的node_modules,或使用npm cache、yarn cache等。这种方式一般会用到 Gitlab CI中的cache机制
  3. 最后,切换镜像到一个国内镜像,也有助于加速。

先说尽量不安装node_modules的方法

全局安装

假定有一个工程,CI任务中只需要处理npm发包。那有可能node_modules中只有 typescript之类的工具。

如果是这种场景的话,可以考虑全局安装typescript等工具,代替项目中安装。

从原来的

FROM node:12-alpine
WORKDIR /workspace

ADD . /workspace
RUN npm i && npm run build && publish

转换成:

FROM node:12-alpine
WORKDIR /workspace
RUN npm i -g typescript

ADD . /workspace
RUN npm run build && publish

这样就省去了 npm i 这个过程,同时因为RUN npm i -g typescript这个步骤比较容易命中Docker cache,所以大多数时候并不会重复安装依赖。

全局安装的方法,很多时候还是避免不了安装node_modules,因为有可能用到一些更复杂的,必须随项目安装的依赖,比如一个需要webpack构建之后,部署构建产物的工程,也就是常见的前端业务工程,基本都实现不了全部用全局包。

这个时候就用到了依赖前置。

依赖前置

依赖前置是为了利用Docker Cache而对Dockerfile进行的一个改进。

修改之后的Dockerfile是这种样子:

FROM node:12-alpine
WORKDIR /workspace
RUN mkdir -p /workspace

COPY ./package.json ./package-lock.json /workspace
RUN npm i

ADD . /workspace
RUN npm run build && publish

它和上面的Dockerfile相比,主要的改动是把 npm install 放在了 ADD . /workspace的前面。

按照Docker cache的原理,上面的layer如果没变,下面的RUN命令就会直接使用缓存。如果package.jsonpackage-lock.json文件没有变化,就会命中缓存,如果这两个文件中任何一个有变化,则无法命中缓存,会重新执行安装。

在大多数场景中,发生变化的是代码,而非package.json等工程配置文件。因此ADD . /workspace之后基本上无法命中缓存,而COPY ./package.json ./package-lock.json /workspace之后则大概率能命中缓存。

以上两种都是避免安装node_modules实现加速,下面介绍下其它的方案:

Gitlab CI Cache

在有yarn cache或npm cache时,安装node_modules会比全新安装快不少,因为有不少的资源可以从本地获取了。

Gitlab CI中提供了一个Cache机制,可以指定要缓存的路径,在下次执行时先加载缓存,后执行任务。

比如说一个常见的CI配置:

cache: &global_cache
  key: ${CI_COMMIT_REF_SLUG}
  paths:
    - node_modules/
    - public/
    - vendor/
  policy: pull-push

job:
  cache:
    # inherit all global cache settings
    <<: *global_cache
    # override the policy
    policy: pull

具体情况,可直接查阅官方文档https://docs.gitlab.com/ee/ci/caching/

在使用Gitlab CI Cache的时候需要注意,对于I/O压力比较高的服务器来说,CI Cache可能也会消耗较长的时间。

切换国内镜像

这一部分资源很多,此处不再赘述。可考虑使用nrm切换到taoabao等镜像源。

ESLint的优化

之前写过一篇博客专门讲这个:传送门

Gitlab Runner优化

Gitlab Runner中可以配置一些优化,我尝试过的主要是如下的方面:

  1. 通过限制资源和并发数,避免CI服务器限入激烈的资源竞争。
  2. 优先使用本地docker镜像,避免因为docker hub服务慢拖慢Runner

限制并发数

Gitlab Runner中可以设置并发数的上限,既有服务级别的,也有Job级别的。

示例配置:

concurrent = 7
check_interval = 0

[session_server]
  session_timeout = 1800

[[runners]]
  name = "hello"
  limit = 2
  url = "http://git.mycompany.com/"
  token = "mytoken"
  executor = "docker"
  [runners.custom_build_dir]
  [runners.docker]
    tls_verify = false
    image = "docker"
    privileged = false
    disable_entrypoint_overwrite = false
    oom_kill_disable = false
    disable_cache = false
    volumes = ["/cache", "/var/run/docker.sock:/var/run/docker.sock"]
    pull_policy = "if-not-present"
    shm_size = 0

如上的示例代码中,concurrent = 7代表此Runner服务最多同时跑7个Job。而limit = 2则代表hello这个job最多同时跑两个。

限制资源

限制资源是通过Docker提供的限制资源的方式,会需要较新的Docker服务版本。可以用来限制CPU、GPU、内存等资源。

如限制Docker run过程中可用的cpu资源:

docker run --cpus="1" xxx

详细使用方法参考官方文档:Runtime options with Memory, CPUs, and GPUs

优先使用本地镜像

Runner服务器的 /etc/gitlab-runner/config.toml文件中,有关于docker executor的配置,在[[runners.docker]]中,默认是始终拉最新的,可以改成优先使用本地的:

  [runners.docker]
    pull_policy = "if-not-present"

配置成if-not-present之后,如果本地有此镜像,就不会再重新查询docker hub。

磁盘的优化

CI服务器需要的磁盘空间一般都比较大,尤其是在需要npm install的时候。所以有可能服务器中使用的是机械硬盘,而非固态。而读写速度对CI的影响会比较大。

在有些时候,有可能能有一些比较小的固态硬盘,CI存储全存在上面不太现实,但可以用来做混合SSD,实现I/O方面的优化。

Linux中可以使用BCache工具制作混合SSD,参考我之前写的博文:Linux中使用小容量SSD制作混合SSD硬盘

定期清理磁盘空间

磁盘过满的时候,也会影响性能,当磁盘空间不足时,甚至会使CI服务直接停止工作。所以需要加一些清理脚本。

在使用Docker executor的时候,磁盘的占用主要是已经不再使用的Docker image,以及一些Docker volume。

要定期清理它们,可以使用下面的命令:

#!/bin/bash

# 清理镜像,保留一天
docker system prune -f --filter "until=$((1*24))h"

# 清理volume,保留三天
docker volume prune -f --filter "until=$((3*24))h"

把这个脚本随便起个名字,加上可执行权限,然后复制到/etc/cron.daily/etc/cron.hourly等目录中,实现每天清理一次或每小时清理一次的效果。

以上。

Gitlab CI的精细化控制

当CI复杂到一定程度之后,就会衍生出各种各样的细致的控制需求。Gitlab CI默认的控制器能实现一定程度的控制。

失败时继续执行后续任务

Gitlab CI中默认情况下,如果上个阶段中有任务未成功执行,则下个阶段会被取消。这是因为它默认配置了 when: on_success 的条件,只有当前面的任务完成时,才会执行后续任务。

如果想接受一个任务失败,不阻塞后续任务,有两个方式能实现:

  1. 设置此任务的属性,allow_failure: true 参考allow_failure说明
  2. 设置此任务后续任务的属性,when: always 参考when的说明

类似地,还可以设置任务失败后的后续处理等。

自动取消过时的pipeline

当提交比较频繁时,可能会产生多个pipeline排队的情况。如果每次pipeline都是可以替代之前的pipeline的,那只有最新的commit需要执行pipeline,其余的已经没有意义了。

这种情况下,可以设置Gitlab自动取消过时的pipeline。

在"Settings->CI/CD"中,找到"Auto-cancel redundant, pending pipelines",勾选上它就可以了。

失败后自动重试

Gitlab 中提供了retry选项,可以设置任务失败后自动重试,最多重试两次,即总共3次。

且失败的时候,可以限制重试的原因。示例:

test:
  script: rspec
  retry:
    max: 2
    when:
      - runner_system_failure
      - stuck_or_timeout_failure

具体的用法可参考官方文档:retry

自动取消过时的Job

Gitlab v12.3之后提供了新的控制选项:interruptible,相较于Gitlab仓库中设置的"Auto-cancel redundant, pending pipelines",它的控制维度更细,细化到了一个Job的级别。

可惜的就是依赖的版本比较高,目前还没用上过。

如果想要在旧版Gitlab中实现类似的效果,可利用webhook技术,在本文的最后部分会提到。

跳过pipeline

如果在CI中涉及到自动修改代码的场景,有可能会希望修改之后的代码不再触发CI。

这种情况下,可以在提交信息中加上[skip ci][ci skip],就可以自动跳过了。

Webhook

最后,假如有Gitlab中暂不支持的功能需求,或者用的是Gitlab旧版本,没有某个需求。可以考虑使用webhook机制,自定义控制。

关于Webhook相关的介绍,可参考Gitlab官方文档:Webhooks

它的原理,简要地说就是在Gitlab仓库的各项事件发生时,Gitlab服务器可以调用一个外部服务,将相关信息发送给它。在这个服务中,配置上Gitlab Token就可以通过API或者一些封装SDK,如nodejs中的gitbeaker,来操作Git仓库,控制它的各项内容了。

Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment