准备工作
在服务器上安装 Git, 基本操作不做赘述
git 配置 ssh
# 1. 首先查看是否配置过密钥
ls ~/.ssh
# 2. 如有则跳过此步骤,没有则执行以下命令创建 rsa 密钥对(邮箱换成自己的),然后全程回车使用默认配置即可
ssh-keygen -t rsa -C "xxxxx@xxxxx.com"
# 3. 查看公钥内容,然后复制(注意:公钥内容以ssh-rsa开头,邮箱结尾,前后不能有空格)
cat ~/.ssh/id_rsa.pub
- 进入 github SSH keys/ Add new 界面,在 Key 下粘贴公钥,Title 尽量设置成公钥所在服务器或者电脑的名称
Webhooks 接收脚本编写
这里以 PHP 代码为例,脚本访问 URL 为后面 github 中 Webhooks 的 Payload URL 配置
# webhooksReceiver.php
<?php
date_default_timezone_set("Asia/Shanghai");
// 填写自己项目根目录绝对路径
$applicationPath = "/usr/share/nginx/html/application";
// 这里是在 github webhooks页面设置的 Secret
$secret = "qwertyblabla";
// github webhooks 请求头中的签名
$signature = $_SERVER['HTTP_X_HUB_SIGNATURE'];
if (!$signature) {
return http_response_code(404);
}
// github webhooks 请求体 Payload 内容
$payloadJson = file_get_contents("php://input");
$content = json_decode($payloadJson, true);
list($algo, $hash) = explode("=", $signature, 2);
// 组装 webhooks 请求信息
$pushInfo = "{$content['head_commit']['author']['name']} 在 " . date('Y-m-d H:i:s') . PHP_EOL;
$pushInfo .= "向 {$content['repository']['name']} 项目的 {$content['ref']} 分支 " .PHP_EOL;
$pushInfo .= "push 了 " . count($content['commits']) . " 个commit: " . PHP_EOL;
// 验签
$payloadHash = hash_hmac($algo, $payloadJson, $secret);
if ($hash === $payloadHash) {
$ret = shell_exec("cd {$applicationPath} && sudo git pull origin master");
$responseLog = "Success: " . PHP_EOL;
$responseLog .= $pushInfo . $ret . PHP_EOL . PHP_EOL;
} else {
$responseLog = "Error: " . PHP_EOL;
$responseLog .= "{$pushInfo} 验签失败" . PHP_EOL . PHP_EOL;
}
// 输出响应内容,可在 github webhooks - Recent Deliveries 中的 Response Body 中查看
echo $responseLog;
// 记录 webhooks 请求日志
file_put_contents("/tmp/webhooks.log", $responseLog);
Github 项目下 Webhooks 配置
- 进入 github 个人项目下点击 settings,然后点击 Webhooks --> Add webhook
- 依次填入 Payload URL(上面的接收脚本访问url),Content type 选择 application/json,Secret 和脚本中 secret 保持一致,默认使用 push 事件触发,提交
配置完毕,此时提交一些改动推送到 Github 上,进入刚刚配置好的 webhooks 查看 Recent Deliveries 详情中的 Response,如下图
如返回成功且项目代码成功更新,则配置完成。
如返回失败,可使用图中的 Redeliver 按钮重新发送请求进行调试
在 Payload URL、Content type、Secret 都配置正确,Response 200 且有 Success 返回的情况下,如果 Response Body 底下没有
git pull
的相关信息输出且服务器代码没有同步更新,可能是因为 PHP 进程用户没有运行git pull
的权限
解决 PHP 进程用户执行命令权限问题
- 查看 php 进程用户名,如果是 nobody,继续 步骤 2,如果有用户名不是 nobody 则跳过 步骤 2
ps -ef | grep php
- 添加用户组、用户,修改 php 配置文件
# 1. 添加用户组,以 www 为例
/usr/sbin/groupadd www
# 2. 添加用户,同样以 www 为例
/usr/sbin/useradd -g www -s /bin/bash www
# 3. 修改 php 配置文件(换成自己的文件路径),找到 user 和 group 将用户和用户组修改成 www
vi /etc/opt/remi/php72/php-fpm.d/www.conf
# 4. 重启 php-fpm 使用上面 `ps -ef | grep php` 得到的 php-fpm master 进程 id(比如是 12345)
kill -SIGUSR2 12345
# 5. 查看 php 进程的用户名是否已更新
ps -ef | grep php
- 修改 sudoers
# 1. 给 sudoers 添加可写权限
chmod +w /etc/sudoers
# 2. 在 sudoers 中加入 `www ALL=(ALL) NOPASSWD: ALL` (允许 www 用户组不用密码执行任何命令)
echo "www ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers
# 3. 移除 sudoers 可写权限
chmod -w /etc/sudoers
最后,Redeliver 按钮点一下,git pull
信息正常输出,问题解决。
以上,Van(完)。