當我們談部署時,我們在談什么?
計算機網(wǎng)絡(luò)把各地的計算機連接了起來,只要有一臺可以上網(wǎng)的終端,比如手機、電腦,就可以訪問互聯(lián)網(wǎng)上任何一臺服務(wù)器的資源(包括靜態(tài)資源和動態(tài)的服務(wù))。
作為開發(fā)者的我們,就是這些資源、服務(wù)的提供者,把資源上傳到服務(wù)器,并把服務(wù)跑起來的過程就叫做部署。
代碼部分的部署,需要先經(jīng)過構(gòu)建,也就是編譯打包的過程,把產(chǎn)物傳到服務(wù)器。
最原始的部署方式就是在本地進行 build,然后把產(chǎn)物通過 FTP 或者 scp(基于 SSH 的遠程拷貝文件拷貝) 傳到服務(wù)器上,如果是后端代碼還需要重啟下服務(wù)。
每個人單獨構(gòu)建上傳,這樣不好管理,也容易沖突,所以現(xiàn)在都會用專門的平臺來做這件事構(gòu)建和部署,比如 jenkins。
我們代碼會提交到 gitlab 等代碼庫,然后 jenkins 從這些代碼庫里把代碼下載下來進行 build,再把產(chǎn)物上傳到服務(wù)器上。
流程和直接在本地構(gòu)建上傳差不多,只不過這樣方便管理沖突、歷史等,還可以跨項目復(fù)用一些東西。
構(gòu)建、部署的過程最開始是通過 shell 來寫,但寫那個的要求還是很高的,很少人會寫(我就不咋會)。后來就支持了可視化的編排,可以被編排的這個構(gòu)建、部署的流程叫做流水線 pipeline。
比如這是 jenkins 的 pipeline 的界面:
除了構(gòu)建、部署外,也可以加入一些自動化測試、靜態(tài)代碼檢查等任務(wù)。
這種自動化了的構(gòu)建、部署流程就叫做 CI(持續(xù)集成)、CD(持續(xù)部署)。
我們現(xiàn)在還是通過 scp / FTP 來上傳代碼做的部署,但是不同代碼的運行環(huán)境是不同的,比如 Node.js 服務(wù)需要安裝 node,Java 服務(wù)需要安裝 JRE 等,只把代碼傳上去并不一定能跑起來。
那怎么辦呢?怎么保證部署的代碼運行在正確的環(huán)境?
把環(huán)境也給管理起來,作為部署信息的一部分不就行了?
現(xiàn)在流行的容器技術(shù)就是做這個的,比如 docker,可以把環(huán)境信息和服務(wù)啟動方式放到 dockerfile 里,build 產(chǎn)生一個鏡像 image,之后直接部署這個 docker image 就行。
比如我們用 nginx 作為靜態(tài)服務(wù)器的時候,dockerfile 可能是這樣的:
FROM nginx:alpine
COPY /nginx/ /etc/nginx/
COPY /dist/ /usr/share/nginx/html/
EXPOSE 80
這樣就把運行環(huán)境給管理了起來。
所以,現(xiàn)在的構(gòu)建產(chǎn)物不再是直接上傳服務(wù)器,而是生成一個 docker image,上傳到 docker registry,然后把這個 docker image 部署到服務(wù)器。
還有一個問題,現(xiàn)在前端代碼、后端代碼都部署在了我們的服務(wù)器上,共享服務(wù)器的網(wǎng)絡(luò)帶寬,其中前端代碼是不會變動的、流量卻很大,這樣使得后端服務(wù)的可用帶寬變小、支持的并發(fā)量下降。
能不能把這部分靜態(tài)資源的請求分離出去呢?最好能部署到離用戶近一點的服務(wù)器,這樣訪問更快。
確實可以,這就是 CDN 做的事情。
網(wǎng)上有專門的 CDN 服務(wù)提供商,它們有很多分散在各地的服務(wù)器,可以提供靜態(tài)資源的托管。這些靜態(tài)資源最終還是從我們的靜態(tài)資源服務(wù)器來拿資源的,所以我們的靜態(tài)資源服務(wù)器叫做源站。但是請求一次之后就會緩存下來,下次就不用再請求源站了,這樣就減輕了我們服務(wù)器的壓力,還能加速用戶請求靜態(tài)資源的速度。
這樣就解決了靜態(tài)資源分去了太多網(wǎng)絡(luò)帶寬的問題,而且還加速了資源的訪問速度。
此外,靜態(tài)資源的部署還要考慮順序問題,要先部署頁面用到的資源,再部署頁面,還有,需要在文件名加 hash 來觸發(fā)緩存更新等,這些都是更細節(jié)的問題。
這里說的都是網(wǎng)頁的部署方式,對于 APP/小程序它們是有自己的服務(wù)器和分發(fā)渠道的,我們構(gòu)建完之后不是部署,而是在它們的平臺提交審核,審核通過之后由它們負責部署和分發(fā)。
總結(jié)
互聯(lián)網(wǎng)讓我們能夠用手機、PC 等終端訪問任何一臺服務(wù)器的資源、服務(wù)。而提供這些資源、服務(wù)就是我們開發(fā)者做的事情。把資源上傳到服務(wù)器上,并把服務(wù)跑起來,就叫做部署。
對于代碼,我們可以本地構(gòu)建,然后把構(gòu)建產(chǎn)物通過 FTP/scp 等方式上傳到服務(wù)器。
但是這樣的方式不好管理,所以我們會有專門的 CI/CD 平臺來做這個,比如 jenkins。
jenkins 支持 pipeline 的可視化編排,比寫 shell 腳本的方式易用很多,可以在構(gòu)建過程中加入自動化測試、靜態(tài)代碼檢查等步驟。
不同代碼運行環(huán)境不同,為了把環(huán)境也管理起來,我們會使用容器技術(shù),比如 docker。把環(huán)境信息寫入 dockerfile,然后構(gòu)建生成 docker image,上傳到 registry,之后部署這個 docker image 就行。
靜態(tài)資源和動態(tài)資源共享服務(wù)器的網(wǎng)絡(luò)帶寬,為了減輕服務(wù)器壓力、也為了加速靜態(tài)資源的訪問,我們會使用 CDN 來對靜態(tài)資源做加速,把我們的靜態(tài)服務(wù)器作為源站。第一個靜態(tài)資源的請求會請求源站并緩存下來,之后的請求就不再需要請求源站,這樣就減輕了源站的壓力。此外,靜態(tài)資源的部署還要考慮順序、緩存更新等問題。
對于網(wǎng)頁來說是這樣,APP/小程序等不需要我們負責部署,只要在它們的平臺提交審核,然后由它們負責部署和分發(fā)。
當我們在談部署的時候,主要就是在談這些。