都9012年了,你還在手動部署程式碼嗎

Ego同學發表於2019-04-08

背景

公司從當初的SVN程式碼版本控制,FTP手動上傳專案程式碼zip壓縮包,到如今的git程式碼版本控制,jenkins一鍵打包部署環境,已經初步完成了手動到自動的大躍進.回過頭來看看自己的專案,還處在本地倉庫修改程式碼 -> 提交遠端github倉庫 -> 自己上伺服器手動pull最新分支程式碼的原始階段.不能忍

OK,接下來讓我們開始我們的進化偷懶之旅,大家一起跟隨我的心路歷程一起進化.

目標

當我們本地倉庫修改完成push遠端倉庫之後, 伺服器能夠自動拉取最新分支程式碼,自動完成專案部署.

前置條件(廢話)
  1. 有個本地倉庫能夠連線到遠端倉庫,能夠push程式碼
  2. 伺服器倉庫能夠從遠端倉庫pull程式碼
  3. 遠端倉庫有webhooks功能

行動

工欲善其事必先利其器,開始行動前有必要理解一波webhooks鉤子自動部署原理;

webhooks自動部署原理
本地倉庫 -> (push提交程式碼) -> 遠端倉庫(webhooks鉤子) -> (傳送帶有key的post請求) -> 測試/生產伺服器(執行部署指令碼) 
複製程式碼

知悉了原理之後我們來看看我們需要準備些什麼:

  • 帶有webhooks的遠端倉庫(gitlab,github,gitee等等)
  • 能夠接收post請求的服務和測試/生產伺服器
  • 部署指令碼(.sh)
遠端倉庫webhooks設定

遠端倉庫的webhooks設定你只需要找到具體位置點進去:

  1. URL: 設定post請求的地址(即伺服器服務地址)

  2. key: 這個key可以設定也可以不設定,建議設定,防止他人隨意請求伺服器介面然後自動瘋狂拉程式碼部署,相當於一個驗籤

部署指令碼auto_build.sh

部署指令碼(.sh)就自由發揮,自己平時怎麼手動部署的就咋寫就完事了,建立檔案auto_build.sh.Linux下建立目錄使用mkdir 目錄名,建立檔案使用touch 檔名.

PROJECTNAME_PATH = '/usr/local/src/專案目錄';

echo "Starting deployment"
cd $PROJECTNAME_PATH
git checkout .
git pull
npm i
gulp release
pm2 start ecosystem.config.js
echo "Finished"
複製程式碼

執行指令碼的時候注意一下使用者許可權的問題以及基本命令的全域性安裝.

編寫服務deploy.js

接下來的重頭戲就是構建起一個能夠接收遠端倉庫post請求的服務,這同樣也很簡單.你可以藉助外掛github-webhook-handler 的幫助,快速建立起這樣一個服務,建立檔案deploy.js.

ps: 這裡的secret就是上面webhooks設定中的key

var http = require('http')
var createHandler = require('github-webhook-handler')
var handler = createHandler({ path: '/webhook', secret: 'myhashsecret' })

http.createServer(function (req, res) {
  handler(req, res, function (err) {
    res.statusCode = 404
    res.end('no such location')
  })
}).listen(7777)

handler.on('error', function (err) {
  console.error('Error:', err.message)
})

handler.on('push', function (event) {
  console.log('Received a push event for %s to %s',
    event.payload.repository.name,
    event.payload.ref)
})

handler.on('issues', function (event) {
  console.log('Received an issue event for %s action=%s: #%d %s',
    event.payload.repository.name,
    event.payload.action,
    event.payload.issue.number,
    event.payload.issue.title)
})
複製程式碼

ps: 還可以設定當有人給自己倉庫提issues時發郵件提醒自己23333333

如果服務無法啟動,報錯類似Error: Cannot find module 'github-webhook-handler',可是依賴包明明已經全域性安裝過了.確認方法:

npm root -g							// 檢視npm全域性安裝路徑
=> /root/.nvm/versions/node/v9.10.1/lib/node_modules

cd /root/.nvm/versions/node/v9.10.1/lib/node_modules
ll 									// 檢視目錄檔案確認依賴是否安裝
複製程式碼

確認安裝後可以通過以下步驟解決:

  1. 進入deploy.js所在目錄
  2. 執行以下命令
npm link github-webhook-handler
複製程式碼

現在,你需要做的是將auto_build.shdeploy.js結合起來.

閱讀上面程式碼,你會發現handler監聽到push事件呼叫對應的函式,所以你要做的就是在函式中執行auto_build.sh命令,你需要在deploy.js新增以及更改如下程式碼

// 新增runCmd函式
funciton runCmd(cmd, args, callback) {
    var spawn = require('child_process').spawn;				// node子程式
    var child = spawn(cmd, args);
    var response = '';
    
    child.stdout.on('data', buffer => response += buffer.toStirng());
    child.stdout.on('end', () => callback(response));
}

// 修改push監聽事件 我這裡auto_build.sh和deploy.js位於同一目錄檔案中
handler.on('push', function(event) {
   runCmd('sh', ['./auto_build.sh'], function(text) { console.log(text) }); 
});
複製程式碼

ps: 可以通過console.log()在相應的步驟輸出相應提示,方便查錯

執行服務deploy.js

我們希望deploy服務能夠一直執行在伺服器上,當遠端倉庫傳送post請求提示我們有新程式碼push的時候能夠正常執行部署指令碼.這時我們需要以守護程式的方式來啟動deploy.js服務,當服務意外崩潰時能夠重啟服務,徹底解放我們的雙手.

這裡提供兩種方法供大家選擇,都可以通過npm安裝:

  1. forever就是保證程式退出時,應用會自動重啟。
forever start deploy.js		   				  // 啟動服務程式
forever list								  // 列出所有程式
forever logs id								  // 檢視程式輸出日誌
forever stop id								  // 停止服務程式
forever restart id							  // 重啟服務程式
forever -m 5 deploy.js						  // 最多重啟次數為5
複製程式碼
  1. pm2功能強大,除了重啟程式以外,還能實時收集日誌和監控。
pm2 start deploy.js		   				  // 啟動服務程式
pm2 list								  // 列出所有程式
pm2 logs id								  // 檢視程式輸出日誌
pm2 stop id								  // 停止服務程式
pm2 restart id							  // 重啟服務程式
pm2 delete id							  // 刪除服務程式
複製程式碼
Nginx反向代理

因為我的伺服器在騰訊雲上面,7777埠並未放開,所以通過一個Nginx反向代理到伺服器安全組開放埠.

在遠端倉庫傳送post測試請求前一定要確認

自己伺服器安全組埠已放開!!!

自己伺服器安全組埠已放開!!!

自己伺服器安全組埠已放開!!!

重要的事情說三遍! 下面是我nginx配置

server {
	listen 8080;
    server_name	localhost;
    
    location /webhook {
        proxy_pass http://127.0.0.1:7777;
    }
}
複製程式碼

ps: Linux下重啟nginx,進入nginx的sbin目錄執行命令./nginx -s reload

Bug

Nginx啟動 ! deploy服務啟動 ! 遠端倉庫webhook設定完畢 ! 點選測試按鈕 !

然後......

報錯!!! (強顏歡笑and笑容逐漸消失.jpg

{
  "error": "No X-Hub-Signature found on request"
}
複製程式碼

看了半天......才想起來我的專案程式碼遠端倉庫是碼雲gitee.com,因為github私人private倉庫2019年2月之前都是需要付費的,所以涉及私人的專案程式碼我都選擇了碼雲作為遠端倉庫,然而我的外掛是github-webhook-handler!!!!能通才有鬼 TAT

沒關係,小問題.都到這一步了,男人怎麼能說不行!

先去github上搜下有沒有對應gitee的webhook外掛,要是沒有就forkgithub-webhook-handler下來自己改下改成適配gitee碼雲的.果然讓我搜到了gitee-webhook-middleware,然後deploy.js改一改

var createHandler = require('gitee-webhook-middleware');
var handler = createHandler({ path: '/webhook', token: '你的key' });
複製程式碼

重啟服務,點選測試 !

{
  "ok": true
}
複製程式碼

完美 !

上伺服器一看專案程式碼還是舊的,媽耶還有坑...後來發現gitee的post請求事件是Push Hook

// handler.on('push', function() {});
handler.on('Push Hook', function() {});
複製程式碼

至此,重新測試,專案程式碼更新成功 !

結果

偷懶成功! 偷懶果然是工程師第一生產力

現在每當我本地倉庫push程式碼到遠端倉庫,伺服器就會拉取最新版本程式碼自動部署.

這只是我一次簡單嘗試,我們完全可以擴充套件自動化測試,自動化部署於一體,完成多人協作開發時的CI/CD,大大減少人力成本,減少人為錯誤的發生,提高大家的工作效率.

相關文章