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