Gitlab CI/CD教程及npm包構建釋出實戰

MangoGoing發表於2022-03-14
!!!實踐過程中請留意文件版本號跟你實際使用Gitlab的版本號

??中文文件-14.8-pre

??Gitlab版本—12.9

前置知識

  1. yaml語法,教程??YAML 入門教程
  2. Docker相關知識,教程??Docker教程
  3. linux命令,教程??Linux 命令大全

自定義配置目錄

預設配置檔案目錄是在mono repo的根目錄,檔名為.gitlab-ci.yml

若需要自定義設定CI指令碼檔案的路徑,如下:

Xnip2022-03-12_09-17-36

流水線配置

.gitlab-ci.yml檔案中對流水線配置大致可以分為2個環節:

  1. 全域性配置,執行在單個stage之前或者之後。
  2. 單個stage配置

結構大致可以如下:

# 指定指令碼執行的映象環境,如下為node環境為14.17.1
image: node:14.17.1

# 單個job執行之前執行
before_script:
  - echo '====== 準備構建中 ========='

# 配置單個stage的執行順序,序列
stages:
  - install
  - build

# 單個stage配置
# 安裝依賴
npm_install:
  only:
    - master
  stage: install
  script:
    - yarn
    - ls -al

# 單個stage配置
# 構建
webpack_build:
  only:
    - master
  stage: build
  script:
    - yarn build

# 單個job全部執行完之後執行
after_script:
  - echo "====== 構建結束 ========="

重要概念

Pipeline

流水線,一次流水線相當於一次構建任務,裡面可以包含多個階段,比如install -> eslint -> build -> deploy等流程 ;

stages

表示構建階段,每個stage序列同步執行。一旦有一個stage中的一個job失敗了,那麼下一個stage的任務便不會執行。如果當前stage定義了多個任務,那麼其中一個任務失敗,另外一個任務還是會被繼續執行。但是隻有當所有 stages 成功完成後,該構建任務 (Pipeline) 才算成功。

jobs

job表示某個stage裡面執行的工作 ,一個stage裡面可以定義多個job 。

jobs有如下特點 :

  • 相同 stage 中的jobs 會並行執行
  • 相同 stage 中的 jobs 都執行成功時,該 stage 才會成功
  • 如果任何一個job 失敗,那麼該 stage 失敗,即該構建任務 (Pipeline) 失敗

gitlab runner

執行構建任務的一個服務,裡面包含了持續整合的的環境,一般由docker建立。它可以在不同的主機上部署,也可以在同一個主機上設定多個gitlab-runner ,還可以根據不同的環境設定不同的環境,比如我們需要區分研發環境,測試環境以及正式環境等。

關鍵字

image

CI/CD指令碼執行環境的docker映象,映象就是一種檔案儲存形式,可以理解為是一個環境的集合,內含多種檔案。如指定node環境映象:

# 最新版本node環境
image: node:@latest

tags

指定gitlab 在執行指令碼時使用哪個runner。

before_script

在單個stage執行之前執行的指令碼內容,內容以陣列形式配置,如上例子中:

before_script:
  - echo '====== 準備構建中 ========='

stages

CI允許我們進行自定義的流水線階段配置,可以將一個流水線拆分為多個階段(stage),stages會序列執行。

stages:
  - install
  - build

script

執行指令碼,指令碼內容以陣列形式配置。如上例子中stage為npm_install階段執行的指令碼為:

script:
    - yarn
    - ls -al

先執行yarn命令安裝依賴,結束後檢視了當前目錄下檔案及目錄的具體資訊,是個序列執行的過程。

cache

快取多個流水線任務之間共用的檔案和目錄,快取相關概念下文詳情講述。

only & except

設定流水線任務執行時機:使用 only 來定義job何時執行,使用 except 定義job 執行的時間。

  • 指定分支觸發執行時機

    job:
    
      only:
        - branches@gitlab-org/gitlab
      except:
        - main@gitlab-org/gitlab
        - /^release/.*$/@gitlab-org/gitlab

    此示例為 gitlab-org/gitlab 上的所有分支執行 job,除了 main 和以 release/ 開頭的分支。

  • 在合併請求時觸發

    job1:
      script:
        - echo "This job runs in merge request pipelines"
      only:
        - merge_requests
  • 在push的時候觸發

    job1:
      script:
        - echo "branch push"
      only:
        - pushes
  • 手動觸發

    在Gitlab Runner/pipeline裡面點選run pipeline時觸發

    job1:
      only:
        - web
  • 根據git提交訊息或者判斷分支觸發執行時機

    build:
      script: 
          - yarn build
      except:
        variables:
          - $CI_COMMIT_MESSAGE =~ /test/ || $CI_COMMIT_BRANCH == "main"

    git commit 訊息為”test“的push跟提交分支為”main“的push不觸發此job。

  • 根據檔案修改判斷執行時機

    build:
      script: yarn build
      except:
        changes:
          - "*.md"

    只要有md檔案修改就不執行此job。

retry

job重試次數,預設為0,最大重試次數為2,其中when可設定在特定失敗原因的情況下執行。

rules:if

此欄位可以在單個流水線job或者workflow欄位下進行配置。

rules關鍵詞下可以進行if語句配置,如果if滿足的話可執行某些自定義配置。

rules:
  - if: $CI_COMMIT_REF_NAME =~ /feature/

注意: only & exceptrules:if都是用來決定單個job執行時機的,在配置時只能存在一個,否則會報錯。

workflow

rules配合用來控制流水線的執行動作,在最外層進行配置,workflow: rules 接受這些關鍵字:

  • if:檢查此規則以確定何時執行流水線。
  • when:指定當if為 true 時要做什麼。

    • 要執行流水線,請設定為 always
    • 要阻止流水線執行,請設定為 never
  • variables:如果未定義,則使用在別處定義的變數。適用版本13.11 ~14.0

當沒有規則為 true 時,流水線不會執行。

以下示例中,前兩天規則都匹配到不執行時機,當else時,流水線執行。

workflow:
  rules:
    - if: '$CI_PIPELINE_SOURCE == "schedule"'
      when: never
    - if: '$CI_PIPELINE_SOURCE == "push"'
      when: never
    - when: always

when

控制上一個stage成功或者失敗時,當前stage的行為。

  • on_success(預設值): 上一個stage成功了才會執行當階段任務,或者之前失敗的任務配置了allow_failure: true
  • on_failure :只有上一個階段任務失敗了才會執行當前任務。
  • always:無論上一個階段的jobs狀態如何,都會觸發當前階段的任務。
  • never:不執行當前任務。
  • manual:在gitlab網頁中手動點選觸發。

模組化

使用關鍵字include引入其他yml檔案中的配置。

include:
  - '/yml/job1_install.yml'
  - '/yml/job2_lint.yml'
  - '/yml/job3_build.yml'
  - '/yml/job4_deploy.yml'

快取

重要概念

在 GitLab CI/CD 中,我們所使用的 runner 是以 docker 的形式執行不同的任務。普通的 cache 機制(即不指定URL,No URL provided, cache will not be downloaded from shared cache server. Instead a local version of cache will be extracted. ),其 cache 是儲存在本地,所以如果兩個 job 實際執行的位置是不在宿主機上的,其相互之間的快取是無法共享的。

分散式快取

分散式快取需要runner配置支援,開啟後需要在cache中配置s3ServerAddress、s3BucketName等資訊進行快取跨runner共享。

快取路徑

在配置cache時,pathsfiles的檔案/目錄都是以專案的根目錄為相對位置的,在store cache的時候也是以專案名區分快取路徑的,應用快取的時候會在專案下配合key值去應用快取,即使是分散式快取也是按照這個策略。

image-20220311091210653

快取檔案資訊上會有最後更新時間(重要資訊)、檔案許可權、cache中設定的key等,其中更新時間跟快取策略有聯絡,如果惡意篡改伺服器時間,可能會出現依賴前後不一致導致打出來的包不符合預期的情況。

快取繫結檔案

快取繫結到當前版本的檔案。當這些檔案之一發生變化時,將計算一個新的快取鍵並建立一個新的快取,如下:

cache-job:
  script:
    - echo "This job uses a cache."
  cache:
    key:
      files:
        - Gemfile.lock
        - package.json
    paths:
      - vendor/ruby
      - node_modules

此時的 key 是根據最近更改了每個列出的檔案的提交計算得出的 SHA。如果在任何提交中都沒有更改任何檔案,則key就是預設值 default

多檔案快取

cache可以配置多個key,適用於13.10 ~ 13.12版本,其他版本可以在key下的filespaths配置多個路徑/檔案來實現。

禁用快取

使用cache: {}來禁用快取。

繼承快取

快取配置可複用的情況下使用繼承寫法,可以在當前job下覆蓋(重寫)某個策略或者設定優先順序

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

job:
  cache:
    # 繼承全域性快取
    <<: *global_cache
    # 重寫快取策略
    policy: pull

回退快取鍵

13.4版本以上可應用回退快取鍵,功能類似快取備份。你可以使用 CACHE_FALLBACK_KEY 變數來指定一個備份快取key,他會在你指定key的快取不存在時去查詢應用備份快取。

variables:
  CACHE_FALLBACK_KEY: fallback-key

job1:
  script:
    - echo
  cache:
    key: "$CI_COMMIT_REF_SLUG"
    paths:
      - binaries/

手動清除快取

您可以在 GitLab UI 中清除快取:

  1. 在頂部欄上,選擇 選單 > 專案 並找到您的專案。
  2. 在左側邊欄上,選擇 CI/CD > 流水線 頁面。
  3. 在右上角,選擇 清除 Runner 快取

在下一次提交時,您的 CI/CD 作業使用新的快取。

實戰:構建釋出元件庫到npm倉庫

編寫.gitlab-ci.yml基本流程,如下:

image: node:14.17.1

before_script:
  - echo '====== 準備構建中 ========='

stages:
  - install
  - lint
  - build
  - deploy

### 配置快取
cache:
  key:
    files:
      - package.json
      - packages/ghost-weapp-ui/package.json
  paths:
    - node_modules/
    - packages/ghost-weapp-ui/node_modules/
    ### 直接快取.npm,.npm中快取了所有依賴,因為gitlab快取是分專案的,所以兩種方法個人覺得沒有什麼區別
    # - .npm/

# eslint檢測
job_lint:
  only:
    - master
  stage: lint
  before_script:
    - echo 'eslint檢測'
    - ls -a
  script:
    - cd packages/ghost-weapp-ui
    - ls -a
    - yarn lint
    - echo 'eslint檢測完成'
  retry: 0
  when: 'on_success'

# 安裝依賴
job_install:
  only:
    - master
  stage: install
  before_script:
    - echo '安裝依賴'
  script:
    - yarn config set registry https://registry.npm.taobao.org/
    - yarn install
    - cd packages/ghost-weapp-ui
    - ls -a
    - yarn install
    - ls -a
    - echo '依賴安裝完成'
  retry: 0

# 打包編譯
job_build:
  only:
    - master
  stage: build
  before_script:
    - echo '開始打包'
  script:
    - cd packages/ghost-weapp-ui
    - ls -a
    - yarn
    - ls -a
    - yarn build
    - echo '構建完成'
  when: 'on_success'
  retry: 0

# 釋出
job_deploy:
  only:
    - master
  stage: deploy
  before_script:
    - echo '更新補丁版本,準備釋出'
  script:
    - cd packages/ghost-weapp-ui
    - node deploy.js ${CI_COMMIT_REF_NAME}
  when: 'on_success'
  retry: 0

after_script:
  - echo "====== 釋出完成 ========="

編寫部署指令碼,其中主要是模擬npm login流程替換為使用token進行登入並且執行npm publish,釋出到npm的流程。

const fs = require('fs')
const path = require('path')
const os = require('os')
const { exec } = require('child_process')

// 替換為自己npm賬號的authToken
// token獲取方法:vim ~/.npmrc 
const npmrcText = `registry=https://registry.npmjs.org/
home=https://www.npmjs.org
//registry.npmjs.org/:_authToken=${authToken}
`

// 獲取命令中第三個引數,此例子中為'master'
// node deploy.js ${CI_COMMIT_REF_NAME}, 分支名為master
const env = process.argv[2]

// 拼接命令,執行npm publish,打tag
function deploy() {
    fs.writeFileSync(path.resolve(os.homedir(), '.npmrc'), npmrcText)
    const argsArray = ['publish'].concat(['--tag', env === 'master' ? 'latest' : 'beta'])
    execa('npm', argsArray);
}

async function execa(a, arry = []) {
    return new Promise((resolve, reject) => {
        exec(`${a} ${arry.join(' ')}`, (err, stdout, stderr) => {
            if (err) {
                console.error(err);
                reject(err);
            }
            resolve(stdout)
        })
    })
}

deploy();

執行結果:

Xnip2022-03-12_17-53-36

收到npm釋出成功反饋郵件:

image-20220312175447181

以上就是gitlab CI/CD的相關知識點以及實戰釋出npm包的示例,感謝閱讀!

相關文章