根据业务需求,已部署GitLab-CE,网站代码上线流程如下图:
开发者 push 推送代码之后,网站代码仍没更新,还需要操作多一步:登录前端web服务器,手动git pull 拉取更新的代码。这一步是运维的工作,很无趣又烦琐。
幸亏,GitLab提供了Webhooks功能,可以轻松实现网站代码自动更新部署。
一、webhooks原理
Project webhooks allow you to trigger a URL if for example new code is pushed or a new issue is created.
You can configure webhooks to listen for specific events like pushes, issues or merge requests. GitLab will send a POST request with data to the webhook URL.
Webhooks can be used to update an external issue tracker, trigger CI jobs, update a backup mirror, or even deploy to your production server.
简单说明
webhooks允许指定一个URL,用于触发push或其他事件时进行自定义操作。
例如,当开发者push代码到GitLab服务器,会触发push事件,GitLab会发送一个POST请求连带数据(数据格式)给webhooks指定的URL,该URL可以是前端web的php程序或Python程序等。这样,每当GitLab有push事件,就能在前端web服务器上执行一个脚本程序。
使用webhooks的步骤:
- 在前端web服务器上安装Git客户端,用于拉取远程仓库 git pull
- 创建并添加公钥,以便免密码拉取远程仓库
- 创建脚本程序,并配置webhooks
二、安装Git客户端
在前端web服务器上,执行以下安装命令
# yum install git
三、创建并添加公钥
前端web服务器的 nginx 和 php-fpm 都是以 www 用户来运行的,所以要为www用户创建并添加公钥。
www 用户的家目录是: /home/www/
修改 www 用户的 shell 为 /bin/bash
www:x:511:511::/home/www:/bin/bash
创建用户的公钥
# su www
$ ssh-keygen -t rsa
遇到交互,全部回车就好。
最后会在/home/www/.ssh 目录下生成两个文件,私钥文件:id_rsa,公钥文件:id_rsa.pub
添加公钥到GitLab后台
获取www用户的公钥文件内容:
cat /home/www/.ssh/id_rsa.pub
复制公钥内容,添加公钥,GitLab后台添加公钥的位置:管理员 > Settings > SSH Keys
修改网站根目录的权限
修改网站根目录( /home/www/test/ ) 的权限,否则以www用户git pull 会报权限问题。
# chmod 775 /home/www/test/ -R
# chown www.www /home/www/test/ -R
测试
测试www用户基于公钥是否能从Git服务器远程拉取代码
手动执行pull操作
# su www
$ cd /home/www/test/
$ git pull
四、部署webhooks
编写webhooks应用的PHP程序
在前端web服务器的网站根目录(/home/www/test/)下新建一个webhooks.php
<?php
//网站目录
$www_file='/home/www/test/';
//打开网站目录下的hooks.log文件,需要在服务器上创建,并给写权限
$fs = fopen('/home/www/test/hooks.log', 'a');
fwrite($fs, '================ Update Start ==============='.PHP_EOL.PHP_EOL);
//自定义字串掩码 用于验证
$access_token = 'QhNO8YHqym5PHQQsexapF7041xOhzm62DRH';
//接受的ip数组,也就是允许哪些IP访问这个文件 这里是gitlab服务器IP
$access_ip = array('192.168.1.15','14.xxx.xxx.19');
//如果使用www.xxx.com/xxx.php?token=xxxxxxx 的方式来传送验证字符串,则用这个方法获取
# $client_token = $_GET['token'];
// 获取请求端的secret token
$client_token = $_SERVER["HTTP_X_GITLAB_TOKEN"];
//获取请求端的IP
$client_ip = $_SERVER['REMOTE_ADDR'];
//把请求的IP和时间写进log
fwrite($fs, 'Request on ['.date("Y-m-d H:i:s").'] from ['.$client_ip.']'.PHP_EOL);
//验证token 有错就写进日志并退出
if ($client_token !== $access_token)
{
echo "error 403";
fwrite($fs, "Invalid token [{$client_token}]".PHP_EOL);
exit(0);
}
//验证ip
if ( !in_array($client_ip, $access_ip))
{
echo "error 503";
fwrite($fs, "Invalid ip [{$client_ip}]".PHP_EOL);
exit(0);
}
//获取请求端发送来的信息,具体格式参见gitlab的文档
$json = file_get_contents('php://input');
$data = json_decode($json, true);
//如果有需要 可以打开下面,把传送过来的信息写进log
# fwrite($fs, 'Data: '.print_r($data, true).PHP_EOL);
//执行shell命令并把返回信息写进日志
$output=shell_exec("cd $www_file && git pull 2>&1");
fwrite($fs, 'Info:'. $output.PHP_EOL);
fwrite($fs,PHP_EOL. '================ Update End ==============='.PHP_EOL.PHP_EOL);
$fs and fclose($fs);
?>
修改PHP配置
因为webhooks用到的php代码中使用了 shell_exec 函数,一般配置php会禁止这个函数,需要打开 shell_exec 函数。
修改前端web服务器上php.ini的 disable_functions 列表,去掉 shell_exec 。
重启php-fpm服务。
配置GitLab
project > Settings > Integrations
Secret Token中字符串的值,要跟webhooks.php中$access_token 的值相同。
Enable SSL verification 不要勾。
可以按 [Test] 按钮,测试配置是否生效。
五、遇到的问题
在部署webhooks中,遇到了个很诡异的问题。
前提说明
GitLab-CE 版本:9.2.6
使用xhang项目对GitLab-CE进行汉化过
问题描述:
已成功部署webhooks,按 [Test] 按钮测试正常。
但在实际使用中,开发者push代码后,webhooks.php没有被执行,前端web代码没有git pull 记录,日志也没有记录。GitLab没有检测到开发者的push事件。
问题分析:
- 通过另外部署一套同版本的、不打汉化补丁的GitLab-CE,发现不是汉化补丁的问题。
- 回想起之前遇到的一个问题,在GitLab-CE上新创建test项目时,开发者push后,GitLab上仍然显示该项目是空项目,无法检测到push事件,后来还是通过修改项目名来使得其能识别push事件。
问题解决:
后来偶然发现,webhooks时GitLab没有及时检测到开发者的push事件,是因为对 /var/opt/gitlab/ 目录做了软链接的缘故。
去掉软链接,改为正常的目录路径。