持续集成之.gitlab-ci.yml篇

在介绍.gitlab-ci.yml以前,咱们先看几个概念:node

GitLab Runner

通常来讲,构建任务都会占用不少的系统资源 (譬如编译代码),而 GitLab CI 又是 GitLab 的一部分,若是由 GitLab CI 来运行构建任务的话,在执行构建任务的时候,GitLab 的性能会大幅降低。git

GitLab CI 最大的做用是管理各个项目的构建状态,所以,运行构建任务这种浪费资源的事情就交给 GitLab Runner 来作啦。由于 GitLab Runner 能够安装到不一样的机器上,因此在构建任务运行期间并不会影响到 GitLab 的性能。web

GitLab Runner的安装特别简单,官网有各平台的安装方法或安装包,此处再也不赘述。正则表达式

注册

  • 打开GitLab 中的项目页面,在项目设置中找到 runners
  • runner运行的机器上,用命令行注册,好比:

    gitlab-runner register --name="XX" --url="https://git.xx.com/" --token="XXX" --executor="shell"redis

按照提示一步一步安装就能够了。其中,executor能够是多种类型,简单的话能够选shell。有熟悉docker的可使用dockerdocker

  • 配置文件在/etc/gitlab-runner/config.tomlshell

    配置项相似下面,可能须要手动添加builds_dircache_dir这两个变量,再重启服务npm

    [[runners]]
       name = "216XX"
       url = "https://git.XX.com/"
       token = "XX"
       executor = "shell"
       builds_dir = "/home/gitlab-runner/builds"
       cache_dir = "/home/gitlab-runner/cache"
       [runners.cache]

常见命令

sudo gitlab-runner list 查看各个 Runner 的状态
    sudo gitlab-runner stop 中止服务
    sudo gitlab-runner start 启动服务
    sudo gitlab-runner restart 重启服务

Stages

Stages 表示构建阶段,说白了就是上面提到的流程。默认有3个stagesbuild, test, deploy。咱们能够在一次 Pipeline 中定义多个 Stages,这些 Stages 会有如下特色:windows

  1. 全部 Stages 会按照顺序运行,即当一个 Stage 完成后,下一个 Stage 才会开始
  2. 只有当全部 Stages 完成后,该构建任务 (Pipeline) 才会成功
  3. 若是任何一个 Stage 失败,那么后面的 Stages 不会执行,该构建任务 (Pipeline) 失败

Jobs

Jobs 表示构建工做,表示某个 Stage 里面执行的工做。咱们能够在 Stages 里面定义多个 Jobs,这些 Jobs 会有如下特色:缓存

一、相同 Stage 中的 Jobs 会并行执行

二、相同 Stage 中的 Jobs 都执行成功时,该 Stage 才会成功

三、若是任何一个 Job 失败,那么该 Stage 失败,即该构建任务 (Pipeline) 失败

.gitlab-ci.yml

.gitlab-ci.yml 用来配置 CI 用你的项目中作哪些操做,这个文件位于仓库的根目录。

当有新内容push到仓库,或者有代码合并后,GitLab会查找是否有.gitlab-ci.yml文件,若是文件存在,Runners将会根据该文件的内容开始build本次commit

.gitlab-ci.yml 使用YAML语法, 你须要格外注意缩进格式,要用空格来缩进,不能用tabs来缩进。

约束

任务中必须得有script部分。

示例

# 定义 stages(阶段)。任务将按此顺序执行。
stages:
  - build
  - test
  - deploy

# 定义 job(任务)
job1:
  stage: test
  tags:
    - XX #只有标签为XX的runner才会执行这个任务
  only:        
    - dev    #只有dev分支提交代码才会执行这个任务。也能够是分支名称或触发器名称
    - /^future-.*$/ #正则表达式,只有future-开头的分支才会执行
  script:
    - echo "I am job1"
    - echo "I am in test stage"

# 定义 job
job2:
  stage: test    #若是此处没有定义stage,其默认也是test
  only:
    - master    #只有master分支提交代码才会执行这个任务
  script:
    - echo "I am job2"
    - echo "I am in test stage"
  allow_failure: true #容许失败,即不影响下步构建    

# 定义 job
job3:
  stage: build
  except:    
    - dev #除了dev分支,其它分支提交代码都会执行这个任务
  script:
    - echo "I am job3"
    - echo "I am in build stage"    
  when: always #无论前面几步成功与否,永远会执行这一步。它有几个值:on_success (默认值)\on_failure\always\manual(手动执行)
    
# 定义 job
.job4:    #对于临时不想执行的job,能够选择在前面加个".",这样就会跳过此步任务,不然你除了要注释掉这个jobj外,还须要注释上面为deploy的stage
  stage: deploy
  script:
    - echo "I am job4"    

# 模板,至关于公用函数,有重复任务时颇有用
.job_template: &job_definition  # 建立一个锚,'job_definition'
  image: ruby:2.1
  services:
    - postgres
    - redis

test1:
  <<: *job_definition           # 利用锚'job_definition'来合并
  script:
    - test1 project

test2:
  <<: *job_definition           # 利用锚'job_definition'来合并
  script:
    - test2 project    

#下面几个都至关于全局变量,均可以添加到具体job中,这时会被子job的覆盖    

before_script:
  - echo "每一个job以前都会执行"    
  
after_script:
  - echo "每一个job以后都会执行"    
  
variables:    #变量
  DATABASE_URL: "postgres://postgres@postgres/my_database"  #在job中能够用${DATABASE_URL}来使用这个变量。经常使用的预约义变量有CI_COMMIT_REF_NAME(项目所在的分支或标签名称),CI_JOB_NAME(任务名称),CI_JOB_STAGE(任务阶段)
  GIT_STRATEGY: "none" #GIT策略,定义拉取代码的方式,有3种:clone/fetch/none,默认为clone,速度最慢,每步job都会从新clone一次代码。咱们通常将它设置为none,在具体任务里设置为fetch就能够知足需求,毕竟不是每步都须要新代码,那也不符合咱们测试的流程

cache:    #缓存
  #由于缓存为不一样管道和任务间共享,可能会覆盖,因此有时须要设置key
  key: ${CI_COMMIT_REF_NAME}  # 启用每分支缓存。
  #key: "$CI_JOB_NAME/$CI_COMMIT_REF_NAME" # 启用每一个任务和每一个分支缓存。须要注意的是,若是是在windows中运行这个脚本,须要把$换成%
  untracked: true    #缓存全部Git未跟踪的文件
  paths:    #如下2个文件夹会被缓存起来,下次构建会解压出来
    - node_modules/
    - dist/

验证gitlab-ci.yml

https://git.xx.com/ci/lint

跳过job

若是你的commit信息包涵[ci skip]或者[skip ci],不论大小写,这个commit将会被建立,可是job会被跳过

shell问题

使用shell脚本时,每步job一开始总有不短的等待时间,对于咱们而言是没必要要的,除去后台jenkins_build这步外,仍要最快20分钟。

以前,我曾在release分支时,暂时将各步整合到一个job里,时间缩短为5分钟。固然,这是不符合语义的。

最近,发现docker没有这个问题。因此,建议使用docker

使用docker

示例

如下是咱们项目中使用的.gitlab-ci.yml文件:

image: xx:1.0

stages:
  - jenkins_build
  - install
  - test
  - build
  - e2e
  - zip
  - copy
  - end

cache:
    policy: pull
    key: "$CI_COMMIT_REF_NAME"
    paths:
        - node_modules/
        - .eslintcache

variables:
  DOCKER_DRIVER: overlay2
  GIT_STRATEGY: "fetch"

.template: &templateDef  # 建立一个锚,'template'
  only:
      - master
      - release
      - dev

install:
  stage: install
  <<: *templateDef           # 利用锚'templateDef'来合并
  cache:
      key: "$CI_COMMIT_REF_NAME"
      paths:
          - node_modules
  script:
    - cnpm i

eslint:
  stage: test
  <<: *templateDef
  script:
    - npm run eslint

unit:
  stage: test
  <<: *templateDef
  script:
    - npm run unit

build:
  stage: build
  <<: *templateDef
  only:
      - release
  script:
    - npm run clear_dist
    - npm run build

.e2e_ci:
  stage: e2e
  <<: *templateDef
  script:
    - npm run e2e_ci

zip:
  stage: zip
  <<: *templateDef
  only:
      - release
  script:
    - npm run zip

## Jenkins 复制
jenkins_copyweb:
  stage: copy
  <<: *templateDef
  only:
      - release
  script:
    - ssh $JENKINS_SERVER_IP /jenkins/XX_copyweb.sh

## Jenkins 提交
jenkins_commit:
  stage: end
  <<: *templateDef
  only:
      - release
  script:
    - ssh $JENKINS_SERVER_IP /jenkins/XX_svn_commit.sh

## Jenkins 构建
jenkins_build:
  stage: jenkins_build
  <<: *templateDef
  only:
      - master
  script:
     - ssh $JENKINS_SERVER_IP /jenkins/build.sh

其中,XX:1.0是咱们本身建立的docker镜像,它主要安装了nodejscnpmjdksshpass,其中sshpass不是必须的,它是使用密码登录宿主机时的一种方案。

如今,咱们使用ssh来与宿主机交互,须要将容器内生成的sshkeyssh-keygen -t rsa),即/root/.ssh/id_rsa.pub中内容,复制到宿主机的/root/.ssh/authorized_keys文件中。

配置

配置文件/etc/gitlab-runner/config.toml修改成

[[runners]]
  name = "216xx"
  url = "https://git.xx.com/"
  token = "xx"
  executor = "docker"
  [runners.docker]
    tls_verify = false
    image = "xx:1.0"
    privileged = false
    disable_cache = false
    pull_policy = "if-not-present"
    volumes = ["/cache","/tmp:/tmp:rw"]
    shm_size = 0
  [runners.cache]

其中,pull_policy是下载docker镜像image的策略,默认会先从网上找,没有就报错,咱们改成先从本地找;volumes是将docker中的数据卷挂载到宿主机上。

相关文章
相关标签/搜索