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,这个应该是没有问题的

扫描二维码关注公众号,回复: 11238726 查看本文章

然后我们需要克隆代码下来,这里需要注意的是用户组和权限的问题

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,就可以使用了

猜你喜欢

转载自blog.csdn.net/weixin_36851500/article/details/104011450