CI/CD 是 Gitlab 提供的一整套持續集成、持續交付解決方案。html
概念:「持續集成(Continuous Integration)」、「持續交付(Continuous Delivery)」和「持續部署(Continuous Deployment)」,概念理解詳細見文章:簡單理解持續集成、持續交付、持續部署 與 談談持續集成,持續交付,持續部署之間的區別前端
近期在抽空把團隊工程化這塊作好,CI/CD只是其中的九牛一毛。在運維文開同窗協助配合下,以公司某項目前端工程作試驗,實現了 CI 的過程,本質上CD也是支持了的,主要是看CD這個過程怎麼作更好。自動觸發了構建操做,仍是直接使用構建後的 artifacts
直接部署,走不走Jenkins後續方案等……下邊簡單介紹一下。vue
前提:服務器部署配置了 Runner 。 如圖,搞了一個共享型的 Runner
,十幾個前端工程均可以基於此 Runner 執行CI腳本。由於Runner是共享的,因此gitlab-ci.yml
中的 docker 鏡像 image 建議保證每一個項目不一致,這樣就能夠共同使用一個 Runner 來並行執行多個項目CI,本質上在不一樣的 docker 鏡像中運行腳本,這樣就不會衝突了。Runner: gitlab-runnernode
下邊是舉例 Angular 前端工程 在 Gitlab 上實踐的 CI
腳本,目前只作了代碼檢查和自動構建過程檢測。實現自動化檢查代碼是否規範,前端限制了一些代碼拼寫規範、console.log禁用、alert禁用
等 tslint的約束,這些均可以在工程下自定義維護規則。aot構建是爲了進一步檢查一些編譯問題。只要二者經過,Jenkins 構建100%是無差錯的。react
配置:android
# GitLab CI/CD 前端 Angular 持續集成實踐 : https://github.com/giscafer/front-end-manual/issues/27
# 由於共享Runner,這裏不建議同樣的版本號,避免同時運行的時候,相同docker鏡像會出問題
image: node:latest
# image: node:10.4.1
# 變量定義
# https://docs.gitlab.com/ee/ci/variables/#using-predefined-environment-variables
variables:
NODE_MODULES_VERSION: 'ng-starter-web-1.0.0' # node_modules版本號,每次升級依賴改一下這裏的數值
CURRENT_BRANCH: $CI_COMMIT_REF_NAME
# 緩存目錄文件
# key是惟一值,重名會覆蓋上一次的緩存
cache:
key: '$NODE_MODULES_VERSION'
paths:
- node_modules/
stages:
- init
- lint
- build
# - deploy
install_packages:
stage: init
cache:
key: '$NODE_MODULES_VERSION'
paths:
- node_modules/
script:
# 打印一下當前是什麼分支而已
- echo "NODE_MODULES_VERSION=$NODE_MODULES_VERSION"
- echo "CURRENT_BRANCH=$CURRENT_BRANCH"
# 設置 npm 的源,會快一些
- npm config set registry http://registry.npm.taobao.org/
# 安裝全部依賴,也就是 node_modules
- npm install --silent
lint_code:
stage: lint
# 定義緩存
cache:
key: '$NODE_MODULES_VERSION'
# 下面的配置指示,咱們當前只拉取緩存,不上傳,這樣會節省很多時間
policy: pull
# 指定要緩存的文件/文件夾
paths:
- node_modules/
script:
- npm run lint
only:
- /^dev.*$/ # dev分支下只作lint語法檢查
build:
stage: build
cache:
key: '$NODE_MODULES_VERSION'
policy: pull
paths:
- node_modules/
script: npm run aot:test
# artifacets 是打包你指定的文件或者文件夾,而後你能夠經過 gitlab 的頁面進行下載的
artifacts:
# artifacets 的名字
name: '$CI_COMMIT_REF_NAME-dist'
# artifacets 的過時時間,由於這些數據都是直接保存在 Gitlab 機器上的,過於久遠的資源就能夠刪除掉了
expire_in: 60 mins
# 制定須要打包的目錄,這裏我把 dist 目錄給打包了,準備發佈到服務器
paths:
- dist/
only:
- master
#
## 部署任務
# deploy:
# stage: deploy
# # 該命令指定只有 master 分支纔可以執行當前任務
# only:
# - master
# # 部署腳本,在下面的代碼中,我用到了不少相似 ${AMAZON_PEM} 的變量,因爲咱們的私鑰、Ip 都算是不宜公開顯示的信息,
# # 因此我用到了 Gitlab 的變量工具,在 repo 的 Setting > CI/CD > Secret variables 中,這些變量值只有項目管理員纔有權限訪問
# script:
# - 'ls -la'
# - 'ls -Rl dist'
# - 'echo "${AMAZON_PEM}" > amazon.pem'
# - 'chmod 600 amazon.pem'
# - 'scp -o StrictHostKeyChecking=no -i amazon.pem -r dist/* ${AMAZON_NAME_IP}:/usr/share/nginx/html/'
複製代碼
Angular gitlab-ci.yml
配置還能夠參考:stackoverflow.com/questions/4…nginx
配置中有幾個關鍵點須要瞭解,如:git
variables
用戶能夠自定義變量或者讀取Gitlab系統自帶的變量,用來動態在腳本中獲取,也能夠根據變量寫一下if語句來執行不一樣的邏輯,以下:github
build:
stage: build
script:
- | if [ "$CI_COMMIT_REF_NAME" = "$ci_defined_secret_variable_deploy_branch" ]; then echo "build ran and conditional was true" fi except:
- master
stagetwo:
stage: deploy
script:
- | echo "stage two ran" only:
variables:
- $CI_COMMIT_REF_NAME == $ci_defined_secret_variable_deploy_branch
複製代碼
下圖是某工程下的構建配置 web
定義 stage,stage 能夠簡單的理解爲「步驟」,會順序執行,若是上一步錯了,那不會繼續執行下一步,好比像上邊定義的,第一步先 lint
檢查代碼規範,第二步構建。完整的階段劃分應該爲:第一步先初始化,第二步檢查代碼規範,第三步進行單元測試,第四步構建,第五步就直接將項目部署到服務器
GitLab CI/CD提供了一種 緩存機制,可用於在運行做業時節省時間。
定義全局的緩存策略,如上所說,每一個不一樣的 stage
,CI 都會從新啓動一個新的容器,因此咱們以前 stage
中的文件都會消失,在前端開發中,就意味着每一個 stage
都要從新完整裝一次 node_modules
,這樣的時間和網絡成本都不低,因此咱們選擇將這些文件緩存下來。
可是,緩存也要講究實效性,例如我在第二次的提交中增長了一個庫,那第二次的 CI 就不能再重複使用上一次的 node_modules
緩存了,在 .gitlab-ci.yml
中,咱們經過設置 cache
的 key
來區分不一樣的緩存,從配置中能夠看到,經過自定義變量 NODE_MODULES_VERSION 來標識 node_modules
的版本,決定是否下載新的依賴,每次工程修改依賴版本或者新增模塊時,維護一下這個NODE_MODULES_VERSION 版本號就能夠了。能夠經過監聽package.json 文件版本更新,而後腳本自動修改NODE_MODULES_VERSION版本號。如腳本:compare-pk.js
# 變量定義
# https://docs.gitlab.com/ee/ci/variables/#using-predefined-environment-variables
variables:
NODE_MODULES_VERSION: 'ng-starter-web-1.0.0' # node_modules版本號,每次升級依賴改一下這裏的數值
CURRENT_BRANCH: $CI_COMMIT_REF_NAME
複製代碼
剩下就是 Job
來定義腳本了,以上的東西都是給 Job
來使用的。下邊舉例詳細說明:
# 這個是某個任務的名稱,你能夠隨意起名
install_packages:
# 指定該任務所屬的步驟,每到一個步驟,該步驟所對應的全部任務都會並行執行
stage: init
# 指定要緩存的文件以及文件夾
cache:
# 這個屬性是 gitlab 比較新版本里面加的特性,意思是在這一步,我只上傳這個緩存,我不會拉取該緩存
policy: push
# 指定緩存的內容,在下面我緩存了 node_modules 這個文件夾,你還能夠在下面繼續添加文件或者文件夾
paths:
- node_modules/
# 該任務要運行的腳本,順序執行
# 都是 bash 命令
# 默認當前目錄就是 repo 的根目錄
script:
# 打印一下當前是什麼分支而已
- echo "CURRENT_BRANCH=$CURRENT_BRANCH"
# 設置 npm 的源,會快一些
- 'npm config set registry "https://registry.npm.taobao.org"'
# 安裝全部依賴,也就是 node_modules
- "npm install"
複製代碼
無緩存作一個lint檢查須要約 8 分鐘
有緩存則約一分半
更多配置項介紹見官方文檔yaml/README
PR: pull request 或 merge request
每次提交或者 PR
都會自動觸發 job:lint
,PR
在代碼lint或者測試沒有經過的狀況下,是默認沒法合併的(按鈕禁用,權限大的用戶才能跳過檢查,但不建議,除非你想出錯)。
更方便的是,PR
能夠設置爲腳本執行經過後自動合併,固然若是須要 CR (code review)
的話,能夠設置爲手動合併。 若是連測試都沒有經過的代碼,就沒有必要 CR
了。
能夠在 master 分支作持續交付操做(CD), 主要就是自動化構建;將構建成功結果物,經過腳原本部署便可。若是還有後期的自動化接口或者組件測試,部署後執行測試,若是失敗則回滾。按理是測試成功的代碼,部署後就通常沒有問題,除非是環境和數據引發的問題。
由於 master 分支是 dev 或者 test 分支 PR 合併過來的,因此他們的測試和代碼檢查通常都經過了的,固然,合併以前也會從新執行一次代碼檢查和測試,最後纔會走構建的job。
Gitlab 的 Pipeline
下能夠看到每次提交觸發Job的執行狀態,能夠對執行日記查看,對應job執行成功或失敗均可以發生通知給開發者。
持續交付在持續集成的基礎上,將集成後的代碼署到更貼近真實運行環境的「類生產環境」中。好比,咱們完成單元測試後,能夠把代碼部署到鏈接數據庫的 Staging 環境中更多的測試。若是代碼沒有問題,能夠繼續手動部署到生產環境中。
從頻繁提交代碼、自動化測試(保證測試覆蓋) -> 運行本地測試 -> 服務器運行測試 -> 部署到測試環境 -> 交付管理
而這些都應該是自動的,因此你須要知道的東西有: 如何編寫測試(Junit、Qunit、BDD、TDD..)、自動化測試(Selenium..)、版本管理(git)、配置(feature toggle)、依賴管理、部署腳本等等。
從0起作好持續交付並不容易,涉及不少東西,從簡單的作起吧。自動觸發了構建操做,目前如何自動部署,走不走 Jenkins 後續方案討論再定。能夠保留 Jenkins 手動構建(出問題能夠規避),也能夠有自動化構建部署兩種方案都有
後邊又嘗試了Gitlab Pages的CI/CD,構建後上傳到遠程服務器:
image: node:10.4.1
variables:
NODE_MODULES_VERSION: 'wiki-web-1.0.0' # node_modules版本號,每次升級依賴改一下這裏的數值
CURRENT_BRANCH: $CI_COMMIT_REF_NAME
# 緩存目錄文件
# key是惟一值,重名會覆蓋上一次的緩存
cache:
key: '$NODE_MODULES_VERSION'
paths:
- node_modules/
stages:
- build
- deploy
build:
stage: build
cache:
paths:
- node_modules/
script:
- npm install --silent
- npm run build
artifacts:
name: 'dist'
expire_in: 60 mins
paths:
- dist
# - docs/.vuepress/dist
only:
- master
deploy:
stage: deploy
environment:
name: Production
before_script:
# - sed -i '/jessie-updates/d' /etc/apt/sources.list
# https://superuser.com/questions/1423486/issue-with-fetching-http-deb-debian-org-debian-dists-jessie-updates-inrelease/1424377#1424377
- printf "deb http://archive.debian.org/debian/ jessie main\ndeb-src http://archive.debian.org/debian/ jessie main\ndeb http://security.debian.org jessie/updates main\ndeb-src http://security.debian.org jessie/updates main" > /etc/apt/sources.list - apt-get update -qq && apt-get install -y -qq sshpass script:
- cd dist/
- ls
- sshpass -V
- export SSHPASS=$USER_PASS
- sshpass -e scp -P 端口 -o stricthostkeychecking=no -r . root@IP:/data/git_cd
# - sshpass -e scp -o stricthostkeychecking=no -r . username@host.com:/var/www/html
# - rsync -avz --delete -e"ssh -p 端口" ./ root@ip:/data/git_cd
when: on_success
only:
- master
複製代碼
是一個基於 vuepress
的工程,CI 自動構建後,會將打包後的 dist文件夾
上傳到 artifacts
, CD 操做的時候從這裏那就行了。
構建生成的附件能夠經過 sshpass
或 rsync
將附件上傳到遠程服務器。相關文章能夠參考:
Android 和 IOS CI 環境搭建參考:
以上是網友的分享文章,前半部分工做主要是搭建 Runner 和 docker 環境,有更快速的方式來搭建。我在搭建 android 環境時,使用了共享性 Runner,image選用的是開源社區的 react-native-community/ci-sample docker 鏡像,而後配置對應的執行腳本便可。越過了繁瑣的 android 環境搭建,這就是 docker 的好處了。
經常使用的有如下幾種:
分享兩個來自 ProcessOn 網友分享的 Jenkins CI/CD 流程圖:
把Runner搞成共享型的,前端的工程就不須要重複配置Runner了,後續逐步的改善便可。一個完整的ci配置應該包含這些過程:第一步先初始化,第二步檢查代碼規範,第三步進行單元測試,第四步構建,第五步就直接將項目部署到服務器
。
整合 DevOps,CI/CD 實現是必須的,目前市場和工具方案都特別成熟,我的認爲,小團隊或者大團隊都有必要去學習掌握,以便改善團隊的效能問題。一切能腳本自動化的工做,都不該該人工參與。不管如何,頻繁部署、快速交付以及開發測試流程自動化都將成爲將來軟件工程的重要組成部分。
歡迎討論~
推薦:
Author: @giscafer,原文地址:front-end-manual/基於 GitLab CI 的前端工程CI/CD實踐 , 歡迎討論