Github的WebHooks實現生產環境代碼自動更新

一般公司都會使用git 或 svn 。現在的線上倉庫比如 Github、Gitlab、Gitee 等都支持 hook 技術,可以很方便的實現代碼的自動化管理

這裏以我經常使用的 Github 爲例,監聽 dev 分支有 push 動作時,可以自動通過設置的 hook 通知生產環境中的腳本執行 git pull 拉取代碼,自動更新,非常方便。

關於 WebHooks

讓我們看看 官方 關於 Github webhooks 的解釋:

Webhooks allow you to build or set up integrations which subscribe to certain events on GitHub.com.

總結出來幾個點就是:

  • 必須是 Github 上面的項目
  • 訂閱了確定的事件(包括 push/pull 等命令)
  • 自動觸發
    其他線上倉庫也是一樣的,我們要達到的目的是:當有新的本地 commit push 到線上倉庫時,服務器倉庫自動 pull 最線上倉庫新的代碼

WebHook 的工作原理也是很簡單的

當我們 push 代碼到線上倉庫,線上倉庫必然知道這個 push 操作,就會 hook(可以理解爲回調)我們預留的 URL

而這個 URL 對應一段後臺代碼,這段代碼執行了 git pull,這樣就實現自動更新的操作。

準備工作
這裏以 PHP 的代碼爲例,實際上用 Java、JavaScript 等都可以

我們需要在生產環境的服務器上裝好 Git,這個應該是沒有問題的

然後我們需要克隆代碼下來,這裏需要注意的是用戶組和權限的問題

PHP 代碼
Github、GitLab、Gitee 雖然都是 Git 倉庫平臺,但是發送的 WebHooks 請求的數據格式有些差別

  • Github 支持 application/json 和 application/x-www-form-urlencoded 兩種格式,安全 token 需通過請求頭 X-Hub-Signature 加密發給 URL,服務器需要解密後驗證。瞭解更多
  • GitLab 支持 application/json 格式,安全 token 通過請求頭 HTTP_X_GITLAB_TOKEN 明文發給 URL。瞭解更多
  • Gitee 也支持 application/json 和 application/x-www-form-urlencoded 兩種格式,安全 token 放在請求體明文發給 URL,名稱是 password。瞭解更多

請求頭我們可以通過 $_SERVER 全局變量獲得請求的值,比如 $_SERVER[‘X-Hub-Signature’]
然後看一下你的服務器支持不支持 shell_exec 這個 PHP 函數

exec()函數用來執行一個外部程序,我們再用這函數基本是在linux。

開啓exec()函數:

exec()函數是被禁用的,要使用這個函數必須先開啓。首先是 要關掉 安全模式 safe_mode = off。然後在看看 禁用函數列表
disable_functions = proc_open, popen, exec, system, shell_exec, passthru
這裏要把 exec 去掉,重啓 apache/nginx就OK了。

<?php
ini_set('date.timezone','Asia/Shanghai');
$target = '/home/www/Multithread'; // 生產環境web目錄
//密鑰
$secret = "123456";
//獲取GitHub發送的內容
$json = file_get_contents('php://input');
$content = json_decode($json, true);
//github發送過來的簽名
$signature = $_SERVER['HTTP_X_HUB_SIGNATURE'];
if (!$signature) {
   return http_response_code(404);
}
list($algo, $hash) = explode('=', $signature, 2);
//計算簽名
$payloadHash = hash_hmac($algo, $json, $secret);
// 判斷簽名是否匹配
if ($hash === $payloadHash) {
   
    $cmd = "cd $target && sudo git pull 2>&1";
    $res = shell_exec($cmd);
   
    $res_log = 'Success:'.PHP_EOL;
    $res_log .= $cmd . '結果' . $res .PHP_EOL;
    $res_log .= $content['head_commit']['author']['name'] . ' 在' . date('Y-m-d H:i:s') . '向' . $content['repository']['name'] . '項目的' . $content['ref'] . '分支push了' . count($content['commits']) . '個commit:' . PHP_EOL;
    $res_log .= $res.PHP_EOL;
    $res_log .= '======================================================================='.PHP_EOL;
    echo $res_log;
} else {
    $res_log  = 'Error:'.PHP_EOL;
    $res_log .= $content['head_commit']['author']['name'] . ' 在' . date('Y-m-d H:i:s') . '向' . $content['repository']['name'] . '項目的' . $content['ref'] . '分支push了' . count($content['commits']) . '個commit:' . PHP_EOL;
    $res_log .= '密鑰不正確不能pull'.PHP_EOL;
    $res_log .= '======================================================================='.PHP_EOL;
    echo $res_log;
}

在執行的命令後面加上 2>&1 可以輸出詳細信息,確定錯誤位置.

打開你的 Github 倉庫項目地址,進入 Webhooks
在這裏插入圖片描述
點擊 Add webhook,添加一個 webhook
在這裏插入圖片描述
Payload URL 填寫可以訪問你剛纔保存的那個文件的地址,建議放在一個可以訪問的目錄即可,不需要在你的項目目錄中,放在項目目錄中會提示你有新文件,很煩人的。當然你也可以把它當做項目的文件去提交上去

Content type 我們選擇 application/json

Secret 就是我們剛纔的 $secret 變量給的值,我這裏是 123456

下面一個不用改,選擇 Just the push event.,因爲我們只需要 push 的時候進行回調,然後添加即可

然後 Github 會發送一個測試的請求,我們可以看一下 Response 是不是 200,然後看一下 Body 中有沒有 success

第一次有個 Warning 是因爲 count 這個函數的問題,Github 發送的測試請求沒有 push 條數

然後我們可以在本地 push 一下,再去測試一下
在這裏插入圖片描述

這裏需要注意的是用戶組和權限的問題,php 程序默認的nginx 或 www 用戶和用戶組 所以你執行sudo時可能需要密碼的問題。

We trust you have received the usual lecture from the local System
Administrator. It usually boils down to these three things:

    #1) Respect the privacy of others.
    #2) Think before you type.
    #3) With great power comes great responsibility.

sudo: no tty present and no askpass program specified

在這裏插入圖片描述
一般的解決方式

  1. 使用 “su –” 命令,進入root用戶;
  2. 爲sudoers文件添加寫入的權限:使用命令
	chmod u+w /etc/sudoers
  1. 執行**visudo** 命令,按i進入編輯模式後,找到“root ALL=(ALL) ALL ”,在後面添加:"nginx ALL=(ALL) NOPASSWD: ALL",再按一下“Esc”鍵退出編輯,輸入“wq”(write quit)後,退出sudoers。
    輸入“chmod u-w /etc/sudoers”將文件的寫入屬性去掉
    通過“exit”切換回自己的用戶,再使用sudo whoami命令時,如果返回root,就可以使用了
發佈了78 篇原創文章 · 獲贊 34 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章