阅读 962

深入浅出,前端团队的自动化部署指南 - 配置篇

上篇文章我们成功使用了Gitlab Runner执行了第一个CI程序,本文在上篇的基础上进行.gitlab-ci.yml文件的配置教程,让你可以利用CI程序轻松做到前端团队项目的自动化部署,如果还没有阅读过上篇文章,请关注 深入浅出,前端团队的自动化部署指南 - 环境篇

任务机制

CI文件中,我们可以对一系列任务做定义,每个任务至少需要包含一条可执行的语句

job1:
    script:
        - npm run build:job1
job2:
    script:
        - npm run build:job2
复制代码

你可以在 script 定义 Runner 环境可执行的所有语句,每一个任务都会按照定义顺序执行,需要注意的是,以下关键词不能用作任务名 | 关键字 | 描述信息 | | ---- | ---- | | image | 当前CI程序运行的Docker镜像 | | services | 当前CI程序使用的Docker服务 | | stages | 定义构建场景 | | types | stages 的别名 | | before_script | 定义每个任务启动前的执行脚本 | | after_script | 定义每个任务启动后的执行脚本 | | variables | 定义构建变量 | | cache | 定义构建时的缓存文件,用于之后的任务执行 |

构建场景

stages关键字用于定义构建场景,可以被构建任务引用定义自己的构建场景,stages定义的顺序也决定了任务执行的顺序,下面给出一个基本的场景示例

stages:
    - test
    - build
    - publish
复制代码
  1. 首先所有任务的构建场景为 test 的任务全部并行执行
  2. 接着会执行构建场景为 build 的所有任务
  3. 最后执行构建场景为 publish 的所有任务
  4. 其中任何一个任务失败,整个流水线会失败,并且之后的任务不会执行

stages可以不被定义,那么程序会默认为 test build deploy 三个场景,如果一个任务没有指定自己的 stage,那么它将默认使用 test

任务切面

这里所说的是 before_scriptafter_script 两个关键字,因为他们的作用类似于AOP,所以我习惯称为任务切面,切点就是所有任务的执行前和执行后 before_script会在所有任务开始之前执行,所有可以在该关键字中定义依赖环境的安装

before_script:
    - npm install
    - echo 'Install successful'
复制代码

after_script会在任务执行之后开始执行,所有可以再这里做一些通知类的操作,需要注意的是,after_script 应该是基于独立环境运行,所有该执行栈不能访问到环境中的某些变量定义和文件缓存,部署等动作建议放在 publish 或者 deploy 环节

after_script:
    - /data/bin/emitUsers.sh $CI_PROJECT_NAME $GITLAB_USER_EMAIL # 通知所有用户完成构建
复制代码

上面的 CI_PROJECT_NAME 以及 GITLAB_USER_EMAIL 是引用 Runner 程序中自带的内置变量,内置变量的种类请参考以下 CI程序内置变量

自定义构建变量

CI 程序允许你向构建过程中添加自定义变量,需要注意的是,CI 文件中定义的变量都是存储在 Git 仓库中,所以关键的路径或程序设置不应该设置在自定义变量中

你可以使用 variables 关键字定义你的自定义变量

variables:
    MY_DATA: 'This is test message'
复制代码

变量还可以单独定义在某一个任务中,仅可以在该任务使用变量

job1:
    variables:
        BUILD_PATH: '/data/web/$CI_PROJECT_NAME'
    script:
        - echo $BUILD_PATH
        - echo $MY_DATA
复制代码

使用缓存

有的时候我们需要在执行构建中多个任务之间缓存一些文件,让多个任务同时使用该缓存,比如前端项目中我们需要缓存 node_modules 文件夹, 那我们可以使用 cache 关键字如下定义,paths 关键字是一个缓存对象数组

cache:
    paths:
        - node_modules/
复制代码

cache 中的 key 属性可以用来定义缓存的作用于,如果不设置,默认为全部分支的全部任务都可以使用该策略,可以选择如下设置

cache:
    key: $CI_JOB_NAME # 不同分支的不同任务都使用该缓存
    key: $CI_COMMIT_REF_NAME # 相同分支使用同一份缓存
    key: $CI_JOB_STAGE-$CI_COMMIT_REF_NAME # 允许每个分支的每个任务通用缓存
    paths:
        - node_modules/
复制代码

cache 中还存在 policy 的相关设置,可以定义缓存在每个任务中的下载推送规则,如果设置得当,则会大量提速你的构建任务,这里不再赘述,请阅读官方文档 Cache

使用 Docker

image关键字允许当前CI程序基于某个Docker镜像中运行,当然前提是你的任务指定的tags必须是以Docker形式注册的Github Runner,CI程序会默认在你本地寻找镜像,如果不存在的话,则会从Docker Hub拉取

services关键字定义基于images运行的程序中需要依赖的其他镜像程序

总体使用Docker的方法类似于 Docker-Compose

任务机制详解

job_name:
  # 要跑的脚本或命令列表
  script:
    - npm install
    - npm run lint
  # pipelines阶段
  stage: test
  # 只针对哪个分支
  only:
    - master
  # 除了哪个分支以外
  except:
    - develop
  # 指定哪些runner适用该job
  tags:
    - fe-vue
  # 是否容错
  allow_failure: true
复制代码
关键字描述信息
script需要执行的脚本或者命令
image当前Job运行的镜像
services当前Job依赖的服务
stage任务的工作场景,默认是test
variables任务级别的变量声明
only在哪些分支生效
except除了哪些分支生效
tags设置任务使用的runners
when定义任务什么时候能被执行,可以是on_success,on_failure,always或者manual
artifacts任务级别缓存,在各个任务之间负责产物传递
environment定义任务完成的环境,一般用于在deploy后声明环境使用,在Github中可以查看环境部署
retry任务失败后的重试次数

script

用来定义一个任务中需要执行的shell脚本

script: "npm install"

# 也可以多组脚本
script:
    - npm install
    - npm run lint
    - npm run build
复制代码

image && services

与外部的关键字作用一致,不过作用于仅在当前任务

stage

定义当前任务的工作场景,通常是stages关键字中定义的一个,也可以使用默认的场景,如果忽略的话,场景默认为test

variables

在当前任务定义的变量,会覆盖掉已经声明的全局变量,如果设置了该关键字的话,在当前任务中YAML文件设置的全局变量则不生效

only && except

这两个关键字定义任务什么时候将会被创建

  1. only定义了任务需要执行的所在分支或者标签
  2. except定义了任务不会执行的所在分支或者标签

以下是这两个参数的几条用法规则:

  1. 两者如果都存在在一个任务声明中,则所需引用将会使用两者交集过滤
  2. 两者均允许使用正则

tags

指定当前任务适用的 runners

when

指定当前任务在什么时候执行,支持以下四个关键字

  1. on_success 只有在之前场景执行的所有作业成功的时候才执行当前任务,该值为默认值,也就是说如果流水线中任何一个任务失败,整个流水线将失败
  2. on_failure 只有在之前场景执行的任务中至少有一个失败的时候才执行
  3. always 总是执行
  4. manual 手动执行

artifacts

指定当前任务的产物缓存,可以用于在多个任务之间传递产物,其中也包含多种个性化设置,参考原文档

CI程序内置变量

自定义变量存在优先级策略,如果设置了相同名称的具备变量,其值可以覆盖CI的内置变量,变量的优先级排序如下,优先级从高到低

  1. Secret variables (私有变量,可以在Gitlab中手动设置,适用于所有流水线)
  2. YAML-defined job-level variables (CI 文件中定义的局部变量,例如任务中定义的变量)
  3. YAML-defined global variables (CI 文件中定义的全局变量)
  4. Deployment variables (项目变量,文档)
  5. Predefined variables (内置变量)

在这里提供 Gitlab CI 的一些内置变量,目前是基于 Gitlab 9.0 版本以上的说明,如果你发现某些变量不存在或者不符合预期,可以访问原文档查看目前的名称及含义

变量名称描述信息
CI标识该任务是在CI环境中执行
CI_COMMIT_REF_NAME用于构建项目的分支或Git tag名称
CI_COMMIT_SHAcommit 的版本号
CI_COMMIT_TAGcommittag 名称,任务对应的 tag
CI_DEBUG_TRACEdebug tracing 开启时才生效
CI_ENVIRONMENT_NAME任务的环境名称
CI_ENVIRONMENT_SLUG环境名称的简化版本,适用于DNSURLsKubernetes labels
CI_JOB_IDGitLab CI 内部调用任务的一个唯一标识
CI_JOB_NAME.gitlab-ci.yml 中定义的任务名称
CI_JOB_STAGE.gitlab-ci.yml 中定义的场景名称
CI_JOB_TOKEN用于 Gitlab Runner 仓库验证的口令
CI_REPOSITORY_URLGit 仓库地址
CI_RUNNER_DESCRIPTIONGitlab 中的 Runner 描述
CI_RUNNER_IDRunner 所使用的唯一标识
CI_RUNNER_TAGSRunner 定义的tags
CI_PIPELINE_IDGitLab CI 在内部使用的当前流水线的唯一标识
CI_PROJECT_DIR仓库克隆的完整本地地址
CI_PROJECT_ID当前项目的唯一标识
CI_PROJECT_NAME当前正在构建的项目名称
CI_PROJECT_NAMESPACE当前正在构建的项目命名空间
CI_PROJECT_PATH命名空间加项目名称
CI_PROJECT_PATH_SLUG$CI_PROJECT_PATH 的小写字母,除了0-9和a-z的其他字母都替换成-,用于地址和域名名称
CI_PROJECT_URL项目的访问地址
CI_SERVER_NAME用于协调任务的 CI 服务器名称
CI_SERVER_VERSION用于调度任务的 Gitlab 版本
ARTIFACT_DOWNLOAD_ATTEMPTS尝试运行下载 artifacts 的任务的次数
GET_SOURCES_ATTEMPTS尝试运行获取源的任务次数
GITLAB_USER_ID开启该任务的用户ID
GITLAB_USER_EMAIL开启该任务的用户邮箱
RESTORE_CACHE_ATTEMPTS尝试运行存储缓存的任务的次数

在多种环境中使用变量的时候,需要区分变量的使用方式有些许不同

  1. bash/sh >>> $variable
  2. windows batch >>> %variable%
  3. PowerShell >>> $env:variable

你也可以使用 export 关键字打印出所有的变量,需要注意的是,该关键字也会打印出任务中定义的所有私有变量

job:
    script:
        - export
复制代码

内置变量打印的例子如下

export CI_JOB_ID = '50'
export CI_COMMIT_SHA = '1ecfd275763eff1d6b4844ea3168962458c9f27a'
export CI_COMMIT_SHORT_SHA = '1ecfd275'
export CI_COMMIT_REF_NAME = 'master'
export CI_REPOSITORY_URL = 'https://gitlab-ci-token:abcde-1234ABCD5678ef@example.com/gitlab-org/gitlab-foss.git'
export CI_COMMIT_TAG = '1.0.0'
export CI_JOB_NAME = 'spec:other'
export CI_JOB_STAGE = 'test'
export CI_JOB_MANUAL = 'true'
export CI_JOB_TRIGGERED = 'true'
export CI_JOB_TOKEN = 'abcde-1234ABCD5678ef'
export CI_PIPELINE_ID = '1000'
export CI_PIPELINE_IID = '10'
export CI_PAGES_DOMAIN = 'gitlab.io'
export CI_PAGES_URL = 'https://gitlab-org.gitlab.io/gitlab-foss'
export CI_PROJECT_ID = '34'
export CI_PROJECT_DIR = '/builds/gitlab-org/gitlab-foss'
export CI_PROJECT_NAME = 'gitlab-foss'
export CI_PROJECT_TITLE = 'GitLab FOSS'
export CI_PROJECT_NAMESPACE = 'gitlab-org'
export CI_PROJECT_PATH = 'gitlab-org/gitlab-foss'
export CI_PROJECT_URL = 'https://example.com/gitlab-org/gitlab-foss'
export CI_REGISTRY = 'registry.example.com'
export CI_REGISTRY_IMAGE = 'registry.example.com/gitlab-org/gitlab-foss'
export CI_REGISTRY_USER = 'gitlab-ci-token'
export CI_REGISTRY_PASSWORD = 'longalfanumstring'
export CI_RUNNER_ID = '10'
export CI_RUNNER_DESCRIPTION = 'my runner'
export CI_RUNNER_TAGS = 'docker, linux'
export CI_SERVER = 'yes'
export CI_SERVER_URL = 'https://example.com'
export CI_SERVER_HOST = 'example.com'
export CI_SERVER_PORT = '443'
export CI_SERVER_PROTOCOL = 'https'
export CI_SERVER_NAME = 'GitLab'
export CI_SERVER_REVISION = '70606bf'
export CI_SERVER_VERSION = '8.9.0'
export CI_SERVER_VERSION_MAJOR = '8'
export CI_SERVER_VERSION_MINOR = '9'
export CI_SERVER_VERSION_PATCH = '0'
export GITLAB_USER_EMAIL = 'user@example.com'
export GITLAB_USER_ID = '42'
复制代码

结语

参照上面的配置文件设置,已经足够完成大多数的CI,CD任务,但是在个性化设置层次还略有不足,另外文字描述略显生硬,基本都是参考原文档的翻译内容,对于学习来说难度略大

下篇文章会给大家带来实战篇的CI,CD部署教程,更多细节性的策略与应用,敬请关注