高效前端專案自動化構建部署實踐——使用webhook鉤子運維

LegendaryLeo發表於2019-08-05

本文首發於我的個人部落格:高效前端專案自動化構建部署實踐——使用webhook鉤子運維,歡迎大家來訪問哦!

優化原由

最近訪問我的部落格網站的時候,我發現經常會出現打不開的情況,我的部落格是搭載在coding的coding pages服務上的,仔細檢查了coding服務上的程式碼,發現沒什麼毛病,應該就是coding pages的伺服器不穩定造成的,由於最近在投遞簡歷,這個情況也給我造成了一定的困擾,考慮到要給招聘者良好的瀏覽體驗,我決定要優化一下自己的部落格網站執行環境了。

優化思路——將網站檔案放到我自己的伺服器上

執行方法——使用ftp部署

我的優化思路就是將網站檔案放到我自己的伺服器上。起初我打算使用Hexo的ftp部署相關的外掛來完成,當我執行hexo d的時候,檔案會自動上傳到伺服器端,我這樣試著弄了之後發現由於ftp協議的特性,在傳大量的檔案的時候,無法充分利用網路頻寬,因此造成了速度非常慢的情況。這種情況只能將網站檔案打包壓縮再上傳,然後在伺服器端解壓才能解決。想了想,我覺得這樣太複雜又累贅,實在是不能體現我程式碼潔癖的風格,拒絕拒絕!

執行方法——使用webhook自動運維部署

我在之前實習公司裡,有見同事用過webhook這玩意兒,瞭解過其運作方法和作用。又查了一下相關資料(下為Github解釋):

Webhooks allow you to build or set up integrations, such as GitHub Apps or OAuth Apps, which subscribe to certain events on GitHub.com. When one of those events is triggered, we'll send a HTTP POST payload to the webhook's configured URL. Webhooks can be used to update an external issue tracker, trigger CI builds, update a backup mirror, or even deploy to your production server. You're only limited by your imagination.

簡單來說就是WebHooks可用於更新外部問題跟蹤器、觸發CI構建、更新備份映象,甚至部署到生產伺服器。這對於我目前的需求完全匹配呀,於是新的思路來了——在伺服器端克隆下自己的部落格專案並安裝依賴,在coding服務上設定相應的webhook鉤子,在伺服器端編寫接受webhook請求的回撥方法,在回撥方法裡執行構建相關的命令。這樣就不用把檔案傳來傳去了,簡潔明瞭,開始搞!

執行步驟

  1. 在伺服器上合適的位置克隆下自己的專案檔案,並安裝好依賴,我這裡是hexo部落格專案,所以還得全域性安裝hexo依賴。

  2. 編寫接收webhook回撥的服務,我這裡是用node.js寫的,你也可以使用其他後端語言,只要能執行shell命令就行。 在服務端合適的位置編寫webhook.js如下:

const http = require('http')
const { exec } = require('child_process')

const PORT = 9999 // 服務埠
const path = '/www/wwwroot/projects/xxxxxxx/' // 這裡是伺服器端,此專案的檔案地址
const commands = [
  'cd ' + path,
  'git pull',
  'yarn dep', // 這個命令是我hexo專案編譯的命令
  'rm -rf ../../hexo-blog/', // 刪除原來的檔案
  'mv ' + path + 'public/ ../../hexo-blog/' // 將編譯的檔案放入網站專案資料夾
].join(' && ') // 這裡寫依次要在伺服器上執行的命令

var deployServer = http.createServer(function(req, res) {
  if (req.url.search(/deploy\/?$/i) > 0) { // 這裡做了個deploy的標記,以防使用者訪問此網址無意出發命令
    let work = exec(commands, {
      maxBuffer: 5000 * 1024, // 預設 200 * 1024
    }, function(err, out) {
      if (!err) {
        res.writeHead(200)
        res.end('Deploy Done.')
      }
    })
    work.stdout.on('data', function(data) {
      console.log('stdout: ' + data)
    })
    work.stderr.on('data', function(data) {
      res.writeHead(500)
      res.end('Server Internal Error.')
      console.log('stderr: ' + data)
    })
  } else {
    res.writeHead(404)
    res.end('Not Found.')
  }
})

deployServer.listen(PORT)

複製程式碼

程式碼很短很簡單,重點就是要呼叫node的子程式來執行命令。有個坑要注意,使用子程式時,在回撥函式裡的列印是不會輸出到控制檯的,需要將當前執行過程設為一個變數,通過其stdout和stderr的data監聽來獲取列印輸出。另外,exec在執行時會在記憶體中建一個buffer來緩衝組合所有的輸出資料,而maxBuffer則是指定該buffer大小的屬性。如果輸出超過指定的大小則會報 maxBuffer exceeded 的錯誤,這也是很常見的錯誤,所以我們需要加大其maxBuffer。

寫好服務端程式碼後,我們ssh連線伺服器,執行node webhook.js將其啟動並不要關閉,以備後面除錯,並且要注意你設定的埠在伺服器安全組裡已經開啟過了,或者你也可以使用Nginx反向代理到80埠開啟另一個服務,這裡就不細說了,目的就是要讓外網能夠訪問到此服務。

  1. 在Git專案管理的設定裡開啟並設定webhook服務

    webhook-setting
    URL是必填項,填寫你格式如:http://你的伺服器地址:剛才設定的埠/deploy,令牌則是傳送webhook時,客服端做的記號,也是起到防止惡意或無意請求到webhook服務的作用,如果設定了令牌,根據Git服務端的不同,會傳送不同的令牌格式,一般是放在請求頭的自定義引數裡,我們需要在服務端接收請求的方法裡進行處理,這裡不再做演示。

  2. 如果設定完成,系統會自動傳送檢測命令來出發webhook回撥。

    webhook-setting-success
    如果設定正常,檢視剛剛開啟的ssh介面,會發現有大段輸出
    child-process-out

  3. 這時我們檢視網站對應的檔案,會發現已經更新了!這時設定好對應的網站服務,就可以正常訪問我們的網站了。

  4. 要注意的是,臨時開啟的node程式會經常自己斷掉,我們最好需要用pm2來管理node服務,PM2是node程式管理工具,可以利用它來簡化很多node應用管理的繁瑣任務。 全域性安裝pm2:

npm install -g pm2
複製程式碼

開啟程式服務

pm2 start webhook.js
複製程式碼

像這樣status為online就是在正常執行了

webhook-pm2

webhook會監聽我們的程式碼推送,所以現在只用Git推送就可以輕鬆地部署我們的專案啦,大工告成!

相關文章