一個web的持續基礎實踐:前端
https://mp.weixin.qq.com/src=3×tamp=1494325174&ver=1&signature=wFVC0E6YlKsNsCYnhs8XlMdRTmtwBU8qMW4YCsNoryvcIAGD8hPCnOCaXb5WisyGrmEOVUJVd1n2FRjV3ohyUWuTDUGMGhkDPXAlvd6t0RtNSivqrMRgof1KJcnZrAvzTYkjURSzDPjk8wR5vq8ASUOarm9mFlUadTp8csvbGM=node
2015年10月我加入一家已盈利的創業公司,負責 Web 技術方向。創業過程當中爲了生存,都是拼快拼狠,不免選用猛糙快的工做方法。隨着業務和團隊不斷擴大,面對的問題也愈來愈具挑戰性。我逐步將一些自動化工具和方法引入到平常工做中,使團隊得到一些收益。程序員
本文總結我這一年來作持續集成的得到經驗教訓。因爲本人技術視野有限,不免考慮不周,歡迎各位同行斧正。web
我的理解:持續集成是經過平臺串聯各個開發環節,實現和沉澱工做自動化的方法。數據庫
持續集成在敏捷開發中運用得很是普遍,幾乎成了各類項目的標配。npm
我認爲持續集成是研發團隊負責人必須瞭解和掌握的方法。json
引入各類方法都是爲了解決各類問題。後端
線上代碼和代碼倉庫不一樣步,影響迭代和團隊協做瀏覽器
加盟公司後,我發現上線部署是經過 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,編寫構建任務,以便跨語言使用。各類工具須要的運行環境就不一一贅述。
工具都在不斷演進,需根據自身團隊狀況自行挑選。
若是使用 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 -- 強大的代碼塊預處理工具,輕鬆適配各類運行環境。
<!--remove trigger="release" desc="僅本機加載,構建時移除"--><script src="node_modules/mockjs/dist/mock.js"></script><script src="mock/mock.js"></script><!--/remove-->