本文是利用nginx的proxypass来做代理到workerman创建的webserver上,从而使得github的git webhook可以起作用。
代码不复杂
1、准备一个composer.json,内容超短:
{"name":"auto deploy","authors":[{"name":"gouki","email":"neatcn@qq.com"},"require":{"workerman/workerman":"dev-master"},"license":"MIT"]}
2、复制下面的代码,并赋予可执行权限(也可以不赋予,直接使用php xxx.php start 即可)
#!/usr/bin/env php
<?php
/**
* composer.json的内容,如果不依赖其他系统,则runtime目录设置为/,同时设置PORT
* {"name":"auto deploy","authors":[{"name":"gouki","email":"neatcn@qq.com"},"require":{"workerman/workerman":"dev-master"},"license":"MIT"]}
* 使用方法:
* php {filename} start -d
* php {filename} reload -g -d
* php {filename} stop -g
*/
use Workerman\Connection\ConnectionInterface;
use Workerman\Worker;
include __DIR__ . "/vendor/autoload.php";
// define('ROOT_PATH', __DIR__);
//http server的端口,用于给nginx做反代,不要和其他程序有冲突
define('HTTP_SERVER', "http://0.0.0.0:8002");
//存放LOG的位置,记得以 / 结尾
define('RUNTIME_PATH', __DIR__ . "/runtime/");
//commit message中的关键字,检测到后才需要更新,如果留空。则全部更新
// define('DEPLOY_KEYWORD','deploy');
Worker::$pidFile = RUNTIME_PATH . str_replace('/', '_', __FILE__) . ".pid";
$config = [
'demo.neatstudio.com' => [
'target' => '/server/wwwroot/yzhan/neatstudio.com',
'secret' => '123456',
//commit message中的关键字,检测到后才需要更新,如果留空。则全部更新
'keyword' => 'deploy',
'commands' => [],
]
];
$worker = new Worker(HTTP_SERVER);
$worker->count = 1;
$worker->reloadable = false;
$worker->onWorkerStart = function() {
};
$worker->onError = function(ConnectionInterface $connection) {
$connection->close(resp_error_msg("ERROR", ['request' => func_get_args()]));
};
$worker->onMessage = function(ConnectionInterface $connection, $data) use ($config) {
// echo(sprintf("[%s]IP: %s:%s , Data: %s", date("Y-m-d H:i:s"), $connection->getRemoteIp(), $connection->getRemotePort(), var_export($data, true)));
$server = $data['server'];
if($server['CONTENT_TYPE'] === "application/x-www-form-urlencoded"){
$post = json_decode($data['post']['payload'], true);
} else{
$post = $data['post'];
}
$repository = $post['repository']['name'] ?? "";
$commitMsg = $post['head_commit']['message'] ?? "";
if(!isset($config[$repository])){//配置资源
$connection->close(resp_error_msg('GIT资源未配置'));
return;
}
$deployKeyword = $config[$repository]['keyword'];
//只有有关键字的时候才会部署
if($commitMsg && $deployKeyword && strpos($commitMsg, $deployKeyword) === false){
$connection->close(resp_error_msg('未检测到关键字,不用部署'));
return;
}
// echo $server['HTTP_X_HUB_SIGNATURE'], "\n";
// echo "sha1=" . hash_hmac('sha1', $GLOBALS['HTTP_RAW_REQUEST_DATA'], $config[$repository]['secret']), "\n";
if(strpos($server['HTTP_USER_AGENT'], "GitHub-Hookshot/") === false ||
$server['HTTP_X_HUB_SIGNATURE'] !== "sha1=" . hash_hmac('sha1', $GLOBALS['HTTP_RAW_REQUEST_DATA'], $config[$repository]['secret'])){
$connection->close(resp_success_msg('数据校验失败'));
return;
}
$ret = '';
//开始执行
$commands = [
"cd {$config[$repository]['target']} ",
"git fetch --all",
"git reset --hard origin/master",
"./yii cache/flush-schema --interactive=0",
];
$commands = array_merge($commands, $config[$repository]['commands'] ?? []);
exec(join(" && ", $commands), $ret);
// exec("cd {$config[$repository]['target']} && git fetch --all && git reset --hard origin/master && ./yii cache/flush-schema --interactive=0 ", $ret);
$connection->close(resp_success_msg('更新成功', $ret));
};
Worker::$logFile = RUNTIME_PATH . "workerman.log";
Worker::runAll();
function resp_json($data, $message = '', $is_error = 0)
{
$result['status'] = 0;
if($is_error){
$result['error'] = $data;
} else{
$result['status'] = 1;
$result['datas'] = $data;
}
$result['message'] = $message;
return json_encode($result, JSON_UNESCAPED_UNICODE);
}
function resp_success($data)
{
return resp_json($data);
}
function resp_success_msg($message, $data = [])
{
return resp_json($data, $message);
}
function resp_error($data)
{
return resp_json($data, '', 1);
}
function resp_error_msg($message, $data = [])
{
return resp_json($data, $message, 1);
}
是不是基本上控制 在100行内?因为访问量不会太大。所以我设置worker->count = 1,即,只启用一个子进程。
有人会说了,其实写一个PHP文件就可以了,设置为web目录指定一个域名不就完事了吗?是的,你说的这样其实也行,但有一点,如果你需要执行git命令还有使用exec命令,可能你的权限就不足了。而且。如果你的GIT是 采用root权限来git pull的。你拉回来的文件的owner都是root,这时候还需要执行chown -R www-data:www-data . 来处理,如果你是当成web项目来做,可能你就没有这个权限。
因此workerman就有了这样的功能。毕竟他是以root权限来运行的(也可以指定其他权限,如果指定非www-data[ubuntu/debian],你还得有权限设置目录的用户组)
-----
对比wallE和那个女娲系统,我这个是超级简单了。只有一个文件。而且不能远程操作(远程操作建议使用本程序+ansible),是不是也简单的够你用了,至少比以前写的 每分钟执行git pull一次好很多,workerman也支持多线程和多进程。性能也不差