持續集成之.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中的數據卷掛載到宿主機上。

相關文章
相關標籤/搜索