2023-02-28 12:48:03 +00:00
|
|
|
|
#!/usr/bin/env php
|
2023-02-08 13:35:01 +00:00
|
|
|
|
<?php
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 节点 ID
|
|
|
|
|
$node_id = '{{NODE_ID}}';
|
|
|
|
|
|
|
|
|
|
// Nginx 单个站点的配置文件路径
|
|
|
|
|
$nginx_conf_path = '/path/to/api.laecloud.com.conf';
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** 自动生成的配置文件,如有变动,按照需求编辑。 **/
|
|
|
|
|
$redis_info = [
|
|
|
|
|
'host' => '{{REDIS_HOST}}',
|
|
|
|
|
'port' => '{{REDIS_PORT}}',
|
|
|
|
|
'password' => '{{REDIS_PASSWORD}}',
|
|
|
|
|
'prefix' => '{{REDIS_PREFIX}}',
|
|
|
|
|
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** 好了,不要再编辑了。配置到此为止了。 **/
|
|
|
|
|
$nginx_conf = '';
|
|
|
|
|
$nginx_file_md5 = '';
|
|
|
|
|
|
|
|
|
|
$prefix = $redis_info['prefix'];
|
|
|
|
|
|
|
|
|
|
// 检查是否存在配置文件
|
2023-02-28 12:48:03 +00:00
|
|
|
|
if (!file_exists($nginx_conf_path)) {
|
2023-02-08 13:35:01 +00:00
|
|
|
|
echo 'nginx.conf not found';
|
|
|
|
|
exit;
|
|
|
|
|
} else {
|
|
|
|
|
$nginx_conf = file_get_contents($nginx_conf_path);
|
|
|
|
|
$nginx_file_md5 = md5_file($nginx_conf_path);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 检查redis_info是否正确
|
|
|
|
|
foreach ($redis_info as $key => $value) {
|
|
|
|
|
if (empty($value)) {
|
|
|
|
|
echo "redis_info[$key] is empty";
|
|
|
|
|
exit;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$redis = new Redis();
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
$redis->connect($redis_info['host'], $redis_info['port']);
|
|
|
|
|
$redis->auth($redis_info['password']);
|
|
|
|
|
|
|
|
|
|
// set db 0
|
|
|
|
|
$redis->select(0);
|
|
|
|
|
} catch (RedisException $e) {
|
2023-02-28 12:48:03 +00:00
|
|
|
|
echo 'Connection to Redis failed: ' . $e->getMessage();
|
2023-02-08 13:35:01 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
try {
|
2023-02-10 04:14:18 +00:00
|
|
|
|
if ($redis->ping('')) {
|
2023-02-08 13:35:01 +00:00
|
|
|
|
output('redis is ok');
|
|
|
|
|
}
|
|
|
|
|
} catch (RedisException $e) {
|
|
|
|
|
output('redis is error');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 检验环境
|
|
|
|
|
// 检测 Nginx 是否存在 which nginx
|
|
|
|
|
$nginx_path = trim(shell_exec('which nginx'));
|
|
|
|
|
if (empty($nginx_path)) {
|
|
|
|
|
echo 'nginx not found';
|
|
|
|
|
|
|
|
|
|
redis_publish('edge.error', [
|
|
|
|
|
'message' => '此节点上并没有安装 Nginx ,但是 Edge 被启动了,现在已经退出。',
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
exit;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
redis_publish('edge.launched');
|
|
|
|
|
|
|
|
|
|
$last_run_at = time() - 100;
|
|
|
|
|
|
|
|
|
|
$ip = '';
|
|
|
|
|
|
|
|
|
|
// 获取本机 IP ifconfig.me
|
|
|
|
|
$ip = trim(shell_exec('curl -s ifconfig.me'));
|
|
|
|
|
|
|
|
|
|
$run_count = 0;
|
|
|
|
|
|
|
|
|
|
// 逻辑部分
|
|
|
|
|
while (true) {
|
|
|
|
|
if ($run_count >= 10000) {
|
|
|
|
|
$run_count = 0;
|
|
|
|
|
|
|
|
|
|
// 重新获取 IP
|
|
|
|
|
$ip = trim(shell_exec('curl -s ifconfig.me'));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
redis_hset('nodes', $node_id, [
|
|
|
|
|
'type' => 'edge',
|
2023-02-28 12:48:03 +00:00
|
|
|
|
'id' => 'edge-' . $node_id,
|
2023-02-08 13:35:01 +00:00
|
|
|
|
'ip' => $ip,
|
|
|
|
|
// utc +8 timestamp
|
|
|
|
|
'last_heartbeat' => time(),
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
// 上次运行时间需要满 60s,才继续,否则 continue
|
|
|
|
|
if (time() - $last_run_at < 60) {
|
|
|
|
|
sleep(1);
|
|
|
|
|
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 重新载入 nginx.conf
|
2023-02-28 12:48:03 +00:00
|
|
|
|
if (!file_exists($nginx_conf_path)) {
|
2023-02-08 13:35:01 +00:00
|
|
|
|
echo 'nginx.conf not found';
|
|
|
|
|
|
|
|
|
|
redis_publish('edge.error', [
|
|
|
|
|
'message' => 'Nginx 配置文件在启动后被删除,Edge 进程退出。',
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
exit;
|
|
|
|
|
} else {
|
|
|
|
|
$nginx_conf = file_get_contents($nginx_conf_path);
|
|
|
|
|
$nginx_file_md5 = md5_file($nginx_conf_path);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 检查 laecloud_database_cluster:nodes 是否存在
|
|
|
|
|
try {
|
2023-02-28 12:48:03 +00:00
|
|
|
|
if (!$redis->exists($prefix . 'cluster:nodes')) {
|
2023-02-08 13:35:01 +00:00
|
|
|
|
output('cluster:nodes not found');
|
|
|
|
|
}
|
|
|
|
|
} catch (RedisException $e) {
|
|
|
|
|
output('redis is error');
|
|
|
|
|
}
|
|
|
|
|
|
2023-02-10 04:14:18 +00:00
|
|
|
|
$nodes = redis_hgetAll('nodes');
|
2023-02-28 12:48:03 +00:00
|
|
|
|
if (!$nodes) {
|
2023-02-08 13:35:01 +00:00
|
|
|
|
output('nodes is empty');
|
|
|
|
|
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
foreach ($nodes as $node) {
|
|
|
|
|
// if node last_heartbeat(utc+8 timestamp) is over 10s, skip
|
|
|
|
|
if (time() - $node['last_heartbeat'] > 10) {
|
|
|
|
|
// 删除节点
|
|
|
|
|
redis_hdel('nodes', $node['id']);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$conf = '';
|
|
|
|
|
|
|
|
|
|
foreach ($nodes as $node) {
|
|
|
|
|
// only allow node type master, slave
|
2023-02-28 12:48:03 +00:00
|
|
|
|
if (!in_array($node['type'], ['master', 'slave'])) {
|
2023-02-08 13:35:01 +00:00
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2023-02-28 12:48:03 +00:00
|
|
|
|
output('node_type: ' . $node['type']);
|
|
|
|
|
output('node_id: ' . $node['id']);
|
2023-02-08 13:35:01 +00:00
|
|
|
|
output('================================================================');
|
|
|
|
|
|
|
|
|
|
$temp_conf = "#node {$node['type']}:{$node['id']}\n";
|
|
|
|
|
$temp_conf .= "server {$node['ip']}";
|
|
|
|
|
|
|
|
|
|
if (isset($node['weight'])) {
|
2023-02-10 04:14:18 +00:00
|
|
|
|
if ($node['weight'] !== '0') {
|
2023-02-09 10:59:27 +00:00
|
|
|
|
$temp_conf .= " weight={$node['weight']} ";
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
$temp_conf .= ' weight=1 ';
|
2023-02-08 13:35:01 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ($node['type'] == 'master') {
|
|
|
|
|
if (count($nodes) <= 2) {
|
2023-02-11 16:29:05 +00:00
|
|
|
|
$temp_conf .= ' backup ';
|
2023-02-08 13:35:01 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-02-11 16:29:05 +00:00
|
|
|
|
$temp_conf .= ' max_fails=1 fail_timeout=10s ';
|
|
|
|
|
|
2023-02-08 13:35:01 +00:00
|
|
|
|
$temp_conf .= ";\n";
|
|
|
|
|
|
2023-02-28 12:48:03 +00:00
|
|
|
|
echo $temp_conf . PHP_EOL;
|
2023-02-08 13:35:01 +00:00
|
|
|
|
|
|
|
|
|
output('================================================================');
|
|
|
|
|
|
2023-02-28 12:48:03 +00:00
|
|
|
|
$conf .= $temp_conf . PHP_EOL;
|
2023-02-08 13:35:01 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
output('!!!!!!!!!!!!!!!!!');
|
|
|
|
|
echo $conf;
|
|
|
|
|
output('!!!!!!!!!!!!!!!!!');
|
|
|
|
|
|
|
|
|
|
$add_header = <<<EOF
|
2023-02-10 04:14:18 +00:00
|
|
|
|
add_header 'Cluster-Ready-Node-Id' 'edge-$node_id';
|
2023-02-08 13:35:01 +00:00
|
|
|
|
add_header 'Powered-by' 'Cluster Ready!';
|
|
|
|
|
EOF;
|
|
|
|
|
|
|
|
|
|
// 放入配置文件,以 ##########CLUSTERREADY######### 开始,以 ##########END_CLUSTERREADY######### 结束
|
2023-02-28 12:48:03 +00:00
|
|
|
|
$nginx_conf = preg_replace('/##########CLUSTERREADY#########.*##########END_CLUSTERREADY#########/s', '##########CLUSTERREADY#########' . PHP_EOL . $conf . '##########END_CLUSTERREADY#########', $nginx_conf);
|
|
|
|
|
$nginx_conf = preg_replace('/##########CLUSTERREADY_PROXY#########.*##########END_CLUSTERREADY_PROXY#########/s', '##########CLUSTERREADY_PROXY#########' . PHP_EOL . $add_header . PHP_EOL . '##########END_CLUSTERREADY_PROXY#########', $nginx_conf);
|
2023-02-08 13:35:01 +00:00
|
|
|
|
|
|
|
|
|
if (md5($nginx_conf) != $nginx_file_md5) {
|
|
|
|
|
file_put_contents($nginx_conf_path, $nginx_conf);
|
|
|
|
|
output('nginx.conf is changed, reload nginx');
|
|
|
|
|
|
|
|
|
|
// reload nginx
|
|
|
|
|
exec('nginx -s reload');
|
|
|
|
|
|
|
|
|
|
output('nginx is reloaded.');
|
|
|
|
|
|
|
|
|
|
// 收尾
|
|
|
|
|
redis_publish('edge.deployed');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$last_run_at = time();
|
|
|
|
|
|
|
|
|
|
$run_count++;
|
|
|
|
|
}
|
|
|
|
|
function output($context): void
|
|
|
|
|
{
|
|
|
|
|
$time_string = date('Y-m-d H:i:s');
|
2023-02-28 12:48:03 +00:00
|
|
|
|
echo $time_string . ': ' . $context . PHP_EOL;
|
2023-02-08 13:35:01 +00:00
|
|
|
|
}
|
|
|
|
|
|
2023-02-10 04:14:18 +00:00
|
|
|
|
function redis_get($key, $default = null)
|
2023-02-08 13:35:01 +00:00
|
|
|
|
{
|
|
|
|
|
global $redis, $prefix;
|
|
|
|
|
|
|
|
|
|
try {
|
2023-02-28 12:48:03 +00:00
|
|
|
|
$value = $redis->get($prefix . 'cluster:' . $key);
|
2023-02-08 13:35:01 +00:00
|
|
|
|
} catch (RedisException $e) {
|
2023-02-28 12:48:03 +00:00
|
|
|
|
exit('redis get error: ' . $e->getMessage());
|
2023-02-08 13:35:01 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (empty($value)) {
|
|
|
|
|
return $default;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return $value;
|
|
|
|
|
}
|
|
|
|
|
|
2023-02-10 04:14:18 +00:00
|
|
|
|
function redis_hget($key, $hash_key, $default = null)
|
2023-02-08 13:35:01 +00:00
|
|
|
|
{
|
|
|
|
|
global $redis, $prefix;
|
|
|
|
|
|
|
|
|
|
try {
|
2023-02-28 12:48:03 +00:00
|
|
|
|
$value = $redis->hget($prefix . 'cluster:' . $key, $hash_key);
|
2023-02-08 13:35:01 +00:00
|
|
|
|
} catch (RedisException $e) {
|
2023-02-28 12:48:03 +00:00
|
|
|
|
exit('redis get error: ' . $e->getMessage());
|
2023-02-08 13:35:01 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (empty($value)) {
|
|
|
|
|
return $default;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return $value;
|
|
|
|
|
}
|
|
|
|
|
|
2023-02-10 04:14:18 +00:00
|
|
|
|
function redis_hgetAll($key)
|
2023-02-08 13:35:01 +00:00
|
|
|
|
{
|
|
|
|
|
global $redis, $prefix;
|
|
|
|
|
|
|
|
|
|
try {
|
2023-02-28 12:48:03 +00:00
|
|
|
|
$value = $redis->hGetAll($prefix . 'cluster:' . $key);
|
2023-02-08 13:35:01 +00:00
|
|
|
|
} catch (RedisException $e) {
|
2023-02-28 12:48:03 +00:00
|
|
|
|
exit('redis get error: ' . $e->getMessage());
|
2023-02-08 13:35:01 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// json_decode all
|
|
|
|
|
foreach ($value as $k => $v) {
|
|
|
|
|
$value[$k] = json_decode($v, true);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return $value;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function redis_hset($key, $hash_key, $value)
|
|
|
|
|
{
|
|
|
|
|
global $redis, $prefix;
|
|
|
|
|
|
|
|
|
|
try {
|
2023-02-28 12:48:03 +00:00
|
|
|
|
$redis->hset($prefix . 'cluster:' . $key, $hash_key, json_encode($value));
|
2023-02-08 13:35:01 +00:00
|
|
|
|
} catch (RedisException $e) {
|
2023-02-28 12:48:03 +00:00
|
|
|
|
echo 'redis get error: ' . $e->getMessage();
|
2023-02-08 13:35:01 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function redis_hdel($key, $hash_key): void
|
|
|
|
|
{
|
|
|
|
|
global $redis, $prefix;
|
|
|
|
|
|
|
|
|
|
try {
|
2023-02-28 12:48:03 +00:00
|
|
|
|
$redis->hdel($prefix . 'cluster:' . $key, $hash_key);
|
2023-02-08 13:35:01 +00:00
|
|
|
|
} catch (RedisException $e) {
|
2023-02-28 12:48:03 +00:00
|
|
|
|
echo 'redis get error: ' . $e->getMessage();
|
2023-02-08 13:35:01 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function redis_publish($event, $message = []): void
|
|
|
|
|
{
|
|
|
|
|
global $redis, $prefix, $node_id;
|
|
|
|
|
|
|
|
|
|
$data = [
|
|
|
|
|
'event' => $event,
|
|
|
|
|
'node' => [
|
|
|
|
|
'type' => 'edge',
|
|
|
|
|
'id' => $node_id,
|
|
|
|
|
],
|
|
|
|
|
'data' => $message,
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
$data = json_encode($data);
|
|
|
|
|
|
|
|
|
|
try {
|
2023-02-28 12:48:03 +00:00
|
|
|
|
$redis->publish($prefix . 'cluster_ready', $data);
|
2023-02-08 13:35:01 +00:00
|
|
|
|
} catch (RedisException $e) {
|
2023-02-28 12:48:03 +00:00
|
|
|
|
echo 'redis publish error: ' . $e->getMessage();
|
2023-02-08 13:35:01 +00:00
|
|
|
|
}
|
|
|
|
|
}
|