前言
關於前端部署,相信不同的公司都有不同的方案。我先說說我所知道的幾種(都是基於SPA應用的),最後聊一聊關於gitlab-ci來發布前端應用。
多樣的部署方案
前端應用的部署可以簡單的分為兩個方面,一是靜態資原始檔的部署,二是html頁面託管。
最傳統的方式(簡單粗暴型)
把打包好的檔案(靜態檔案和html頁面)全部丟給後端同學,由服務端提供渲染html的功能。
弊端:使用者所有訪問的檔案都在伺服器上,伺服器的壓力相對更大,一旦伺服器掛了,直接訪問出錯,使用者體驗不太好。
好處:不需要額外的工具作為支撐,對於小公司而言,可能是最簡單方便的部署方案。
cdn託管靜態資源
由cdn託管靜態資源,html檔案放在後端服務進行渲染。把css,js檔案部署在cdn,一方面可以降低伺服器的壓力,另一方面也能提升使用者的訪問速度。
大家都知道webpack打包後的檔案預設都是帶contenthash值
的,如app.0d203f04c0cb433d9f67f9a4fa8cf74e.css
,那麼如果html放在後端服務的話,務必要根據前端打包後的html,再重新去更新html,這肯定不是我們想要的結果。因此我們修改webpack配置,把部分資源的contenthash值去掉,這樣我們打包出來的css檔案,js檔案就沒有這些hash值了,但是因為cdn有快取,所以html檔案中引入的靜態資原始檔還要在最後帶上時間戳,這樣可以保證訪問正常。但是這又帶來一個問題,如果時間戳是每次訪問都重新整理,那麼使用者每次訪問都要請求cdn上的檔案,也就相當於本地沒有快取,對於載入不是很好。所以就衍生出另一種機制,通過呼叫api去重新整理時間戳,這樣一來可以保證本地快取正常,其次html也不用每次釋出都重新更新了。但是,如果我們哪天要更新html的內容,比如產品經理說我們要加個google打點,那麼我們需要在html上加一段js指令碼,這時候我們並不涉及後端的改動,我們卻要後端幫忙重新發布html檔案,是不是不太友好呢。
半自動化釋出
這種釋出模式和第二種釋出方式本質上是一樣的,公司內部可能會提供一個釋出平臺,我們通過釋出平臺打包構建我們的應用,再由這個平臺把打包好的檔案釋出到cdn上。與上一種方式相比,我們不需要再在本地打包了。
gitlab-ci釋出部署
方案初衷
- 解決未前後端分離帶來的痛點。如:重新整理時間戳(因不通專案重新整理機制不通,麻煩),html更新不方便。
- 規範化前端構建和釋出流程
- 自動化前端構建和釋出流程
- 擴充套件前端能力邊界, 例如MPA、SSR等等
架構原理
準備條件
gitlab-runner
構建任務都會佔用很多的系統資源 (譬如編譯程式碼),而 GitLab CI 又是 GitLab 的一部分,如果由 GitLab CI 來執行構建任務的話,在執行構建任務的時候,GitLab 的效能會大幅下降。
GitLab CI 最大的作用是管理各個專案的構建狀態,因此,執行構建任務這種浪費資源的事情就交給 GitLab Runner 來做啦。因為 GitLab Runner 可以安裝到不同的機器上,所以在構建任務執行期間並不會影響到 GitLab 的效能。
Runner 的註冊, 需要一臺伺服器 (官方說法是: 任何一個連線網際網路且可以執行程式的機器或容器), 在需要執行工作流時, Gitlab 會將任務分配給合適的 runner 執行 (可以註冊很多個不同分工的 runner).
註冊一個 runner 又分兩步:
- 在伺服器上安裝 gitlab-runner: docs.gitlab.com/runner/inst…
- 把這臺伺服器註冊為一個專案的 runner: docs.gitlab.com/runner/regi…
(這裡可能需要預備一些伺服器相關的知識)
.gitlab-ci.yml
.gitlab-ci.yml 用來配置 CI 用你的專案中做哪些操作,這個檔案位於倉庫的根目錄。
當有新內容push到倉庫,或者有程式碼合併後,GitLab 會查詢是否有 .gitlab-ci.yml 檔案,如果檔案存在,Runners 將會根據該檔案的內容開始 build 本次 commit。
.gitlab-ci.yml 使用YAML語法,你需要格外注意縮排格式,要用空格來縮排,不能用tabs來縮排。
api規範
規範後端api,比如所有api都符合 /api/**
規則,有一定規則後,才方便做代理轉發。
接入步驟
預設已經準備好一臺伺服器和響應的指令碼(可能需要運維參與。如果是自己嘗試玩兒,可以把本地的電腦當作跑runner的機器,寫對應的指令碼,配置好自己的伺服器,即可把想要推的檔案推送到伺服器啦)
一、runner繫結
在已經安裝好gitlab-runner的機器上註冊一個runner。註冊runner時需要繫結專案的token。
建議:繫結runner時,可以設定tag,推薦設定。
二、配置指令碼(./deploy.sh)
目錄結構
.
├── deploy.sh
├── build
├── src
├── package.json
├── index.html
├── ...
├── .gitlab-ci.yml
├── README.md
複製程式碼
# 需要保證應用名稱是唯一的
ENV=$3 # 環境區分
PROJECT_NAME=$2 # 應用名稱
ASSETS_PUBLIC_PATH=$1 # 應用名稱 + 分支名稱 / dist
if [ $ENV = 'test' ]
then
rsync -rzav --delete $ASSETS_PUBLIC_PATH/*.html --rsync-path="mkdir -p ~/front-asserts/$PROJECT_NAME && rsync" roy@192.168.XXX.XXX:~/front-asserts/$PROJECT_NAME
sudo /opt/bin/rsync-to-cdn ./ $ASSETS_PUBLIC_PATH/static
elif [ $ENV = 'prd' ]
then
mkdir -p $PROJECT_NAME
mv $ASSETS_PUBLIC_PATH/*.html $PROJECT_NAME
sudo /opt/bin/rsync-to-prd ./ $PROJECT_NAME
sudo /opt/bin/rsync-to-cdn ./ $ASSETS_PUBLIC_PATH/static
fi
# 指令碼使用說明:
# sudo /opt/bin/rsync-to-prd dir1 dir2
# dir1和dir2組合其實是用來定位當前資源路徑的,而最終對外輸出的路徑依賴於dir2。
# example: sudo /opt/bin/rsync-to-cdn /var/xxx/yyy abc/version1/dist
複製程式碼
這個指令碼主要做了兩件事情。一、把打包出來的html檔案傳送到託管頁面的伺服器。二、把dist目錄推送到cdn上。
我們可以看到test
和 prd
環境的區別在於推送到託管頁面的伺服器的方式不一樣。prd環境的伺服器為了安全考慮是不暴露出來的,而是執行跑runner機器上的指令碼。
三、配置.gitlab-ci.yml
.gitlab-ci.yml
# test 和 master分支預設支援線上部署
# cache 可根據實際情況加上,建議加上,有利於加快裝包的速度
# tag 就是註冊runner時填寫的tag
stages:
- build
- deploy
variables:
# 應用名稱(必須保證應用名稱的唯一性,否則有可能影響其他應用,注意與打包時的專案名保持一致)
CI_PROJECT_NAME: projectName
ASSETS_PUBLIC_PATH: $CI_PROJECT_NAME-$CI_COMMIT_REF_NAME/dist
# 安裝依賴&&構建打包
build pack:
stage: build
cache:
key: customSetting
paths:
- node_modules/
only:
- test
- master
tags:
- test-tag
script:
- npm install
- BRANCH=$CI_COMMIT_REF_NAME node build/build.js
- mkdir -p $ASSETS_PUBLIC_PATH && mv dist/* $ASSETS_PUBLIC_PATH
artifacts:
expire_in: 10 min
name: $CI_PROJECT_NAME
paths:
- $ASSETS_PUBLIC_PATH
# 測試分支部署到測試環境
deploy test:
stage: deploy
only:
- test
tags:
- test-tag
script:
- chmod u+x ./bin/deploy.sh
- ./bin/deploy.sh $ASSETS_PUBLIC_PATH $CI_PROJECT_NAME test
# 主分支部署到生產環境
deploy prodcution:
stage: deploy
only:
- master
tags:
- test-tag
script:
- chmod u+x ./bin/deploy.sh
- ./bin/deploy.sh $ASSETS_PUBLIC_PATH $CI_PROJECT_NAME prd
複製程式碼
四、部署上線
通知運維,配置伺服器的nginx。
一、在託管頁面的伺服器上,我們已經可以看到我們推送上來的檔案了。我們需要配置一下nginx來託管這個html。
server {
listen 8090;
location / {
add_header Cache-Control "no-cache";
root ~/xxx/xxx; #該專案的入口頁目錄位置
index index.html;
try_files $uri $uri/ /index.html;
}
}
複製程式碼
二、nginx反向代理配置
location /example/api/ {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $http_host;
proxy_pass http://ip:port; # 所在後端服務的地址
}
location /example/ {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $http_host;
proxy_pass http://ip:port; # 上個步驟配置的地址。
}
複製程式碼
總結&心得
在一段時間的實踐後,我覺得可以把這個過程簡單的理解為,有一臺機器在我們把程式碼push到程式碼倉庫的時候,自動幫我們打包並把打包好的內容分發到它應該在的地方。
回過頭來,再看一下這張架構圖,希望有更深的體會。
gitlab-ci實現部署是一個比較靈活的方案。其中涉及到的內容也比較多。需要了解gitlab-ci相關的內容,伺服器相關的一些內容。它可以做的其實遠不止這些,我們可以還整合自動化測試、使用docker部署等,讓整個流程更加規範,更加完善。