使用GitHub的Webhooks实现代码的自动部署
前言
前段时间搞了个小项目放到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
设置Webhooks
这里面的坑
如果发现推送返回以下的错误信息:
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 协议》,转载必须注明作者和本文链接
推荐文章: