關注若川視野, 回復"pdf" 領取資料,回復"加群",可加群長期交流學習
一、前言
大家好,我叫鰻魚,這次分享的主題是如何從 0 到 1 打造適合自己的構建部署方案。
先例行的自我介紹,大概 14 年開始接觸前端,曾經在菜鳥實習過,現在是在百度我也不知道算啥 title 的前端開發,帶了個小團隊。前兩期在女生職業發展道路上已經分享過一次,然后當時說過自己對工程化這一塊興趣比較大,相信懶是程序員的美德之一,這次又過來做一次分享。
這次的話題其實說大不大,說小也有很多零零散散的東西可以講,自己公司內部也有一定的實戰經驗甚至完善的平臺。不過調研發現其實大部分中小型公司并沒有專門的人去折騰這些事情,也不知道怎么做或者說沒精力搞那么復雜的東西。
所以這次分享的話題可能比較輕松,剛好大家午休時間,可以邊吃飯邊看,也不用那么燒腦。主要受眾可能是一些對構建部署還停留在聽說過,但是沒有實際用過的偏小白。時間關系也沒有像其他講師畫那么多高大上的架構圖。但是會比較細粒度的解析構建部署的過程,希望能幫助形成一個大體的概念,便于梳理能去選擇合適自己的方案。具體的平臺實現還可以參考其他講師們的 PPT,也都非常不錯。
這次主體大致包含兩部分:
第一塊就是,為什么我們要花那么多功夫去做構建部署的事情。
第二塊是我們可以怎么去做,分為構建和部署兩個部分。
二、為什么要做?
項目開發流程
從前端進入現代社會之后,無論是看社區論壇還是各種分享,都能看到各種各樣講構建部署的東西。那么它到底有什么魔力吸引大家都紛紛駐足呢?我們可以從項目的整體結構來看,前端其實就是軟件開發交付過程中的一個小小的環節而已。通常來說,一個互聯網軟件開發的流程如下:
大多數都是本地編碼完畢,然后執行 npm run build
? 去做打包構建,通過一定的方式推送到一個測試環境去看看有沒有問題。遇到 bug 就改 bug,沒有 bug 就喊相關人員驗收,并進行部署上線。這整個流程可能有自動化的部分,也有手動的部分,每個團隊應該多少都有點區別 ,通常來說自動化程度跟團隊規模還有業務復雜度都有關系。
但是業務如果持續發展,可能一般都會經歷一個過程,就是剛開始我覺得這么玩玩就好了,我覺得好像也沒什么問題,實際上會變得越來越復雜。
我們理想中,可能會覺得 A 項目做完了,就上到 A 項目的服務上去,B 做完上到 B 的服務,C 做完上到 C 的服務 但是實際情況下,可能會出現不同的項目模塊,有相互依賴的關系,比如 B 服務要在 A 上線之后才能上線,D 又依賴 C,最可怕的還是相互依賴,遞歸依賴,傳說中依賴黑洞的現象。那么,這可能會出現什么問題呢?
軟件危機
我們看幾個歷史上的實際的例子,都是計算機早期的時候真實發生的故事:
美國銀行信托軟件系統開發案:美國銀行 1982 年進入信托商業領域,并規劃發展信托軟件系統。項目原訂預算 2 千萬美元,開發時程 9 個月,預計于 1984 年 12 月 31 日以前完成,后來至 1987 年 3 月都未能完成該系統,期間已投入 6 千萬美元。美國銀行最終因為此系統不穩定而不得不放棄,并將 340 億美元的信托賬戶轉移出去,并失去了 6 億美元的信托生意商機。
阿麗亞娜-5 運載火箭爆炸事件:96 年 6 月,阿麗亞娜-5 運載火箭首次測試發射,在發射后 37 秒被迫自行引爆,原因由于 64 位的運算錯誤地變為 16 位的運算,造成程序崩潰,火箭感測角度失常,從而觸發自毀裝置的啟動。
以上軟件問題均出現在計算機誕生早期的時候,計算機剛剛投入實際使用,軟件的規模比較小,很少使用系統化的開發方法。但是由于計算機的飛速發展,軟件系統的規模越來越大,復雜程度越來越高,產生的問題也越來越突出。其實在早 1968 年的時候,北大西洋公約組織在一次國際會議上,就已經創造了軟件危機這一詞,并且連續召開過幾次會議,提出了軟件工程的概念。
那么軟件危機是什么呢?那與我們今天要說的工程化或者構建部署有什么關系呢?
其實它需要解決的基本上是一類問題,主要是日益龐大的軟件系統,其復雜度已經遠超我們人腦可以直接控制的程度,很難說我們靠人力靠時間就能比較好的去保證所有東西都是沒問題的。
那么對于前端來說,他面領哪些問題呢?當你代碼寫久了可能會有一些感覺,我們日常遇到的技術問題可能少一些或者說好解決一些,但是工程問題反而較多,而且大多缺乏系統性和通用性。
比如說我們要開發一款完整的 Web 應用時,我們不光要書寫 HTML/CSS/JS 之類的,來完成功能的開發。也將會面臨更多的工程問題,比如:
體量比較大的系統,有很多功能,有很多頁面,有各種狀態,要怎么去把他們組織起來;
再比如對于大型系統多人團隊,我們作為承上啟下的環節,怎么去比較好的進行多人甚至多團隊合作開發;
再有就是我們經常說的性能優化問題,比如說 CDN 部署、緩存控制、按需加載、首屏渲染等等。
所以,這個時候其實我們就需要工程化了,前端工程化的定義就是借助軟件工程的技術、方法和思想,來優化前端側的流程、效率和規范等。參考網上將前端工程化分四個能力點:規范化、模塊化、組件化、自動化,個人是比較認同。
但是其中的每個點要細講,都能牽扯出不少的東西,這次的分享只是講其中的一部分,就是如何自動化,更具體來說是構建部署階段的自動化。
工程化&自動化
說到自動化,有一個可能都聽說過的詞,CI/CD。但是他具體是指帶什么?我們看一下:
CI/CD 是指在應用開發過程中,通過自動化手段來頻繁向客戶交付應用的方法。核心概念是持續集成、持續交付和持續部署。
CI(Continuous Integration)簡稱持續集成,原意是各個開發者在開發過程中,需要將代碼集合到一起,比如我們的 GitLab,GitHub 等。現在大多會包含集成之后,自動觸發編譯,測試等過程,幫助開發者及時收集問題。
CD(Continuous Delivery)指的是持續交付和持續部署,經過 CI 后,代碼自動部署到服務器上的一個過程。
然后看一下市面上對于項目的開發流程過程中,會涉及到的一些常見的平臺(這里是網上找的一張圖比較糊,沒來得及找高清的,大概看一下后面都會有詳細說明):
代碼托管:我們有 GitHub/GitLab/還有國內的碼云,Coding 之類的平臺;
構建:對于 Java 有 Maven,對于前端是 npm;
集成:有 Jenkins,Travis,測試對于前端是 Mocha/Jest 之類的工具;
部署:物理機/虛擬機/Docker K8s 等等。
CI/CD 主要是自動化地在云端平臺去完成這些事情。一方面來說像早上冬冬說的保持環境的一致性,提高構建部署的穩定性。另外一方面就是通過自動化去減少重復機械的勞動。
所以從收益來講,肯定是項目越多,模塊關系越復雜,帶來的收益越明顯。
三、怎么做?
第二個環節,我們大概知道了要做什么,那么具體怎么做呢?
構建篇
首先是構建,剛剛說過,構建指從本地開發提交到代碼庫,以及完成遠程構建,自動化測試等一系列的過程。我們按順序來看:
首先,當你完成一個功能,本地看著沒問題之后,去做 git commit 的時候,從自動化的角度來說,我們可以做什么事情?
這里有一個很重要的點,也是會貫穿構建流的一個點。就是我們要知道,git 不光只是代碼存儲,還有一系列鉤子,能允許你在特定的時期,做一些想做的事情。例如 precommit,就是代碼提交前,我們可以用它來做一些本地代碼檢查,比如 ESLint,再有比如自動化測試,在檢查通過之后再允許代碼提交。通常對于前端來說,我們會結合 husky 來使用。
作為一個合格的校驗系統,當然不光只是讓用戶自己做本地檢查就夠了,畢竟在某些特殊狀態下,大家可以有各種手段去繞過自己的檢查。因此對于一些關鍵平臺或者項目,就需要服務端檢查的東西了。比如目前我們自己這邊的系統,在代碼提交之后但是還沒入庫之前,會自動的去做一些復用率檢查,安全掃描等等,這個就是 pre-receive 鉤子可以做到的事。當然,對于一些小型系統這個環節其實可以直接跳過。
另外,我們可能還會有 Code Review 環節,代碼被人審查過之后才允許合入。以及在合入之后,也能有一定事件,比如去通知合作方及時更新代碼,去通知流水線繼續走后續構建的流程等等。
當我們提交完代碼,作為一個合格的 CI 系統,還需要做什么事情呢?就是打包構建了。
這里的打包其實就是 npm run build
? 的過程,只是執行的環境不是你本地的機器,而是換成了在線的統一環境的機器,比如項目測試環境的機器,公司內統一的編譯機等。但是他做的事還是一樣的。
通常大多數情況來說,我們執行 npm run build
? ,然后去拿 dist 的產物就結束了。但是實際如果你玩 CI 的過程中,你很有可能遇到一些環境不一致,版本不一致等莫名其妙報錯的問題,這個時候如果你能對構建過程有一定了解,在定位問題層面可能就能有一定幫助了。
比如在現代化前端的演進中,我們早就從解釋性語言,變成了半編譯型語言。因此在打包核心功能時就是要把我們自己理解的代碼,變成瀏覽器可認識的代碼,這里舉個實際的例子。
比如對于 TypeScript 的代碼,我們有 Interface,有變量類型定義,轉化器也是會先將它解析成 AST 的語法樹,具體解析成啥樣有個在線的網站可以查詢,具體的解析原理其實網上也很多資料,然后根據 AST 去掉給我們看的內容,變成可執行的 JS 代碼。
當然在編譯過程中,肯定不止是代碼轉換這么簡單,很多時候我們有很多很多其他的配置,例如 icon,我們可能需要把零零散散分散在各處的圖標,生成 iconfont 或者雪碧圖。還有代碼合并壓縮,靜態變量替換等等,具體可能會做什么事情,以 Webpack 為例,可以參照其常見的 loader。
總的來說,當我們執行 npm run build
? 的時候,無論你用什么工具什么方式,我們核心需要把零零散散的資源打包匯總到一起,讓其可執行。
那么常見的打包工具有哪些呢?比如早一點的有 Browserify,Gulp,Grunt,新一點的有 Webpack,Rollup,Parcel 等等。
打包這塊好了,那 CI 的一個核心點,是自動化,就是在代碼提交之后能自動去運行打包的腳本,而不是我在本地打包之后一起提交帶代碼庫里面。
通常來說我們可以去選擇各大平臺提供的現成工具,例如 Travis CI,這是一個跟 GitHub 強集成的 CI 平臺,對于一些開源項目,或者自己想要練練手的時候,就可以用它去玩了。左邊是一份它的 CI 的配置文件,大致功能就是能配置在什么階段,可以去做什么事情。
另外還有 Jekins,這是一個開源的基于 Java 的一種持續集成平臺,對于一些私有化部署的項目應該算是用得非常多的一個平臺了。還有基于 GitLab 內置的平臺,國內的幾個代碼托管平臺好像也有類似的服務。當然對于一些大型公司,還會有自研的平臺,這里就不細說。
具體要怎么選?個人覺得:
對于一些中小型團隊,建議直接找市面上成熟的工具,然后結合這次大家的分享,可以做一些簡單的封裝;
對于成熟度比較高業務復雜的大型團隊,有較強的技術中臺或者有專門的人力去做這一塊的事情的話,可以考慮自研或者高度定制化。
具體怎么做?無論哪種方式,其實他的思路都差不多,自研需要的東西也很簡單:
首先,你要有一個運行環境,就是能讓你執行
npm run install
? 和npm run build
? 不會報錯的地方。無論是物理機,還是虛擬機,還是容器都沒問題。其次,你需要一個代碼托管平臺,無論是現成的,還是自己私有化搭建的,只要能保證以能執行 git 的各種鉤子就行。
然后大致的一個流程,當你提交代碼之后,可能會去做一些本地檢查,這個應該是配置在項目代碼庫中的,比如用 husky 結合 ESLint 做代碼規范性檢查。檢查過了之后,git 會自動推送代碼到遠程代碼庫,這個時候可以結合服務端的 git-hook
? 做檢查,當然沒有也沒問題。
當你收到代碼提交通知的時候,需要有一個 Web hook 連接通知到你配置的可用編譯環境里面,告訴它我有新的代碼提交了,你可以開始一系列后續任務。那么通常來說編譯機會要做什么呢?首先需要將代碼 clone 下來,并安裝所需要的依賴,對于前端來說就是 npm install
?,然后去打包就是 npm run build
?。這樣你在服務器上就已經得到了你想要的產出,構建過程就已經完畢。
看起來是不是覺得很簡單 :)
但是當系統復雜度升高,業務多了之后,實際情況可能會遇到的一些思考點,也是我們目前有的一些東西,這里只是拋出來大家可以想一想。
首先 Git hook 觸發方式,代碼提交了之后是自動觸發的,那怎么去做到定時觸發,怎么去在一個代碼庫編譯完了之后,通知另外一個代碼庫去做編譯。其次還有分支,有時候我們只想 dev 分支去做自動編譯,master 分支需要有特殊控制,怎么去更好的監聽分支的變化,除了精確匹配是否還可以有前綴匹配,正則匹配等方式。再有就是實際業務是怎樣的,我需要用到哪些鉤子等等...
然后在編譯構建層面,可能還會涉及到,環境變量有哪些,不同流程之間怎么做到一些通用變量共享。我們實際有哪些環境,比如說 node8,node10,怎么去特定換定編譯,怎么切換?
編譯所有都串型感覺太慢了,我們怎么去做并行編譯。機器對編譯產物怎么去存儲,是否有定時清理機制過期時間等,還有一些異常的處理,超時機制,各種檢查具體怎么做?
這些都是一些細節問題,也沒辦法在此次分享給出一個標準答案。它是一個跟業務密切相關的過程,只要做了多多少少都會碰到這些問題。但相信對于一些積極思考熱愛學習的同學,比如能周末來聽早早聊的,應該能自己去探索得出答案。
部署篇
然后部署,當我們拿到了產出,怎么把產出給弄到不同的環境,怎么優雅的上線,也是一個值得思考的問題。
我們再看看歷史,一直在說前后端分離不分離,那么具體常見的前后端合作模式有哪些呢?
前后端完全不分離,前后端在一個代碼庫里面,前端在本地跑的時候很有可能要配置后端的服務環境,提交代碼后端幫忙一起部署;
前后端代碼庫分離了,但是部署到機器中還是在同個服務內,這個時候可能我們會把代碼產出本地打包丟給后端,或者說通過一系列自動化工具直接推到服務器對應的靜態資源目錄里面;
前端后端代碼分離了,部署也都分離開了,前端這個時候通常來說可能就是一個簡單的 HTTP,中間可能通過一些后端路由轉發的形式做關聯;
對于一些現在的大型團隊,可能前端不直接跟后端對接,還會有一個 BFF 中間層去做一些轉發配置,甚至身份校驗之類的事情。
以上,應該是一個前端開發的歷史進程的縮影,我們來來回回的折騰,看著越來越復雜,但是其實無論哪種,部署都是大同小異的。
來看看我們的目標,最前面也有說,所謂的構建部署,就是把各種手動操作的東西,變成自動化規范化的流程。
因此我們的目標,就是需要把曾經手動丟服務器,需要多人協同操作口口相傳的這種情況。變成能由較少人可以操作,由工具去幫我們自動做分發,部署之類的事情,從而來提高部署的效率和穩定性。
具體怎么丟,其實很簡單,可以理解成是一個文件上傳的過程。所以無論你使用 FTP,還是有個 HTTP 請求的接口,都沒什么大的問題,這里不做仔細描述。
那么我們遇到的問題可能是什么呢,對于前后端分開部署前端有自己獨立服務的應用,可能更大的問題是應該要怎么發布,畢竟服務重啟這回事,如果掛了分分鐘影響的都是流量。這也是為什么大部分業務上線時間可能都是挑晚上上線。
我們看看市面上常見的一些發布策略,這個對于前端來說可能接觸得并不是很多。
首先說藍綠部署,指我們同時運行兩個版本的應用,藍綠部署的時候,并不停止掉老版本,而是直接部署一套新版本,等新版本運行起來后,再將流量切換到新版本上。
這就要求在升級過程中,同時運行兩套程序,對硬件的要求就是日常所需的二倍,比如日常運行時,需要 10 臺服務器支撐業務,那么使用藍綠部署,你就需要購置 20 臺服務器,顯然,比較耗費資源。
滾動升級,就是在升級過程中,并不一下子啟動所有新版本,是先啟動一臺新版本,再停止一臺老版本,然后再啟動一臺新版本,再停止一臺老版本,直到升級完成,這樣的話,如果日常需要 10 臺服務器,那么升級過程中也就只需要 11 臺就行了。
再有就是灰度發布,這個其實就已經不算是發布策略了,而是一個測試的策略。也是日常會用得比較多的一個點,先啟動一個新版本應用,但是并不會像是滾動升級一樣,不斷的對所有服務進行切換,而是會將小部分了流量導入到新版本的環境中,測試人員對新版本進行線上測試。如果沒有問題,那么可以將少量的用戶流量導入到新版本上。這種發布方式也叫做金絲雀發布,具體為什么叫金絲雀有興趣的同學可以自己搜一搜。
如果這個時候我們對新版本做運行狀態觀察,收集各種數據,并做新舊數據的對比,這就是所謂的 A/B 測試。
說了那么多部署方式,那么對我們前端來說有什么用呢,一方面來說更好的了解后端的一個部署模式在跟后端或者做溝通的時候可以稍微多一些底氣,另外也可以借鑒借鑒,知道前端要怎么玩。
通常來說,前端部署可能可以劃分為覆蓋式部署和非覆蓋式部署。覆蓋式部署大多就是資源在服務器上,每次部署把之前的內容都刪了重新替換。而非覆蓋式會存儲多套資源,在恰當的時候去控制做資源的切換,有點類似藍綠,但是沒有銷毀的過程。
對于個人來說,我們這邊可能目前用的比較多的是非覆蓋式,將資源都部署到對象存儲上面,例如阿里的 OSS,百度的 BOS,去使用它們的 CDN 功能。然后在 Nginx 或者哪一層去控制資源的版本切換,或者說默認使用其 lastest 的版本。
那么對于普通的業務開發,我們應該怎么選呢?上面說的各種部署方式,市面上很多云平臺都有一定的支持。因此對一些業務簡單的小團隊,可以考慮直接找個云平臺,然后擼一擼公共腳本或者服務,串一串就可以開心的玩耍了。
對于一些業務龐大復雜,有人力精力的情況下,也可以考慮弄一個可視化的流水線平臺,像是早上其他講師分享的。這建議是在有一定規模之后,且簡單模式 run 了一定時候再去搞。
具體可能會涉及到哪些東西呢,首先呢還是一樣,需要有一個環境,可以跟上面說的編譯環境保持一致。然后拉取打包后的產物,并將產物發送到指定的機器/CDN,期間可能會涉及到一些服務之間的關聯,部署模式等。
這是我們這邊的一個流水線平臺的大概例子,它大概的功能可以遠遠不止 Web 的構建和打包,還有像是客戶端,Server 類型的不同環境的編譯,都是以插件的形式集成到其中。
另外還可以做一些常見跟發布相關的功能,比如打版本號,提測,環境切換,發單,審批等都可以在這里進行。
然后對于部署,同樣有一些思考點,這里也是列舉不做詳細的解答,比如:怎么制定部署到不同環境,怎么去做權限的控制,然后部署成功的通知,失敗的回滾和通知,怎么去打版本號,還有對于前端 Sourcemap 怎么存,怎么做關聯,日志怎么去做上報存儲分析,對于物理機,虛擬機,Docker 等不同形式我們怎么去做部署。
另外,如果自己搞平臺,那么我們的關注點,除了構建部署,我們還能做什么別的事情,比如說:代碼跟需求卡片關聯,自動提測,各種服務端的檢查,各種測試,審批等等。
思路層面這里基本就講完了。
四、總結
總的來說,以上就是構建部署的一個簡單介紹。對于具體業務,不同的方向的需求多多少少都有些不同,這也是軟件開發中一個比較難的部分。
這次分享只是做了細粒度的思路拆解,具體方案其他講師也都說得很清楚。這里引用人月神話中一句話,“軟件開發中最困難的部分是規格說明,設計和測試這些概念上的結構,而不是對概念進行表達和對表達完整程度進行驗證。所以軟件開發天生就沒有銀彈”。
這里核心想說明的就是構建部署沒有銀彈,大家需要根據自身情況做各種調整,希望大家都能早日造就適合自己的方式。
既然說到這里了,那么分享例行需要推薦的書就是這本《人月神話》。被很多人都推薦以及評分都特別高的書,剛開始看可能看不懂,當你有了一定經驗,項目達到一定規模之后再回頭來看,可能會有不一樣的體會。
推薦閱讀
我在阿里招前端,我該怎么幫你?(現在還可以加模擬面試群)
如何拿下阿里巴巴 P6 的前端 Offer
如何準備阿里P6/P7前端面試--項目經歷準備篇
大廠面試官常問的亮點,該如何做出?
如何從初級到專家(P4-P7)打破成長瓶頸和有效突破
若川知乎問答:2年前端經驗,做的項目沒什么技術含量,怎么辦?
若川知乎高贊:有哪些必看的 JS庫?
末尾
你好,我是若川,江湖人稱菜如若川,歷時一年只寫了一個學習源碼整體架構系列~(點擊藍字了解我)
關注
若川視野
,回復"pdf" 領取優質前端書籍pdf,回復"加群",可加群長期交流學習我的博客地址:https://lxchuan12.gitee.io?歡迎收藏
覺得文章不錯,可以點個
在看
呀^_^另外歡迎留言
交流~
小提醒:若川視野公眾號面試、源碼等文章合集在菜單欄中間
【源碼精選】
按鈕,歡迎點擊閱讀,也可以星標我的公眾號,便于查找