淺談gitlab-ci分離部署方案

Roy_Pu發表於2020-03-19

前言

關於前端部署,相信不同的公司都有不同的方案。我先說說我所知道的幾種(都是基於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-ci分離部署方案

準備條件

gitlab-runner

構建任務都會佔用很多的系統資源 (譬如編譯程式碼),而 GitLab CI 又是 GitLab 的一部分,如果由 GitLab CI 來執行構建任務的話,在執行構建任務的時候,GitLab 的效能會大幅下降。

GitLab CI 最大的作用是管理各個專案的構建狀態,因此,執行構建任務這種浪費資源的事情就交給 GitLab Runner 來做啦。因為 GitLab Runner 可以安裝到不同的機器上,所以在構建任務執行期間並不會影響到 GitLab 的效能。

Runner 的註冊, 需要一臺伺服器 (官方說法是: 任何一個連線網際網路且可以執行程式的機器或容器), 在需要執行工作流時, Gitlab 會將任務分配給合適的 runner 執行 (可以註冊很多個不同分工的 runner).

註冊一個 runner 又分兩步:

  1. 在伺服器上安裝 gitlab-runner: docs.gitlab.com/runner/inst…
  2. 把這臺伺服器註冊為一個專案的 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,推薦設定。

淺談gitlab-ci分離部署方案

二、配置指令碼(./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上。 我們可以看到testprd環境的區別在於推送到託管頁面的伺服器的方式不一樣。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實現部署是一個比較靈活的方案。其中涉及到的內容也比較多。需要了解gitlab-ci相關的內容,伺服器相關的一些內容。它可以做的其實遠不止這些,我們可以還整合自動化測試、使用docker部署等,讓整個流程更加規範,更加完善。

相關文章