前端的gitlab的ci初嘗試

小落發表於2018-05-22

本文記錄一個前端部署Gitlab的CI。不是在自己的伺服器上面搭建的Gitlab。使用的是Gitlab.com的Gitlab的CI,在騰訊雲擼的羊毛的小水管也搭不起Gitlab,做個CI的伺服器還是能勉勉強強的。

Gitlab和Github

Github 一個網站,提供給使用者空間建立git倉儲,儲存使用者的一些資料文件或者程式碼等。

Gitlab 一個基於git實現的線上程式碼倉庫軟體,你可以用Gitlab自己搭建一個類似於Github一樣的系統,一般用於在企業、學校等內部網路搭建Git私服。

什麼是持續整合

阮一峰的這個文章寫的挺好的持續整合是什麼?

持續整合指的是,頻繁地(一天多次)將程式碼整合到主幹。

持續整合的目的,就是讓產品可以快速迭代,同時還能保持高質量。它的核心措施是,程式碼整合到主幹之前,必須通過自動化測試。只要有一個測試用例失敗,就不能整合。

Gitlab的CI

從 GitLab 8.0 開始,GitLab CI 就已經整合在 GitLab 中,我們只要在專案中新增一個 .gitlab-ci.yml 檔案,然後新增一個 Runner,即可進行持續整合。 而且隨著 GitLab 的升級,GitLab CI 變得越來越強大。

首先明白Gitlab CI 幾個基本的概念

GitLab-CI

這個是一套配合GitLab使用的持續整合系統,是GitLab自帶的,也就是你裝GitLab的那臺伺服器上就帶有的。無需多考慮。.gitlab-ci.yml的指令碼解析就由它來負責。

GitLab-Runner

這個是指令碼執行的承載者,.gitlab-ci.yml的script部分的執行就是由runner來負責的。GitLab-CI瀏覽過專案裡的.gitlab-ci.yml檔案之後,根據裡面的規則,分配到各個Runner來執行相應的指令碼script。這些指令碼有的是測試專案用的,有的是部署用的。

前端的gitlab的ci初嘗試

.gitlab-ci.yml

這個是在git專案的根目錄下的一個檔案,記錄了一系列的階段和執行規則。GitLab-CI在push後會解析它,根據裡面的內容呼叫runner來執行。

簡單來說就是,你利用Git版本管理Push了原生程式碼到Remote上(這裡就是你gitlab.com),然後Gitlab,就通知你的伺服器,也就是Gitlab-runner來執行構建任務。然後跑測試用例,測試用例通過了就生成Build出相應的環境的程式碼,自動部署上不同的環境伺服器上面去。

安裝Gitlab Runner

如果想要使用Docker Runner,則需要安裝Docker。(可選)

curl -sSL https://get.docker.com/ | sh
複製程式碼

安裝 GitLab Runner 太簡單了,按照著 官方文件 的教程來就好拉! 下面是 Debian/Ubuntu/CentOS 的安裝方法,其他系統去參考官方文件:

# For Debian/Ubuntu
$ curl -L https://packages.gitlab.com/install/repositories/runner/gitlab-ci-multi-runner/script.deb.sh | sudo bash
$ sudo apt-get install gitlab-ci-multi-runner
# For CentOS
$ curl -L https://packages.gitlab.com/install/repositories/runner/gitlab-ci-multi-runner/script.rpm.sh | sudo bash
$ sudo yum install gitlab-ci-multi-runner
複製程式碼

然後註冊Gitlab Runner Runner需要註冊到Gitlab才可以被專案所使用,一個gitlab-ci-multi-runner服務可以註冊多個Runner。

在 GNU/Linux 系統上註冊 Runner:

執行下面命令啟動註冊程式:

sudo gitlab-runner register
複製程式碼

輸入 GitLab 例項 URL:

Please enter the gitlab-ci coordinator URL (e.g. https://gitlab.com )
https://gitlab.com
複製程式碼

輸入獲取到的用於註冊 Runner 的 token:

Please enter the gitlab-ci token for this runner
xxx //這個token在你gitlab.com的專案的 setting >> CI/CD >> Runners settings 下
複製程式碼

前端的gitlab的ci初嘗試
輸入該 Runner 的描述,稍後也可通過 GitLab's UI 修改:

Please enter the gitlab-ci description for this runner
一個配置很低的伺服器
複製程式碼

給該 Runner 指派 tags, 稍後也可以在 GitLab's UI 修改:

Please enter the gitlab-ci tags for this runner (comma separated):
tengxun // 這個就相當於每一個runner的唯一id,記住這個tag。
複製程式碼

選擇 Runner 是否接收未指定 tags 的任務(預設值:false), 稍後可以在 GitLab's UI 修改:

Whether to run untagged jobs [true/false]:
[false]: true
複製程式碼

選擇是否為當前專案鎖定該 Runner, 之後也可以在 GitLab's UI 修改。 該功能通常用於被指定為某個專案的 Runner (預設值:true):

Whether to lock Runner to current project [true/false]:
[true]: true
複製程式碼

選擇 Runner executor:

Please enter the executor: ssh, docker+machine, docker-ssh+machine, kubernetes, docker, parallels, virtualbox, docker-ssh, shell:
docker  // 我選擇的docker,請記住,選擇docker的之前要把docker啟動,docker的使用就不是本文所講的了
複製程式碼

如果你選擇 Docker 作為你的 executor,註冊程式會讓你設定一個預設的映象, 作用於 .gitlab-ci.yml 中未指定映象的專案:

Please enter the Docker image (eg. ruby:2.1):
alpine:latest
複製程式碼

然後,你重新整理你setting下面的配置

前端的gitlab的ci初嘗試
有個綠色的小圓點,這就表明你已經註冊Runner成功了。

配置.gitlab-ci.yml

配置好 Runner 之後,我們要做的事情就是在專案根目錄中新增 .gitlab-ci.yml 檔案了。 當我們新增了 .gitlab-ci.yml 檔案後,每次提交程式碼或者合併 MR 都會自動執行構建任務了。

在.gitlab-ci.yml有一些需要講解的概念

Pipeline

一次 Pipeline 其實相當於一次構建任務,裡面可以包含多個流程,如安裝依賴、執行測試、編譯、部署測試伺服器、部署生產伺服器等流程。我們的任何提交或者 Merge Request 的合併都可以觸發 Pipeline。如下圖:

+------------------+           +----------------+
|                  |  trigger  |                |
|   Commit / MR    +---------->+    Pipeline    |
|                  |           |                |
+------------------+           +----------------+
複製程式碼

Stages

Stages 表示構建階段,說白了就是上面提到的流程。 我們可以在一次 Pipeline 中定義多個 Stages,每個Stage可以完成不同的任務。 Stages有下面的特點:

  • 所有 Stages 會按照順序執行,即當一個 Stage 完成後,下一個 Stage 才會開始
  • 只有當所有 Stages 完成後,該構建任務 (Pipeline) 才會成功
  • 如果任何一個 Stage 失敗,那麼後面的 Stages 不會執行,該構建任務 (Pipeline) 失敗

因此,Stages 和 Pipeline 的關係就是:

+--------------------------------------------------------+
|                                                        |
|  Pipeline                                              |
|                                                        |
|  +-----------+     +------------+      +------------+  |
|  |  Stage 1  |---->|   Stage 2  |----->|   Stage 3  |  |
|  +-----------+     +------------+      +------------+  |
|                                                        |
+--------------------------------------------------------+
複製程式碼

Jobs

Jobs 表示構建工作,表示某個 Stage 裡面執行的工作。 我們可以在 Stages 裡面定義多個 Jobs,這些 Jobs 會有以下特點:

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

所以,Jobs 和 Stage 的關係圖就是:

+------------------------------------------+
|                                          |
|  Stage 1                                 |
|                                          |
|  +---------+  +---------+  +---------+   |
|  |  Job 1  |  |  Job 2  |  |  Job 3  |   |
|  +---------+  +---------+  +---------+   |
|                                          |
+------------------------------------------+
複製程式碼

這些是部署指令碼里面的一些基本結構,接下來說一些.gitlab-ci.yml的基本構成

下面是一個最簡單的Node專案的部署指令碼。

image: node:alpine  // 預設的ci部署的docker映象

stages:  // 首先按順序定義有幾個步驟。步驟下面的所有job是同步執行的
  - test  
  - build
  
job1:
  stage: test  // 屬於test的stage
  script:
    - npm run test // 這個job執行的指令碼
  only:
    - master  // 只監聽master分支的程式碼提交
  tags:
    - tengxun  // 要使用哪個runner

job2:
  stage: build
  script:
    - npm run build
  only:
    - master
  tags:
    - tengxun

複製程式碼

注意這裡的job1,job2名字是隨便取的,沒有關係,只要不用Gitlab-CI的關鍵字就可以。

列出一些常用的關鍵字,掌握了這些就可以開發了。

關鍵字 是否必須 描述
image 用於docker映象,檢視docker文件
services 用於docker服務,檢視docker文件
stages 定義構建階段
types stages 的別名(已廢除)
before_script 定義在每個job之前執行的命令
after_script 定義在每個job之後執行的命令
variable 定義構建變數
cache 定義一組檔案列表,可在後續執行中使用

發現這篇文章對每個關鍵字對解釋的好清楚,算是個拋磚引玉吧。比我寫的都還要清楚。

Gitlab CI yaml官方配置檔案翻譯

配置之前,你還要在你gitlab.com的對應專案裡面的setting >> CI/CD >> Secret variables 定義一些構建變數,因為你的Gitlab-CI要去自動的登入伺服器,然後把打包出來的檔案自動更新上去。

Runner 登入你的伺服器是不能用傳統輸入賬號密碼的形式,(因為都自動化了,還需要輸入密碼,那還叫什麼自動化)。只能通過走SSH登入的形式,如果不懂SSH登入,請自行谷歌。私鑰這些東西肯定不能寫在yml檔案裡面,因為yml檔案是每個人都能看見的,所以Gitlab-CI就可以在專案裡面自定義私有的變數名。至少專案開源出去之後,不是每個人都能看見部署伺服器的私鑰的。

前端的gitlab的ci初嘗試

這裡的$SSH_PRIVATE_KEY 是你開發機(也就是你的的開發電腦)生成的私鑰。 注意一定要複製

-----BEGIN RSA PRIVATE

-----END RSA PRIVATE KEY-----
複製程式碼

這些東西。(這裡是個坑。。。因為很少會讓你複製私鑰的) 下面配置的${CI_COMMIT_REF_NAME},是Gitlab CI 的預設關鍵字。詳情見文件

最後貼上我那個騰訊雲小水管的配置,親測有用。

還真是一個很簡單的vue專案。就用vue-cli生成,然後釋出到伺服器上面指定的目錄,伺服器上面的nginx配置已經配置好了。

stages:
  - test
  - build
  - deploy

cache:
  key: ${CI_COMMIT_REF_NAME}
  paths:
  - node_modules/

test_dev:
  image: node:alpine
  stage: test
  only:
    - dev
  tags:
    - tengxun
  script:
    - npm run test


build:
  image: node:alpine
  stage: build
  only:
    - master
    - dev
  tags:
    - tengxun
  script:
    - npm set registry https://registry.npm.taobao.org # 設定淘寶映象地址
    - npm install --progress=false
    - npm run build
  artifacts:  
    expire_in: 1 week
    paths:
      - dist

deploy_dev:
  image: alpine
  stage: deploy
  only:
    - dev
  tags:
    - tengxun
  script:
    - echo "http://mirrors.aliyun.com/alpine/v3.7/main/" > /etc/apk/repositories
    - apk add --no-cache rsync openssh
    - mkdir -p ~/.ssh
    - echo "$SSH_PRIVATE_KEY" >> ~/.ssh/id_dsa
    - chmod 600 ~/.ssh/id_dsa
    - echo -e "Host *\n\tStrictHostKeyChecking no\n\n" > ~/.ssh/config
    - rsync -rav --delete dist/ "$SERVER_USER_HOST:$SERVER_DEV_PATH"

deploy_master:
  image: alpine
  stage: deploy
  only:
    - master
  tags:
    - tengxun
  script:
    - echo "http://mirrors.aliyun.com/alpine/v3.7/main/" > /etc/apk/repositories
    - apk add --no-cache rsync openssh
    - mkdir -p ~/.ssh
    - echo "$SSH_PRIVATE_KEY" >> ~/.ssh/id_dsa
    - chmod 600 ~/.ssh/id_dsa
    - echo -e "Host *\n\tStrictHostKeyChecking no\n\n" > ~/.ssh/config
    - rsync -rav --delete dist/ "$SERVER_USER_HOST:$SERVER_MASTER_PATH"
  when: manual
複製程式碼

這裡用rsync來同步Build出來的程式碼,其實也很簡單的。

rsync 是一個開源工具,可以進行快速的增量的檔案傳輸。相關文章

簡單來說就是讓你源計算機和目標計算機進行檔案的同步。

附上rsync的翻譯的文件 點我

在GitLab-CI中, cache與artifacts比較容易混淆.

其中 cache 指的是快取, 常用於依賴安裝中, 如幾個jobs都需要安裝相同的依賴, 可以使用依賴, 此時可以加快依賴的安裝進度; 對於artifacts則是將某個工件上傳到GitLab提供下載或後續操作使用, 由於每個job啟動時, 都會自動刪除.gitignore中指定的檔案, 因此對於依賴安裝目錄, 即可以使用cache, 也可以使用artifacts.

兩個主要有以下幾個區別:

  • 雖然定義了cache, 但是如果cache和.gitignore中重複的這部分, 仍然需要重新安裝
  • 重新安裝時因為使用的是快取, 所以很有可能不是最新的
  • 特別是開發環境, 如果每次都希望使用最新的更新, 應當刪除cache, 使用artifacts, 這樣可以保證確定的更新
  • artifacts中定義的部分, 會自動生成, 並可以傳到下面的job中解壓使用, 避免了重複依賴安裝等工作 如果使用Docker執行Gitlab-Runner, cache會生成一些臨時容器, 不容易清理
  • artifacts可以設定自動過期時間, 過期自動刪除
  • artifacts會先傳到GitLab伺服器, 然後需要時再重新下載, 所以這部分也可以在GitLab下載和瀏覽

因為我們這裡要重複使用之前job打包出來在dist下面的檔案,所以我會使用artifacts。

when: manual

這裡master一般是值穩定的程式碼版本,所以最好手動執行的。when: manual就是需要手動部署,所有job預設都是自動執行的。

魯迅曾經說過:有國內加速映象地址的一定要用國內映象地址

這裡的映象地址配置包括Docker,APK,NPM。一定要設定啊,當時就卡在這裡了很久。

然後我們push程式碼到master,點選你專案的CI/CD皮膚。

前端的gitlab的ci初嘗試
然後小水管過了2分鐘才跑完Build,扎心了。

前端的gitlab的ci初嘗試
點選右面的那個播放三角形,就可以部署到我的那個騰訊雲伺服器上面去了。(當然,dev分支是預設自動部署和的),這就開始構建了。

好啦,一個簡單的前端CI嘗試就完了。

that's all。

參考資料

gitlab之gitlab-ci自動部署 GitLab 中文文件 Gitlab CI yaml官方配置檔案翻譯 用 GitLab CI 進行持續整合

相關文章