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"