前段時間搞了個小專案放到GitHub
上面,剛開始的時候,在本地push
後,然後在到伺服器上面執行pull
拉取,還不覺得有多麻煩,但是後面更新比較頻繁的時候,就覺得十分的繁瑣,所以我就使用GitHub
自帶的Webhooks
來實現自動部署。
使用GitHub
自帶的Webhooks
的自動部署邏輯。
- 本地修改程式碼,然後push提交
- github傳送請求給你的網站伺服器
- 網站伺服器收到更新請求,執行自動部署指令碼
- 自動部署指令碼執行程式碼拉取等動作完成網站的更新部署
這裡的鉤子就是被請求的URL
,如果你只有一個專案的話,你就可以把鉤子直接寫到你的專案裡面,如果有多個專案要管理的話,最好是單獨建一個專案去管理,這樣比較好管理一些。
我只有一個專案所以,我就寫到專案裡面的,我用的是laravel
框架。
這裡我為什麼要自己寫一個執行shell的方法呢?因為shell_exec/exec/system/passthru
這些函式對錯誤資訊太不友好了。我大部分時間都耗在了排查錯誤上面,而且這些函式很有可能是被禁用掉的。
//github 專案鉤子
public function hook(Request $request){
//webhook中設定的Secret
$secret_token = env("WEBHOOK_SECRET_TOKEN");
//驗證簽名
$hub_signature = $request->header('X-Hub-Signature',"");//這個是GitHub返回來的簽名
if(empty($hub_signature)){
Log::info("無效的鉤子請求");
return "";
}
//這是簽名演算法
$signature = "sha1=".hash_hmac('sha1', $request->getContent(),$secret_token);
//$request->getContent()是請求內容
//如果你用的不是laravel,還可以使用file_get_contents("php://input")獲取
if(strcmp($signature,$hub_signature) == 0){
//簽名驗證成功,執行shell命令
$webPath = "/home/www/xxxxx";//生產環境下專案的目錄地址
$cmd = "cd $webPath && git pull origin master";//shell 命令
$res = $this->doShell($cmd);
Log::info("執行shell命令返回資料:".json_encode($res));
//返回資訊,給GitHub記錄
print_r(json_encode($res));
}else{
Log::info("鉤子請求籤名驗證失敗");
}
}
//執行shell命令
private function doShell($cmd, $cwd = null) {
$descriptorspec = array(
0 => array("pipe", "r"), // stdin
1 => array("pipe", "w"), // stdout
2 => array("pipe", "w"), // stderr
);
$proc = proc_open($cmd, $descriptorspec, $pipes, $cwd, null);
// $proc為false,表明命令執行失敗
if ($proc == false) {
Log::info("shell 命令:".$cmd." 執行失敗");
return false;
} else {
$stdout = stream_get_contents($pipes[1]);
fclose($pipes[1]);
$stderr = stream_get_contents($pipes[2]);
fclose($pipes[2]);
$status = proc_close($proc); // 釋放proc
}
$data = array(
'stdout' => $stdout, // 標準輸出
'stderr' => $stderr, // 錯誤輸出
'retval' => $status, // 返回值
);
return $data;
}
GitHub官方建議不要把Secret放到程式碼裡面,官方是建議把Secret放到環境變數裡面
把這個程式碼放到任意一個控制器中就行,然後配置好路由就行。該方法是POST
請求,所以你不能驗證CSRF-TOKEN
,我是直接把這個路由放到api
路由下面的
如果你不只是拉取程式碼,如還需要打包等,就可以先寫一個shell指令碼,然後在
pull
後執行指令碼,cd $webPath && git pull origin master && /bin/bash dabao.sh
如果發現推送返回以下的錯誤資訊:
Host key verification failed.
fatal: Could not read from remote repository.
Please make sure you have the correct access rights and the repository exists.
首先判斷你執行指令碼的使用者(我的是www
使用者)的ssh-key
是否加到了GitHub
裡面,如果沒有就生成加入。
//為www使用者生成ssh-key
sudo -Hu www ssh-keygen -t rsa -C "github賬號的郵箱"# 請選擇 "no passphrase",一直回車下去
//我是用的root使用者給www使用者生成ssh-key的,如果你是登入的就是www使用者,執行下面的命令就行
ssh-keygen -t rsa -C "github賬號的郵箱"
-Hu www 命令:
-u 代表切換到哪一個使用者,這裡說的是www
-H 代表切換HOME環境變數的值,也就是password檔案中www使用者對應的home目錄
百度上面基本就是說沒有配置ssh-key
,但是我配置了的,還是會返回這個錯誤。
這個是因為你執行指令碼的使用者,是第一次連線GitHub
,所以會彈出一個是否把遠端地址加入到konw_host
,我們執行的shell
是回車操作,但是直接回車,則預設沒有許可權寫入,必須輸入yes
才能正確寫入 konw_host
。
解決方法:
1.我們可以在
ssh_config
配置檔案中降低安全配置級別,不做提示,直接加入到konw_host
。#開啟ssh_config /etc/ssh/ssh_config #找到: StrictHostKeyChecking ask 修改為: StrictHostKeyChecking no
但是我不建議這樣做。或者當加入到
konw_host
後,你再把安全配置改回來。2.登陸你執行指令碼的使用者,然後使用這個使用者去專案庫裡面拉取一次,然後你輸入
yes
就行了。
更多文章參考我的部落格
本作品採用《CC 協議》,轉載必須註明作者和本文連結