1. 程式人生 > >用Gitlab持續整合解放你的雙手

用Gitlab持續整合解放你的雙手

Gitlab持續整合是Gitlab提供的一整套持續整合、持續交付解決方案。Gitlab自9.0版本開始增加了CI和CD功能,所以如果你的公司裡的Gitlab上在Settings裡找不到關於CI/CD的配置項那麼你們確實該對公司的GitLab進行升級了。

我們公司之前專案部署一直在用一個叫瓦力的工具,雖然也能實現交付專案的功能但是也有不少弊端,比如:

  1. 前置任務和後置任務功能不夠強大,需要專門寫shell指令碼來完成複雜的任務。
  2. build環境永遠是一套,公司裡有的php專案用的版本有5.6、7.0、7.1 java專案以來的jdk版本不同,這些版本都會相互排斥,一旦一個版本的專案構建成功後必定會影響其他版本的專案。
  3. 構建過程和構建結果不夠視覺化。

後來公司有的專案陸陸續續開始使用GitLab CI,因為當時對這套解決方案研究不深不知道該如何在CI上進行程式碼回滾,如何管控生產環境的部署上線(比如只有許可權高的人才能部署測試環境、構建完成後想手動部署生產環境而不是push後自動部署)所以只用來做構建和部署測試環境的程式碼。與此同時執行CI Jobs的機器仍然是一臺物理機,上面需要全域性安裝了這些構建工具來完成專案構建工作,這仍然會遇到上面第二點專案程式碼版本依賴的衝突。

由於我自己現在公司一個重點專案裡做架構師,在專案開始之初就有打算將持續整合和持續交付這裡好好梳理一下,解決上面這些比較突出的問題。最近由於這些問題爆發的越來越嚴重覺得有義務拿出一套比較好的解決方案來解決這些問題所以一直在研究解決這些問題的方案。

隨著對Gitlab CI 這套方案理解的加深慢慢制定瞭如下的策略:

  1. 使用Docker來作為git runner 的executor(執行器),這樣在每個Job完成後都會清理build環境。
  2. 應用不同的docker映象來解決構建程式碼版本依賴的問題(php7的專案用php7的映象起的容器來執行構建工作,5.6的就用php5.6 映象起的容器去執行構建工作)
  3. 控制Git工作流,針對不同功能的程式碼分支分別寫CI Job去執行構建、測試和部署的工作。並且master只接受合併請求不允許任何人push, 這樣就能夠控制釋出正式環境的時間點了,而且部署操作除了push自動觸發外也可以配置成需要手動部署。

我基本上是將CI分成build , test, deploy三個階段,build裡主要就是完成專案程式碼依賴包的安裝(composer 和 npm install 之類的工作, 我們前後端是兩個專案,前端專案事先需要針對不同環境配置不同的打包命令)。

build:
  stage: build
  image: kevinyan001/git-runner:php7.1-node10
  script:
    - /usr/local/bin/composer install
  only:
    - develop
    - uat
  tags:
    - your-runner-tag

test階段會去執行專案中編寫的測試用例:

test-dev:
  stage: test
  image: kevinyan001/git-runner:php7.1-node10
  script:
    - php artisan migrate --force
    - ./vendor/bin/phpunit
  only:
    - develop
  tags:
    - your-runner-tag

deploy階段完成專案最後的部署和一些伺服器reload操作最終將專案交付上線。

deploy-testing:
  stage: deploy
  script:
    - rsync -az --delete --exclude=.git --exclude=.gitignore --exclude=.gitlab-ci.yml ./ $SERVER_TOKEN_TEST:$WEB_ROOT_TEST
    - ssh $SERVER_TOKEN_TEST -t "chown -R www:www ${WEB_ROOT_TEST}"
  environment:
    name: test
    url: http://test.example.com
  only:
    - develop
  tags:
    - your-runner-tag

git runner會在每個Job的開始階段通過映象kevinyan001/git-runner:php7.1-node10 跑一個容器,在容器中執行這些操作,等Job執行完後容器會被停止掉,這就需要我們在每次容器起來的在容器裡執行一些預備工作,比如與目標伺服器建立信任關係這些基礎的工作,我是通過將SSH PRIVATE KEY注入到容器中,目標伺服器事先放上對應的公鑰來建立容器與目標主機的信任關係的:

before_script:
  - mkdir -p ~/.ssh
  - echo "$SSH_PRIVATE_KEY" | tr -d '\r'  > /root/.ssh/id_rsa
  - chmod -R 600 ~/.ssh
  - echo "$SSH_KNOWN_HOSTS" > ~/.ssh/known_hosts
  - chmod 644 ~/.ssh/known_hosts
  - mkdir -p /etc/ansible
  - echo 'xx.xx.xxx.xxx db_master' >> /etc/hosts #make container can connect to mysql server
  - echo 'xx.xx.xxx.xxx db_slave' >> /etc/hosts

另外提供一個我寫的Laravel專案的CI配置檔案供大家參考,這是一個完全可以應用在這大型專案交付上的CI配置,實踐的時候更換成你們具體的配置,它也同時適用於除Laravel以外的其他專案只需要把不同階段執行的任務換成對應的命令即可。

kevinyan001/git-runner:php7.1-node10是我做的一個專門用來跑CI任務的容器的映象https://github.com/kevinyan81..., 你可以針對你的需求製作其他的映象。