1. 程式人生 > >Gitlab-Runner原理與實現

Gitlab-Runner原理與實現

應用場景:

通過技術手段保證gitlab中專案某個版本的可用性,當我想釋出新版本時隨實可以tag出一個可用的版本。與github配套的是travis,使用非常簡單,只需要將github賬戶與travis繫結就可以選擇保護的專案及版本,但是要在gitlab上實現類似的功能就只能靠自己來搭建了,今天就來介紹下gitlab-runner是如何工作的。

 

Gitlab/GitHub使用規範

示意圖:

注意事項:

1 Maintainer職責是最重要的,負責程式碼的review、approve merge、關心test結果,是master程式碼質量的第一負責人。

2 通過gitlab-runner執行pipeline,可以根據自己的需要編寫複雜度不同的pipeline,初期只用在單元測試即可,fork版中的測試環節是非必需的,master版本中的測試環節是必須的。

 

Runner的實現原理:

示意圖:

Runner分為共享型(Shared Runner)和特享型(Specific Runner),因為gitlab專案語言種類和執行環境複雜多樣,我們選用Specific Runner型。

 

 Gitlab與Runner的整合:

 專案中新增.gitlab-ci檔案定義runner要做的事情,tag決定哪個runner來執行。

 

實現細節:

1 安裝gitlab

    在centos7上安裝最新版本gitlab,我的版本是GitLab Enterprise Edition 11.3.4-ee

#安裝依賴:
sudo yum install postfix
sudo systemctl enable postfix
sudo systemctl start postfix

#安裝企業版gitlab
sudo yum -y install gitlab-ee

#修改gitlab訪問地址和埠號(external_url)
sudo vi /etc/gitlab/gitlab.rb

#配置修改生效
sudo gitlab-ctl reconfigure

 按照自己配置的external_url去訪問gitlab,首次登陸需要設定administrator的密碼

2 安裝 runner

  Runner分為共享型(Shared Runner)和特享型(Specific Runner)兩種,共享型可以被gitlab上所有project公用;特享型繫結project只被指定使用。

  由於我的業務java、php、python各種語言都有,每條產品線執行環境也存在差異,所以傾向採用Specific Runner

  Runner可以安裝在獨立的vm內,也可以安裝在容器內,這裡的Specifig Runner我們執行在docker中。

  注意:runner不要與gitlab安裝在一起,註冊發現會有問題。

  2.1 準備docker環境

  docker的安裝以前博文有介紹過,這裡不再詳解,重點是獲取gitlab/gitlab-runner這個image。

  2.2 啟動gitlab-runner

sudo docker run -d --name gitlab-runner --restart always \
  -v /srv/gitlab-runner/config:/etc/gitlab-runner \
  -v /var/run/docker.sock:/var/run/docker.sock \
  gitlab/gitlab-runner:latest

  2.3 註冊runner到gitlab 

  先在gitlab的CI/CD頁面找到url和token,如圖

#進入容器
sudo docker exec -it gitlab-runner /bin/bash
#容器中完成註冊
gitlab-runner register \
  --non-interactive \
  --url "http://10.100.129.113:8090" \
  --registration-token "S1Erstg39-nh1xQVMtBN" \
  --executor "docker" \
  --docker-image maven:latest \
  --description "193runner " \
  --tag-list "193" \
  --run-untagged \
  --locked="false"

重要引數說明:

    url和token參考上圖,在runner需要對接的gitlab中獲得;

    executor是runner中pipeline以什麼方式執行,這裡選擇的是docker方式,其實還支援shell等其它方式。

    docker-image是runner中pipelne以哪個image為基礎來執行executor。

    tag-list是runner的tag,在gitlab的project中關於ci的配置檔案中會引用得到。

Runner註冊成功後就會在gitlab的CI/CD頁面看到下圖中的紅框內容:

如果出現灰色的runner說明runner雖然註冊上來但是不可用,當gitlab與runner安裝在同一臺機器時就會出現這種情況,所以請儘量分開。

3 在gitlab的專案中配置gitlab-ci

    在專案根目錄下新增.gitlab-ci.yml檔案,gitlab-ci很強大,本質就是以yml的格式定義了一個pipeline,與jenkins存在功能重疊的部分,由於我們只是利用runner做專案master版本的單元測試,所以只需要在gitlab-ci中執行maven test。

     .gitlab-ci.yml內容如下:

image: maven:latest

stages:
  - test

job_test:
  stage: test
  script:
    - mvn test
  tags:
- '193'

4 配置user的許可權

限制只有maintainers才可以push和merge專案的master版本

 

5 測試驗證

  專案準備 maven-jdk1.8-Junit,可以在我的GitHub中直接下載:https://github.com/yejingtao/runproject.git

  驗證步驟:

  5.1 maintainers直接操作

   以maintainers使用者直接push,成功,同時觸發pipeline。

  5.2 developer操做

     5.2.1 模擬直接提交

     用developer使用者clone出runproject專案,直接push,因許可權不足失敗。

     5.2.2 fork 提交push到自己

     Developer使用者從runproject專案中fork出自己版本,直接push可以成功,因為他是自己版本的maintainer

     5.2.3 發起PR

     Developer修改程式碼並push到自己fork專案後,發起PR

     5.2.4 maintainer使用者mergePR

     Maintainer登陸gitlab後會看到RP通知,有兩種merge方式:

     下拉列表第一種是Developer自己的fork版本通過pipeline測試後再merge進master版本;第二種是直接merge進master版本。無論選擇哪一種,都會觸發master版本的一次pipeline。

     因為我們的目的只是保證master版本的可用性,所以推薦第二種。

     5.2.5 master revert本次操作

    如果merge一次PR後pipeline沒有通過或者其他形式發現程式碼不可用,可以在PR頁面找到當此PR,執行Revert。

Revert的本質其實就是以老版本重新發起一次PR,所以Revert後也會觸發一次pipeline。

6 細節注意:

  1 .gitignore中記得要把.gitlab-ci.yml新增進去,不要被隨意修改。

  2 如果要通過mvn test來做單元測試需要嚴格按照框架的命名規則,例如Junit預設測試Test結尾的類。

  3 Executor Image的選擇要給予自己專案的場景,對於Specific Runner由研發自定義docker的image,可以提高執行效率。

 

Maven的依賴:

每次pipeline利用maven做單元測試時都會重新拉取程式碼的依賴包,如果有辦法利用volume等手段快取依賴的話可以提高測試效率。

理解了前面的原理,快取的設定需要做兩部份工作:1如何在docker中通過volume讓maven的倉庫可以直接在宿主機上掛載;2如何在gitlab-ci中進行配置。

volume掛載:

修改/srv/gitlab-runner/config/config.toml檔案,我們從前面docker命令-v就可以看得出修改這裡其實就是在修改runner容器中註冊的問題件,修改如下:

[[runners]]
  name = "193runner"
  url = "http://10.100.129.113:8090"
  token = "327781c1630cef378aa4c62441a4e4"
  executor = "docker"
  [runners.docker]
    tls_verify = false
    image = "maven:latest"
    privileged = false
    disable_cache = false
    volumes = ["/var/runcache:/cache:rw"]
    shm_size = 0
  [runners.cache]
    [runners.cache.s3]
    [runners.cache.gcs]

volumes這一行是關鍵,把宿主機的/var/runcache目錄掛在到maven executor容器的/cache碟符下,並賦予讀寫許可權。 

gitlab-ci配置:

在.gitlab-ci.yml中新增如下幾行:

variables:
  MAVEN_OPTS: "-Djava.awt.headless=true -Dmaven.repo.local=./.m2/repository"

cache:
  paths:
    - ./.m2/repository

對比下優化的效果:

優化前:

優化後:

可以看到效率得到明顯的提高,再讓我們看下宿主機的/var/runcache中到底有什麼:

可以看到/var/runcache/${gitlab_username}/${project_name}/default目錄下有個cache壓縮檔案,解壓后里面就是.m2倉庫檔案了,裡面就是專案快取的依賴包了。

你可以修改專案的pom.xml新增新的依賴,再來這個cache中看下就可以確定自己的猜測了。 

gitlab版本問題: 

gitlab與runner的版本需要匹配使用,如果版本不匹配會出現runner無法註冊、runner註冊後無法連線、runner無法執行executor等一系列莫名其妙的錯誤。

例如我公司由於歷史包袱的原因,現在使用的gitlab是企業版8.1,我就在搭建這套環境中吃夠了苦頭。

1 gitlab-runner是9.0以後的產品,它的前身是gitlab-ci-multi-runner,所以用gitlab-runner是無法註冊成為gitlab的runner的,像我的gitlab8.1版本的gitlab-ci-multi-runner對應的是1.8.5版本,下載地址:https://packages.gitlab.com/runner/gitlab-ci-multi-runner/packages/fedora/21/gitlab-ci-multi-runner-1.8.5-1.x86_64.rpm

2 .gitlab-ci.yml中的cache是gitlab8.2版本新增的屬性,所以在我公司的版本中會報無法識別的錯誤,需要去掉。如果你想多個maven的executor之間共享local repository,可以修改config.toml中的volume,把宿主機的一個目錄掛到executor的容器中去,然後在config.toml的variables中指定maven的本地倉庫,例如:MAVEN_OPTS: "-Djava.awt.headless=true -Dmaven.repo.local=/root/.m2/repository"