前言:
代碼托管平台如:Github等提供了一個 Webhooks功能,每次 push 完代碼,可以利用它實現代碼的自動拉取,這樣可以減少好多部署代碼的麻煩事。
-
Webhooks
Webhooks 是代碼托管平台提供的一個功能,對於任意一個項目,可以設置一個 URL,同時選擇一些事件,當觸發了這些事件(push、pull request、fork 等)時,代碼托管平台會自動請求該 URL,並帶上一些必要的參數。
-
實現(以GitHub為例)
-
設置回調URL 選擇事件
登錄GitHub,新建一個版本庫,命名為 testWebhooks,依次點擊 Settings -> Webhooks -> Add webhook
- Payload URL 配置為可以測試機上正常訪問的地址,比如在/www/ 下面有 index.php 或 main.go ,下面以index.php 為例,並且服務器的環境也搭建好了,可以通過http請求直接訪問到
- Content type:POST 攜帶數據的方式,GitHub 上提供 application/json 和 application/x-www-form-urlencoded 兩種,如果上面設置的index.php 中需要用到請求的參數,可以選取自己適合的方式。在這里可以隨便選擇一個
- Secret:密鑰,用於驗證
-
添加 Deploy keys
-
兩個公鑰
- 用戶公鑰:SSH keys,認證用戶身份,添加用戶公鑰后,對該用戶的所有項目擁有讀寫權限,用於開發機;
- 部署公鑰:Deploy keys,對項目進行授權,擁有只讀權限,一般用於生產或測試服務器。
-
生成公鑰
在服務器上執行下面命令
sudo mkdir /var/www/.ssh //將目錄 .ssh 的擁有者、所屬組修改為 www-data sudo chown -R www-data:www-data /var/www/.ssh // 在 /var/www/.ssh 目錄下生成密鑰,同時將該密鑰的擁有者、所屬組修改為 www-data。在 Ubuntu 中,PHP 運行時的用戶為 www-data,如果不修改,PHP 運行時的用戶是讀不到這個部署公鑰的,也就拉不了代碼了 sudo -Hu www-data ssh-keygen -t rsa -C "your_name@example.com"
如果不確定系統的 PHP 運行時使用的哪個用戶,在測試機上建一個測試PHP文件test.php,然后執行以下即可
// test.php <?php system("whoami"); ?>
-
查看並添加部署公鑰
-
查看部署公鑰
sudo cat /var/www/.ssh/id_rsa.pub
-
添加部署公鑰
依次點擊項目的 Setting -> Deploy keys -> Add deploy key,將公鑰粘進去,點擊 Add key 添加完成
-
-
-
准備鈎子文件
之前設置的回調URL可以訪問到的index.php的文件,如下:
<?php // 切換到項目目錄,執行 git pull,加上 2>&1 會輸出一些錯誤信息,便於調試 shell_exec("cd /www/testWebhooks && git pull 2>&1"); ?>
-
克隆項目文件
cd /www/ sudo -Hu www-data git clone git地址
到此為止,每次往項目中推送代碼,測試服務器都會自動拉取代碼到測試服務器上,如果沒拉取成功,很有可能就是由於前面所說的部署秘鑰及項目文件夾沒有設置成拉取腳本(index.php文件)運行時的用戶。
-
-
效果
打開項目,點擊 Setting -> Webhooks,可以看到剛剛設置的回調 URL,點進去拉到最下面 Recent Deliveries,可是看到所有的被觸發事件的請求
-
Request
- Headers:請求頭,包含一些基本信息;
- Payload:觸發這次事件的所有信息都包含在這里面,包括項目名、commit、用戶名等等,如果服務器上的鈎子文件要做一些高級操作,就可以解析這個字段。
-
Response
- Headers:響應頭
- Body:服務器鈎子文件的返回信息,調試輸出信息可以寫到鈎子文件里,請求后在這里查看。
每一種事件發送的 Payload 格式是不一樣的,關於 Payload 更多信息,請看官方文檔: Event Types & Payloads
-
-
服務器拉取代碼時進行驗證,防止惡意攻擊(設置的回調URL有可能被泄露,被認為請求)
-
添加 Webhooks 的時候,Secret 列填上一個隨機字符串比如: testWebhooks
-
鈎子函數文件 index.php 改為:
<?php $secret = "testWebhooks"; //密鑰,和 GitHub 上對應 $path = "/var/www/html/Webhooks"; //服務器上的項目文件目錄 $signature = $_SERVER["HTTP_X_HUB_SIGNATURE"]; //獲取散列字符串 if($signature) { $rawPost = file_get_contents("php://input"); //獲取收到的數據 list($algo, $hash) = explode("=", $signature, 2); //獲取散列算法、散列值 if ($hash === hash_hmac($algo, $rawPost, $secret)) { //驗證 shell_exec("cd /var/www/html/Webhooks && git pull 2>&1"); echo "代碼拉取成功"; } else { echo "Secret 驗證失敗"; } } else { echo "請輸入 Secret"; }
-
注意:
-
每次觸發事件,GitHub 會使用 SHA-1 將發送的數據和 Secret 一起散列,生成一個散列字符串,在鈎子文件中需要對這個散列字符串進行驗證。
-
對於其它代碼托管平台,有的不提供 Secret 字段,有的 Secret 在鈎子文件中直接驗證,具體使用還需要研究一下官方說明
-
-
注: