一個web的持續基礎實踐:
https://mp.weixin.qq.com/src=3×tamp=1494325174&ver=1&signature=wFVC0E6YlKsNsCYnhs8XlMdRTmtwBU8qMW4YCsNoryvcIAGD8hPCnOCaXb5WisyGrmEOVUJVd1n2FRjV3ohyUWuTDUGMGhkDPXAlvd6t0RtNSivqrMRgof1KJcnZrAvzTYkjURSzDPjk8wR5vq8ASUOarm9mFlUadTp8csvbGM=
背景
2015年10月我加入一家已盈利的創業公司,負責 Web 技術方向。創業過程中為了生存,都是拼快拼狠,難免選用猛糙快的工作方法。隨著業務和團隊不斷擴大,面對的問題也越來越具挑戰性。我逐步將一些自動化工具和方法引入到日常工作中,使團隊獲得一些收益。
本文總結我這一年來做持續整合的獲得經驗教訓。由於本人技術視野有限,難免考慮不周,歡迎各位同行斧正。
什麼是持續整合(Continuous integration)?
個人理解:持續整合是通過平臺串聯各個開發環節,實現和沉澱工作自動化的方法。
持續整合在敏捷開發中運用得非常廣泛,幾乎成了各種專案的標配。
我認為持續整合是研發團隊負責人必須瞭解和掌握的方法。
我們為什麼要做持續整合
引入各種方法都是為了解決各種問題。
引入持續整合之前碰到的問題
-
線上程式碼和程式碼倉庫不同步,影響迭代和團隊協作
加盟公司後,我發現上線部署是通過 FTP 直接上傳程式碼,使用檔案比較工具進行程式碼合併。由於配置不一樣,修改的人不一樣,經常導致程式碼倉庫和線上程式碼不統一。每次上線之前程式碼都要做一次線上線下手工合併。
-
靜態資源釋出依賴人工,浪費開發人力
圖片資源轉碼、壓縮、部署都需要人工介入。靜態資源的 CDN 連結也需要人工替換。
-
缺少自動化測試,產品質量得不到保障
每次上線僅僅依賴人工測試,測試用例難以覆蓋所有被影響的功能,常常出現初級的介面問題,直到產品上線使用者反饋後才能發現問題。
-
文案簡單修改上線,需要技術介入
重運營的產品,節假日均有運營活動。活動頁面的文案需要運營同學反覆推敲,頻繁修改習以為常。可每次修改文案都需要研發同學介入才能部署生效。為修改一個字,研發就需要陪運營熬到很晚。
持續整合的需求
為了解決上述這些問題,我們迫切需要改變一下工作方法,梳理需求如下。
自動化
不想把任務丟給機器執行的程式設計師不是好程式設計師!(搶月餅除外)
-
自動編譯
自動引入各種依賴(開發依賴、包依賴、配置依賴)。資源自動轉碼、合併、壓縮。自動處理配置檔案。
-
自動部署
靜態資源自動上傳 CDN 伺服器。應用檔案自動上傳和同步到應用伺服器。
-
自動測試
自動進行單元測試、整合環境測試。
-
自動監控
構建異常、測試異常、執行異常自動通知相關負責人。
團隊協作
持續整合也不僅是研發崗位需要, 測試、產品、設計師、運維等崗位一樣需要。
-
設計師更新圖片素材
設計師可以直接更新圖片資源,圖片自動切割、轉碼、上線
-
團隊成員(包括:測試、產品經理)能以最快的時間測試和體驗最新版本
第一時間部署內測版本,並自動通知團隊成員
-
運營策劃可直接修改活動、幫助文案
面向使用者的說明文件,如僅文案修改不需要介入研發人力,即可完成線上更新。
-
數值工程師可以直接更新數值配表
數值工程師指遊戲場景中設計裝備、屬性和等級數值關係的人。數值配置通常是一份 Excel 檔案。需要自動編譯、更新和推演。
適配各種執行環境
-
本機環境 local
應用能最少依賴在本機執行。能夠及時修改和預覽程式碼。能夠模擬執行環境(介面或資料)。
模擬 Ajax,推薦使用 Mock.js
-
開發環境 develop
一般 Web 專案上線前,都會有一個區域網的開發環境供團隊成員測試和體驗。開發環境有完整的沙盒資料與線上隔離。方便列印完整日誌、提供特權供。
-
線上環境 online
線上環境也叫生產環境,直接面向使用者。訪問的是真實資料,測試和體驗時需非常謹慎。
通常會上線多個版本,方便測試和回滾。
敏捷開發
-
時間上:小步快跑,推進每次迭代速度,沉澱工作方法
-
空間上:將各個崗位的工作彙集和串聯實現自動化
怎麼做持續整合
需要的工具
工欲善其事必先利其器。如今持續整合被應用得如此廣泛,必然有很多成熟的工具可以選用。
-
統一的程式碼倉庫
強烈推薦 GitLab,類似一個私有 GitHub。程式碼倉庫、里程碑、成員、靜態資源、文件、持續整合、靜態網站等等,幾乎覆蓋軟體開發需要的各項功能。
-
持續整合平臺
我們使用的是老牌持續整合平臺 Jenkins,當然也有很多後起之秀比如 Travis CI,GitLab 自身也有一套 CI 服務。
-
構建工具
Web 構建工具也是百花齊放。我們選用的是 FIS3 和 Gulp。主要是除了前端以外,我們還要處理 PHP、NodeJS、Go 等執行環境。
-
部署工具
由於多數情況使用的是 FIS 釋出,所以自己擴充套件了 FIS 部署接收器。但從效能、安全性上推薦 rsync 老牌的同步工具。
-
其他
為兼顧團隊成員同時使用 Windows 和 Mac 開發,測試、編譯環節儘量使用 NodeJS、PHP 這類跨平臺的指令碼。而在構建平臺裡我們選用 Shell,編寫構建任務,以便跨語言使用。各種工具需要的執行環境就不一一贅述。
工具都在不斷演進,需根據自身團隊情況自行挑選。
持續整合工作示意圖
建立 CI 專案
如果使用 GitLab + Jenkins 組合參考:Gitlab Hook Plugin
-
基礎設定
專案名稱、描述、任務型別等等
-
指定程式碼倉庫和相關授權使用者
指定程式碼倉庫訪問連結、有許可權拉取相關程式碼的授權使用者
-
設定構建觸發器
指定觸發型別同時在程式碼倉庫平臺(如:GitLab)新增觸發構建請求的時機和地址。
-
設定構建指令碼
設定構建指令碼,建議使用 Shell
根據自身專案特點,我們約定了幾個常用的NPM Scripts
npm run online # 構建到線上環境npm run develop # 構建到開發環境npm run stable # 構建到內網穩定版npm run debug # 啟動本機除錯
-
設定構建異常通知
指定構建負責人的郵件,當發生構建發生異常和修復時通知負責人。
收益
陸陸續續對持續整合的探索和實施,確實有一些顯而易見的收益
降低人工成本
重複繁瑣的工作可以自動化。團隊工作流程可以不斷完善和沉澱。
提高產品穩定性
部署前測試、部署後測試,測試用例覆蓋各個基本功能。測試發現和使用者反饋 Bug 可以轉為用例,持續加強測試覆蓋率。
降低程式碼維護成本
通過構建過程自動配置各種執行環境,整個開發過程均只維護一套程式碼倉庫。
加快產品迭代速度
每次程式碼文件變更均產出可體驗的版本,加速測試和體驗產品介入的時間。
構建例項
舉幾個實際的例子
網頁遊戲素材資源自動上線
換裝類遊戲,經常會添置服裝飾品。設計師提供 png 素材,由構建工具自動轉成 webp 資源釋出到 CDN。
日常活動文案更新交給運營
將運營的同學加到 GitLab 專案成員。運營同學不需要安裝其他軟體,直接在瀏覽器中修改 GitLab 專案檔案(通常是 HTML 中的文案),儲存即刻更新上線。
叢集服務自動部署和測試
高併發的 Web 應用,通常都有很多分片(可以理解為多個主機)。程式碼需要同步到各個分片上,而各個分片可能有微小差異,不一定每次程式碼迭代全都能正常執行。我們將每一個分片提出一個測試埠,上線前各個分片均做一次測試用例覆蓋,確保整合服務的穩定性。
使用成本
解決老問題的同時也會帶來新的問題。
學習和使用成本
持續整合幾乎覆蓋了開發環節和執行環境方方面面,普通專案組成員不一定都能接觸。所以我給組內的同學下放更多的內網環境許可權。當然我們也可以自行安裝相關環境。
線上環境隱私保護
線上環境的操作需要十分謹慎,一些配置有很高的保密性。包括不限於:第三方支付授權碼、第三方應用授權碼、檔案部署授權碼、資料庫使用者身份,即:各種重要的私密配置。
我們的做法是準備另一套程式碼倉庫專門管理線上配置,僅對管理員開放。
區分不同執行環境
本機執行、開發環境(個人開發環境、穩定版、開發版)、線上環境(預上線、灰度上線),都需要通過配置或環境變數區分。
構建過程自身異常
就構建本身也可能出現異常。如:構建機器軟硬體異常(網路中斷、磁碟滿了、編譯依賴升級失敗)。還有節假日不在辦公環境。
需要準備短時手工介入維護的方案,比如:預留個系統升級頁面,可以爭取時間,不容易降低使用者體驗。
錯誤覆蓋線上專案的風險
有時為趕專案進度,使用了程式設計師必殺技
Ctrl+C、Ctrl+V
。克隆構建任務也是有風險的,因為有相同的部署配置,處理不好會覆蓋之前的線上程式碼,導致線上事故。
為避免這種問題出現,我們在構建前加了一段程式碼以核對構建專案名稱
node -e 'if(require("./package.json").JOB_NAME!==process.env.JOB_NAME){console.error("JOB_NAME Error.");process.exit(1)}'
實踐經驗
定義專案
無論是前端專案還是後端專案(PHP、NodeJS、Go),我們均用 package.json
來定義。方便統一專案名稱、版本、構建指令碼的來源。
構建過程使用跨平臺的指令碼
可以選用 PHP、NodeJS、Python 等跨平臺的指令碼,方便執行到各種環境中。不建設使用 VBScript
或 JScript
,僅能在 Windows 直接執行的指令碼。
編寫小成本測試用例
編寫測試用例也不一定要引入重型的測試框架,其實只要程式以非零狀態退出就可以中斷構建過程。NodeJS 用 process.exit(1);
,PHP 用 exit(1);
構建專案規範
沒有規矩不成方圓,使用統一的規範可以更好的進行團隊協作。
比如:用 package.json
宣告專案、用 NPM Scripts
寫構建入口指令碼、用 JOB_NAME
欄位核對構建專案。
手動構建
為避免開發期成員部署專案互相干擾,特給每個成員分配一個性埠。程式碼不需要提交到倉庫,通過手動部署相應專案。
使用 jdists 配置不同執行環境
最後安利一下:jdists -- 強大的程式碼塊預處理工具,輕鬆適配各種執行環境。
<!--remove trigger="release" desc="僅本機載入,構建時移除"--><script src="node_modules/mockjs/dist/mock.js"></script><script src="mock/mock.js"></script><!--/remove-->