增加 集群配置文件同步
This commit is contained in:
parent
abdc547173
commit
d70d502377
1
.gitignore
vendored
1
.gitignore
vendored
@ -7,6 +7,7 @@
|
|||||||
.env
|
.env
|
||||||
.env.backup
|
.env.backup
|
||||||
.env.production
|
.env.production
|
||||||
|
.env.slave
|
||||||
.phpunit.result.cache
|
.phpunit.result.cache
|
||||||
Homestead.json
|
Homestead.json
|
||||||
Homestead.yaml
|
Homestead.yaml
|
||||||
|
33
app/Console/Commands/Cluster/ReportSystem.php
Normal file
33
app/Console/Commands/Cluster/ReportSystem.php
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Console\Commands\Cluster;
|
||||||
|
|
||||||
|
use Illuminate\Console\Command;
|
||||||
|
use Symfony\Component\Console\Command\Command as CommandAlias;
|
||||||
|
|
||||||
|
class ReportSystem extends Command
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The name and signature of the console command.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $signature = 'cluster:report';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The console command description.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $description = '报告此系统';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute the console command.
|
||||||
|
*
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public function handle(): int
|
||||||
|
{
|
||||||
|
return CommandAlias::SUCCESS;
|
||||||
|
}
|
||||||
|
}
|
85
app/Console/Commands/Cluster/Sync.php
Normal file
85
app/Console/Commands/Cluster/Sync.php
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Console\Commands\Cluster;
|
||||||
|
|
||||||
|
use Illuminate\Console\Command;
|
||||||
|
use Illuminate\Support\Facades\Cache;
|
||||||
|
use Illuminate\Support\Facades\Storage;
|
||||||
|
use Symfony\Component\Console\Command\Command as CommandAlias;
|
||||||
|
use ZipArchive;
|
||||||
|
|
||||||
|
class Sync extends Command
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The name and signature of the console command.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $signature = 'cluster:sync';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The console command description.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $description = '下载配置。';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute the console command.
|
||||||
|
*
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public function handle(): int
|
||||||
|
{
|
||||||
|
$this->info('正在下载配置。');
|
||||||
|
|
||||||
|
$node_type = config('settings.node_type');
|
||||||
|
|
||||||
|
$cache_key = "cluster:${node_type}_config";
|
||||||
|
$config = Cache::get($cache_key);
|
||||||
|
|
||||||
|
if ($config) {
|
||||||
|
$this->info('检查下载目录的 MD5 值。');
|
||||||
|
$config_md5_key = "cluster:${node_type}_config_md5";
|
||||||
|
$config_md5 = Cache::get($config_md5_key, '');
|
||||||
|
|
||||||
|
$md5 = md5($config);
|
||||||
|
if ($md5 !== $config_md5) {
|
||||||
|
$this->error('下载目录 MD5 值被篡改。请尝试从其他节点重新同步。');
|
||||||
|
return CommandAlias::FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 将缓存写入文件
|
||||||
|
$this->info('正在写入文件。');
|
||||||
|
Storage::disk('local')->put('cluster/config.zip', $config);
|
||||||
|
|
||||||
|
$path = Storage::disk('local')->path('cluster/config.zip');
|
||||||
|
|
||||||
|
// 删除 config 目录
|
||||||
|
$this->info('正在删除 config 目录。');
|
||||||
|
$cache_path = base_path('config');
|
||||||
|
|
||||||
|
// exec
|
||||||
|
$cmd = "rm -rf ${cache_path}";
|
||||||
|
exec($cmd);
|
||||||
|
|
||||||
|
$this->info('正在解压缩。');
|
||||||
|
|
||||||
|
$zip = new ZipArchive();
|
||||||
|
$zip->open($path);
|
||||||
|
$zip->extractTo(base_path());
|
||||||
|
$zip->close();
|
||||||
|
|
||||||
|
$this->info('正在清理。');
|
||||||
|
|
||||||
|
// 删除目录
|
||||||
|
Storage::disk('local')->deleteDirectory('cluster');
|
||||||
|
} else {
|
||||||
|
$this->error('没有找到缓存。请尝试从其他节点重新同步。');
|
||||||
|
return CommandAlias::FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return CommandAlias::SUCCESS;
|
||||||
|
}
|
||||||
|
}
|
137
app/Console/Commands/Cluster/Upload.php
Normal file
137
app/Console/Commands/Cluster/Upload.php
Normal file
@ -0,0 +1,137 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Console\Commands\Cluster;
|
||||||
|
|
||||||
|
use Illuminate\Console\Command;
|
||||||
|
use Illuminate\Support\Facades\Artisan;
|
||||||
|
use Illuminate\Support\Facades\Cache;
|
||||||
|
use Symfony\Component\Console\Command\Command as CommandAlias;
|
||||||
|
use ZipArchive;
|
||||||
|
|
||||||
|
class Upload extends Command
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The name and signature of the console command.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $signature = 'cluster:upload';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The console command description.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $description = '将此节点配置文件上传到集群中。';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute the console command.
|
||||||
|
*
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public function handle(): int
|
||||||
|
{
|
||||||
|
$this->info('正在初始化节点。');
|
||||||
|
|
||||||
|
$node_type = config('settings.node_type');
|
||||||
|
|
||||||
|
if ($node_type === 'master') {
|
||||||
|
$this->warn('此节点为主节点,将同时上传两份版本(如果有 .env.slave 的话)。');
|
||||||
|
|
||||||
|
// 上传 master
|
||||||
|
$this->upload('master');
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 检测 .env.slave 是否存在
|
||||||
|
if (file_exists(base_path('.env.slave'))) {
|
||||||
|
// 备份当前的 .env 文件为 .env.temp
|
||||||
|
$this->info('正在备份 .env 文件。');
|
||||||
|
copy(base_path('.env'), base_path('.env.temp'));
|
||||||
|
|
||||||
|
// 复制 .env.slave 为 .env
|
||||||
|
$this->info('正在复制 .env.slave 文件。');
|
||||||
|
copy(base_path('.env.slave'), base_path('.env'));
|
||||||
|
|
||||||
|
$this->upload('slave');
|
||||||
|
|
||||||
|
// 恢复 .env 文件
|
||||||
|
$this->info('正在恢复 .env 文件。');
|
||||||
|
copy(base_path('.env.temp'), base_path('.env'));
|
||||||
|
|
||||||
|
// 删除 .env.temp
|
||||||
|
unlink(base_path('.env.temp'));
|
||||||
|
|
||||||
|
$this->info('节点初始化完成。');
|
||||||
|
}
|
||||||
|
|
||||||
|
// if is local
|
||||||
|
if (app()->environment() === 'local') {
|
||||||
|
$this->info('清理开发节点。');
|
||||||
|
|
||||||
|
Artisan::call('route:clear');
|
||||||
|
Artisan::call('config:clear');
|
||||||
|
}
|
||||||
|
|
||||||
|
return CommandAlias::SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function addFileToZip(string $path, ZipArchive $zip): void
|
||||||
|
{
|
||||||
|
$handler = opendir($path);
|
||||||
|
while (($filename = readdir($handler)) !== false) {
|
||||||
|
if ($filename != '.' && $filename != '..') {
|
||||||
|
if (is_dir($path . '/' . $filename)) {
|
||||||
|
$this->addFileToZip($path . '/' . $filename, $zip);
|
||||||
|
} else {
|
||||||
|
$zip->addFile($path . '/' . $filename);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@closedir($handler);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public function upload($node_type)
|
||||||
|
{
|
||||||
|
$this->warn("正在上传 ${node_type} 文件。");
|
||||||
|
$this->info('正在打包 config 目录。');
|
||||||
|
|
||||||
|
if ($node_type === 'master') {
|
||||||
|
// 相对路径
|
||||||
|
$cache = 'config';
|
||||||
|
|
||||||
|
$cacheZip = $cache . '.zip';
|
||||||
|
$zip = new ZipArchive();
|
||||||
|
$zip->open($cacheZip, ZipArchive::CREATE);
|
||||||
|
$this->addFileToZip($cache, $zip);
|
||||||
|
$zip->close();
|
||||||
|
|
||||||
|
$this->info('正在上传 config 目录。');
|
||||||
|
|
||||||
|
$cache_key = "cluster:${node_type}_config";
|
||||||
|
Cache::forever($cache_key, file_get_contents($cacheZip));
|
||||||
|
|
||||||
|
// md5
|
||||||
|
$this->info('正在报告 cache 目录的 MD5 值。');
|
||||||
|
$cache_md5_key = "cluster:${node_type}_config_md5";
|
||||||
|
Cache::forever($cache_md5_key, md5_file($cacheZip));
|
||||||
|
|
||||||
|
unlink($cacheZip);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// 上传 .env 文件
|
||||||
|
$this->info('正在上传 .env 文件。');
|
||||||
|
$env_key = "cluster:${node_type}_env";
|
||||||
|
Cache::forever($env_key, file_get_contents(base_path('.env')));
|
||||||
|
|
||||||
|
// 上传 .env 文件的 MD5
|
||||||
|
$this->info('正在报告 .env 文件的 MD5 值。');
|
||||||
|
$env_md5_key = "cluster:${node_type}_env_md5";
|
||||||
|
Cache::forever($env_md5_key, md5_file(base_path('.env')));
|
||||||
|
|
||||||
|
$this->info('完成。');
|
||||||
|
}
|
||||||
|
}
|
49
app/Console/Commands/Init.php
Normal file
49
app/Console/Commands/Init.php
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Console\Commands;
|
||||||
|
|
||||||
|
use Illuminate\Console\Command;
|
||||||
|
use Illuminate\Support\Facades\Artisan;
|
||||||
|
use Symfony\Component\Console\Command\Command as CommandAlias;
|
||||||
|
|
||||||
|
class Init extends Command
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The name and signature of the console command.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $signature = 'init';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The console command description.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $description = '不清理缓存情况下的 optimize';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute the console command.
|
||||||
|
*
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public function handle(): int
|
||||||
|
{
|
||||||
|
$this->info('正在删除 bootstrap/cache 目录。');
|
||||||
|
$cache_path = base_path('bootstrap/cache');
|
||||||
|
$files = glob($cache_path . '/*');
|
||||||
|
foreach ($files as $file) {
|
||||||
|
if (is_file($file)) {
|
||||||
|
unlink($file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Artisan::call('route:clear');
|
||||||
|
Artisan::call('config:clear');
|
||||||
|
Artisan::call('view:clear');
|
||||||
|
|
||||||
|
Artisan::call('optimize');
|
||||||
|
|
||||||
|
return CommandAlias::SUCCESS;
|
||||||
|
}
|
||||||
|
}
|
@ -26,6 +26,27 @@ class Kernel extends ConsoleKernel
|
|||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
protected function schedule(Schedule $schedule): void
|
protected function schedule(Schedule $schedule): void
|
||||||
|
{
|
||||||
|
if (config('settings.node_type') === 'master') {
|
||||||
|
$this->registerMasterSchedules($schedule);
|
||||||
|
} else {
|
||||||
|
$this->registerSlaveSchedules($schedule);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register the commands for the application.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
protected function commands(): void
|
||||||
|
{
|
||||||
|
$this->load(__DIR__ . '/Commands');
|
||||||
|
|
||||||
|
require base_path('routes/console.php');
|
||||||
|
}
|
||||||
|
|
||||||
|
private function registerMasterSchedules(Schedule $schedule): void
|
||||||
{
|
{
|
||||||
// 清理过期的 Token
|
// 清理过期的 Token
|
||||||
$schedule->command('sanctum:prune-expired --hours=24')->daily();
|
$schedule->command('sanctum:prune-expired --hours=24')->daily();
|
||||||
@ -63,15 +84,8 @@ protected function schedule(Schedule $schedule): void
|
|||||||
$schedule->job(new SetBirthdayGroupJob())->dailyAt('00:00');
|
$schedule->job(new SetBirthdayGroupJob())->dailyAt('00:00');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private function registerSlaveSchedules(Schedule $schedule): void
|
||||||
* Register the commands for the application.
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
protected function commands(): void
|
|
||||||
{
|
{
|
||||||
$this->load(__DIR__ . '/Commands');
|
|
||||||
|
|
||||||
require base_path('routes/console.php');
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"require": {
|
"require": {
|
||||||
"php": "^8.1",
|
"php": "^8.1",
|
||||||
|
"ext-zip": "^1.19",
|
||||||
"doctrine/dbal": "^3.4",
|
"doctrine/dbal": "^3.4",
|
||||||
"erusev/parsedown": "^1.7",
|
"erusev/parsedown": "^1.7",
|
||||||
"fruitcake/laravel-cors": "^3.0",
|
"fruitcake/laravel-cors": "^3.0",
|
||||||
|
5
composer.lock
generated
5
composer.lock
generated
@ -4,7 +4,7 @@
|
|||||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||||
"This file is @generated automatically"
|
"This file is @generated automatically"
|
||||||
],
|
],
|
||||||
"content-hash": "9ba10b0e61eac712b437b33b0ab61fbe",
|
"content-hash": "81fa8fb300376dbf0ae3eb8771d2018f",
|
||||||
"packages": [
|
"packages": [
|
||||||
{
|
{
|
||||||
"name": "bacon/bacon-qr-code",
|
"name": "bacon/bacon-qr-code",
|
||||||
@ -11696,7 +11696,8 @@
|
|||||||
"prefer-stable": true,
|
"prefer-stable": true,
|
||||||
"prefer-lowest": false,
|
"prefer-lowest": false,
|
||||||
"platform": {
|
"platform": {
|
||||||
"php": "^8.1"
|
"php": "^8.1",
|
||||||
|
"ext-zip": "^1.19"
|
||||||
},
|
},
|
||||||
"platform-dev": [],
|
"platform-dev": [],
|
||||||
"plugin-api-version": "2.3.0"
|
"plugin-api-version": "2.3.0"
|
||||||
|
Loading…
Reference in New Issue
Block a user