使用 Git 的 webhooks 进行自动化部署

前一阵子我其实是想用 Google drive + incron 的方式自动提交博客,然而碰到了一些问题,Goole drive 可以同步文件夹,但不能自动同步文件夹,并且没有 git 这样优秀的版本控制。
而我又不想自己手动上传文章以及拉取文章,拉取之后还得手工 hexo g,太麻烦了。
写定时拉取,自动更新的确可以,但是这样太没逼格了。
于是我就查资料,发现了 git 有 webhooks。

什么是 Webhooks

先放几个官方的说明:

简单概括一下(译自 Github Webhooks):

  • Webhooks 允许我们建立关于项目的在 GitHub 上的事件集成. 当事件触发的时候, 会通过 HTTP POST 的方式, 向我们的服务器发送请求. 我们可以用这个服务器去更新外部跟踪, 触发 CI build, 更新备份镜像, 部署到生产服务器.
  • 每个 Webhook 都可以安装在一个项目或者组织上, 安装完毕之后, 就可以随着订阅的时间进行触发.
  • 每个项目的每个事件最多可以安装 20 个 Webhook.

Webhooks 脚本

Webhook 脚本实现可以用 PHP、NodeJS 等,本文仅介绍 PHP 脚本,笔者也用的这个脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
<?php
// 本地仓库路径
$local = '/var/www/html/';

// 安全验证字符串,为空则不验证
$token = '123456';

// 如果启用验证,并且验证失败,返回错误
$httpToken = isset($_SERVER['HTTP_X_GITLAB_TOKEN']) ? $_SERVER['HTTP_X_GITLAB_TOKEN'] : '';
if ($token && $httpToken != $token) {
header('HTTP/1.1 403 Permission Denied');
die('Permission denied.');
}

// 如果仓库目录不存在,返回错误
if (!is_dir($local)) {
header('HTTP/1.1 500 Internal Server Error');
die('Local directory is missing');
}

// 如果请求体内容为空,返回错误
$payload = file_get_contents('php://input');
if (!$payload) {
header('HTTP/1.1 400 Bad Request');
die('HTTP HEADER or POST is missing.');
}

/*
* 这里有几点需要注意:
*
* 1. 确保 PHP 正常执行系统命令。写一个 PHP 文件,内容:
* `<?php shell_exec('ls -la')`
* 在通过浏览器访问这个文件,能够输出目录结构说明 PHP 可以运行系统命令。
*
* 2、PHP 一般使用 www-data 或者 nginx 用户运行,PHP 通过脚本执行系统命令也是用这个用户,
* 所以必须确保在该用户家目录(一般是 / home/www-data 或 / home/nginx)下有. ssh 目录和
* 一些授权文件,以及 git 配置文件,如下:
* ```
* + .ssh
* - authorized_keys
* - config
* - id_rsa
* - id_rsa.pub
* - known_hosts
* - .gitconfig
* ```
*
* 3. 在执行的命令后面加上 2>&1 可以输出详细信息,确定错误位置
*
* 4.git 目录权限问题。比如:
* `fatal: Unable to create'/data/www/html/awaimai/.git/index.lock': Permission denied`
* 那就是 PHP 用户没有写权限,需要给目录授予权限:
* ``
* sudo chown -R :www-data /data/www/html/awaimai`
* sudo chmod -R g+w /data/www/html/awaimai
* ```
*
* 5.SSH 认证问题。如果是通过 SSH 认证,有可能提示错误:
* `Could not create directory'/.ssh'.`
* 或者
* `Host key verification failed.`
*
*/
echo shell_exec("cd {$local} && git pull 2>&1");
die("done " . date('Y-m-d H:i:s', time()));

Webhooks 配置

像图片中这样设置就可以了


注意事项

如果不能正常的拉取,你可以先使用下面的 php 程序进行测试。

1
2
3
4
<?php
$output = shell_exec('ls -lart');
echo "<pre>$output</pre>";
?>

如果网页不能够输出你当前的文件夹下的文件,说明 shell_exe() 函数被禁用了,你需要修改 php.ini,启用该函数

然后用下面的 php 程序接着测试

1
2
3
4
5
6
7
<?php
// 本地仓库路径
$local = '/var/www/html/';

echo shell_exec("cd {$local} && git pull 2>&1");
die("done" . date('Y-m-d H:i:s', time()));
?>

看看输出的信息。在执行的命令后面加上 2>&1 可以输出详细信息,确定错误位置。

一般情况下有 3 种错误:

  • 权限不足
  • ssh 认证错误
  • 不能读写文件

对于权限不足,你需要给网站 www 或则 nginx 用户组权限,不是 777 这样的权限,因为 PHP 一般使用 www 或者 nginx 用户运行,PHP 通过脚本执行系统命令也是用这个用户。一般可以用下面的命令解决,具体还是要看你的环境:

1
2
sudo chown -R www:www /data/www/
sudo chmod -R g+w /data/www/

对于 ssh 认证错误,你需要保证 www 或则 nginx 用户组的文件夹下有. ssh 目录(一般是 / home/www 或 / home/nginx)和一些授权文件,以及 git 配置文件,如下:

1
2
3
4
5
6
7
+ .ssh
- authorized_keys
- config
- id_rsa
- id_rsa.pub
- known_hosts
- .gitconfig

而且你需要在 Github、Gitlab、Gitee 中加入你的公钥。具体你可以百度谷歌一下。
输入下面的命令就可以了

1
ssh-keygen -t rsa

参考资料 & 转载来源

部分内容是转载自:
Github、GitLab、Gitee 使用 Webhooks 实现代码自动部署
其他优秀参考资料:
gitlab 利用 webhook 自动部署代码
利用 GitLab 的 Webhooks 功能,实现网站代码自动更新部署
给你的项目增加 Webhooks,自动进行部署(包含 Github/Gitlab)
使用 Gitlab Webhooks 自动部署代码
使用 GitHub / GitLab 的 Webhooks 进行网站自动化部署
git webhooks 实现自动拉取代码
利用 WebHook 实现 PHP 自动部署 Git 代码
使用 Git 的 Webhooks 进行服务器自动部署代码
使用 Github 的 webhooks 进行网站自动化部署

坚持原创技术分享,您的支持将鼓励我继续创作!