兩年前在開始一個新的商業專案時我花了兩個星期時間在專案開發流程中應用上了持續整合,隨後一年又隨著專案的發展和商用化做了很多改進。所以掌握了GitLab 持續整合這套方案在商業軟體中完整的落地實踐經驗。文章最早釋出在其他平臺,當時引起了不少關注,內容雖然是對一個用PHP Laravel
框架開發的專案持續整合的設定,但是整個持續整合是完全容器化的,這套方法論可以很方便的應用於任何程式語言的專案。
關注文章下方公眾號,關鍵字回覆CI可以獲取完整的持續整合方案的編排檔案和容器的Dockerfile 原始碼。
GitLab CI/CD
Gitlab持續整合是Gitlab提供的一整套持續整合、持續交付解決方案。Gitlab自9.0版本開始增加了CI和CD功能,所以如果你的公司裡的Gitlab上在Settings裡找不到關於CI/CD的配置項那麼你們確實該對公司的GitLab進行升級了。
我們公司之前專案部署一直在用一個叫瓦力的工具,雖然也能實現交付專案的功能但是也有不少弊端,比如:
- 前置任務和後置任務功能不夠強大,需要專門寫shell指令碼來完成複雜的任務。
- build環境永遠是一套,公司裡有的php專案用的版本有5.6、7.0、7.1 ,java專案依賴的jdk版本不同,這些版本都會相互排斥,一旦一個版本的專案構建成功後必定會影響其他版本的專案。
- 構建過程和構建結果不夠視覺化。
後來公司有的專案陸陸續續開始使用GitLab CI,因為當時對這套解決方案研究不深不知道該如何在CI上進行程式碼回滾,如何管控生產環境的部署上線(比如只有許可權高的人才能部署測試環境、構建完成後想手動部署生產環境而不是push後自動部署)所以只用來做構建和部署測試環境的程式碼。與此同時執行CI Jobs的機器仍然是一臺物理機,上面需要全域性安裝了這些構建工具來完成專案構建工作,這仍然會遇到上面第二點專案程式碼版本依賴的衝突。
由於我自己現在在公司一個重點專案裡做架構師,在專案開始之初就有打算將持續整合和持續交付這裡好好梳理一下,解決上面這些比較突出的問題。最近由於這些問題爆發的越來越嚴重覺得有義務拿出一套比較好的解決方案來解決這些問題所以一直在研究解決這些問題的方案。
隨著對Gitlab CI 這套方案理解的加深慢慢制定瞭如下的策略:
- 使用Docker來作為git runner 的executor(執行器),這樣在每個Job完成後都會清理build環境。
- 應用不同的docker映象來解決構建程式碼版本依賴的問題(php7的專案用php7的映象起的容器來執行構建工作,5.6的就用php5.6 映象起的容器去執行構建工作)
- 控制Git工作流,針對不同功能的程式碼分支分別寫CI Job去執行構建、測試和部署的工作。並且master只接受合併請求不允許任何人push, 這樣就能夠控制釋出正式環境的時間點了,而且部署操作除了push自動觸發外也可以配置成在GitLab專案頁面裡手動點選按鈕來部署。
我基本上是將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
說明:
- 任務中的
$SERVER_TOKEN_TEST
這些是提前在GitLab專案的Settings --> CI/CD Pilelines裡定義的變數,執行任務時容器會在BASH SHELL中讀入這些預先定義的變數。 $SERVER_TOKEN_TEST
裡設定的內容是user@server_ip
,${WEB_ROOT_TEST}
裡設定的是專案在服務端的路徑。- 我在容器的映象裡安裝了ansible, 釋出正式環境時使用ansible將專案部署到正式環境對應的多個主機上。
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
具體可以參考gitlab ci關於這一塊的說明文件:https://docs.gitlab.com/ee/ci/ssh_keys/
由於GitLab CI的功能非常多,可配置像也很多所以具體某個配置的作用我就不細說了,貼幾個我認為比較有用的說明文件出來節省大家的搜尋時間。
https://docs.gitlab.com/runner/register/
https://docs.gitlab.com/ee/ci/
https://docs.gitlab.com/ee/ci/examples/lar...
https://docs.gitlab.com/ee/ci/yaml/#jobs
https://docs.gitlab.com/ee/ci/environments...
kevinyan001/git-runner:php7.1-node10
是我做的一個專門用來跑CI任務的容器的映象,已經上傳到了 Docker 官方的映象源中可以直接使用。你可以針對你的需求製作其他的映象。關注下面公眾號回覆CI可以獲得源版的Dockerfile。
Conclusion
GitLab CI/CD提供了一套通用的解決方案讓你從最初的Coding開始到最後程式碼交付上線都能在它提供的工具集合中輕鬆完成,通過Git Runner的Executor執行不同階段定製的任務進行程式碼build、整合測試、和部署上線。除此之外還可以幫我們完成API文件生成、程式碼檢查、Wiki文件構建等工作,只要在Linux Bash Shell中能實現的任務它都能幫你實現。它支援用很多不同型別的Executor來執行CI Jobs,其中我最推薦使用的型別是Docker Executor,這樣我們的build環境就不依賴於Git Runner宿主機上的環境,從而能夠應用不同容器完成各種不同專案的構建工作。
本作品採用《CC 協議》,轉載必須註明作者和本文連結