Laravel项目接入Nacos配置中心完整部署方案

🎯 一、架构设计

1.1 配置分层策略

Nacos配置中心
├── 公共配置 (shared)
│   ├── database.properties (数据库配置)
│   ├── redis.properties (Redis配置)
│   ├── aliyun.properties (阿里云服务)
│   └── tencent.properties (腾讯云服务)
├── 环境配置
│   ├── develop (开发环境)
│   ├── test (测试环境)
│   └── production (生产环境)
└── 应用私有配置
    └── dbb_live_api.properties

1.2 命名空间设计

  • develop - 开发环境
  • test - 测试环境
  • production - 生产环境

1.3 配置组设计

  • DEFAULT_GROUP - 应用基础配置
  • DATABASE_GROUP - 数据库相关
  • CACHE_GROUP - 缓存相关
  • THIRD_PARTY_GROUP - 第三方服务

🔧 二、技术实现方案

2.1 安装Nacos PHP SDK

composer.json添加依赖:

{
    "require": {
        "nacos-group/nacos-sdk-php": "^0.2"
    }
}

2.2 创建Nacos配置文件

创建 config/nacos.php:

<?php

return [
    // Nacos服务器地址
    'host' => env('NACOS_HOST', '127.0.0.1'),
    'port' => env('NACOS_PORT', 8848),
    
    // Nacos认证
    'username' => env('NACOS_USERNAME', 'nacos'),
    'password' => env('NACOS_PASSWORD', 'nacos'),
    
    // 命名空间(环境隔离)
    'namespace_id' => env('NACOS_NAMESPACE_ID', ''),
    
    // 配置组
    'group' => env('NACOS_GROUP', 'DEFAULT_GROUP'),
    
    // 数据ID(配置文件名)
    'data_ids' => [
        'app' => env('NACOS_DATA_ID_APP', 'dbb_live_api'),
        'database' => env('NACOS_DATA_ID_DATABASE', 'database'),
        'redis' => env('NACOS_DATA_ID_REDIS', 'redis'),
        'third_party' => env('NACOS_DATA_ID_THIRD_PARTY', 'third_party'),
    ],
    
    // 配置格式
    'format' => env('NACOS_FORMAT', 'properties'), // properties, json, yaml
    
    // 是否启用配置监听(热更新)
    'enable_listener' => env('NACOS_ENABLE_LISTENER', false),
    
    // 配置缓存路径
    'cache_dir' => storage_path('framework/nacos'),
    
    // 配置缓存时间(秒)
    'cache_ttl' => env('NACOS_CACHE_TTL', 300),
];

2.3 创建Nacos服务提供者

创建 app/Providers/NacosServiceProvider.php:

<?php

namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use Nacos\NacosClient;
use Illuminate\Support\Facades\Cache;

class NacosServiceProvider extends ServiceProvider
{
    /**
     * Register services.
     */
    public function register()
    {
        $this->app->singleton('nacos', function ($app) {
            return new NacosClient(
                config('nacos.host'),
                config('nacos.port'),
                config('nacos.username'),
                config('nacos.password')
            );
        });
    }

    /**
     * Bootstrap services.
     */
    public function boot()
    {
        // 只在非测试环境加载Nacos配置
        if (!$this->app->runningUnitTests() && env('NACOS_ENABLED', false)) {
            $this->loadNacosConfig();
        }
    }

    /**
     * 从Nacos加载配置
     */
    protected function loadNacosConfig()
    {
        try {
            $nacos = $this->app->make('nacos');
            $dataIds = config('nacos.data_ids');
            $group = config('nacos.group');
            $namespaceId = config('nacos.namespace_id');

            foreach ($dataIds as $key => $dataId) {
                $cacheKey = "nacos_config_{$key}_{$namespaceId}_{$group}_{$dataId}";
                
                // 尝试从缓存获取配置
                $config = Cache::remember($cacheKey, config('nacos.cache_ttl'), function () use ($nacos, $dataId, $group, $namespaceId) {
                    try {
                        $response = $nacos->getConfig($dataId, $group, $namespaceId);
                        return $this->parseConfig($response);
                    } catch (\Exception $e) {
                        \Log::error("Failed to fetch Nacos config: {$dataId}", [
                            'error' => $e->getMessage()
                        ]);
                        return [];
                    }
                });

                // 将配置合并到运行时环境
                $this->mergeConfig($config);
            }
        } catch (\Exception $e) {
            \Log::error('Nacos config loading failed', [
                'error' => $e->getMessage(),
                'trace' => $e->getTraceAsString()
            ]);
        }
    }

    /**
     * 解析配置内容
     */
    protected function parseConfig($content)
    {
        $format = config('nacos.format');
        
        switch ($format) {
            case 'json':
                return json_decode($content, true) ?? [];
            case 'yaml':
                return yaml_parse($content) ?? [];
            case 'properties':
            default:
                return $this->parseProperties($content);
        }
    }

    /**
     * 解析properties格式配置
     */
    protected function parseProperties($content)
    {
        $config = [];
        $lines = explode("\n", $content);
        
        foreach ($lines as $line) {
            $line = trim($line);
            if (empty($line) || strpos($line, '#') === 0) {
                continue;
            }
            
            if (strpos($line, '=') !== false) {
                list($key, $value) = explode('=', $line, 2);
                $config[trim($key)] = trim($value);
            }
        }
        
        return $config;
    }

    /**
     * 合并配置到环境变量
     */
    protected function mergeConfig(array $config)
    {
        foreach ($config as $key => $value) {
            // 设置到环境变量
            putenv("{$key}={$value}");
            $_ENV[$key] = $value;
            $_SERVER[$key] = $value;
        }
    }
}

2.4 创建Nacos配置管理命令

创建 app/Console/Commands/NacosConfigCommand.php:

<?php

namespace App\Console\Commands;

use Illuminate\Console\Command;
use Nacos\NacosClient;

class NacosConfigCommand extends Command
{
    protected $signature = 'nacos:config {action} {--data-id=} {--group=} {--content=}';
    protected $description = 'Nacos配置管理命令';

    public function handle()
    {
        $action = $this->argument('action');
        
        switch ($action) {
            case 'publish':
                $this->publishConfig();
                break;
            case 'get':
                $this->getConfig();
                break;
            case 'delete':
                $this->deleteConfig();
                break;
            case 'sync':
                $this->syncFromEnv();
                break;
            default:
                $this->error("Unknown action: {$action}");
        }
    }

    /**
     * 发布配置到Nacos
     */
    protected function publishConfig()
    {
        $dataId = $this->option('data-id');
        $group = $this->option('group') ?? config('nacos.group');
        $content = $this->option('content');
        
        if (!$dataId || !$content) {
            $this->error('data-id and content are required');
            return;
        }

        try {
            $nacos = app('nacos');
            $result = $nacos->publishConfig(
                $dataId,
                $group,
                $content,
                config('nacos.namespace_id')
            );
            
            if ($result) {
                $this->info("Config published successfully: {$dataId}");
            } else {
                $this->error("Failed to publish config: {$dataId}");
            }
        } catch (\Exception $e) {
            $this->error("Error: " . $e->getMessage());
        }
    }

    /**
     * 获取配置
     */
    protected function getConfig()
    {
        $dataId = $this->option('data-id');
        $group = $this->option('group') ?? config('nacos.group');
        
        if (!$dataId) {
            $this->error('data-id is required');
            return;
        }

        try {
            $nacos = app('nacos');
            $config = $nacos->getConfig(
                $dataId,
                $group,
                config('nacos.namespace_id')
            );
            
            $this->info("Config content:");
            $this->line($config);
        } catch (\Exception $e) {
            $this->error("Error: " . $e->getMessage());
        }
    }

    /**
     * 从.env文件同步配置到Nacos
     */
    protected function syncFromEnv()
    {
        $envFile = base_path('.env');
        
        if (!file_exists($envFile)) {
            $this->error('.env file not found');
            return;
        }

        $content = file_get_contents($envFile);
        $this->info('Syncing .env to Nacos...');
        
        try {
            $nacos = app('nacos');
            $dataId = config('nacos.data_ids.app');
            $group = config('nacos.group');
            
            $result = $nacos->publishConfig(
                $dataId,
                $group,
                $content,
                config('nacos.namespace_id')
            );
            
            if ($result) {
                $this->info('Sync completed successfully');
            } else {
                $this->error('Sync failed');
            }
        } catch (\Exception $e) {
            $this->error("Error: " . $e->getMessage());
        }
    }
}

2.5 创建Nacos配置热更新监听器

创建 app/Services/NacosConfigListener.php:

<?php

namespace App\Services;

use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Log;

class NacosConfigListener
{
    protected $nacos;
    protected $listeners = [];

    public function __construct()
    {
        $this->nacos = app('nacos');
    }

    /**
     * 添加配置监听
     */
    public function addListener($dataId, $group, $callback)
    {
        $this->listeners[] = [
            'dataId' => $dataId,
            'group' => $group,
            'callback' => $callback,
            'md5' => '',
        ];
    }

    /**
     * 启动配置监听
     */
    public function listen()
    {
        while (true) {
            foreach ($this->listeners as &$listener) {
                try {
                    $config = $this->nacos->getConfig(
                        $listener['dataId'],
                        $listener['group'],
                        config('nacos.namespace_id')
                    );

                    $currentMd5 = md5($config);
                    
                    if ($listener['md5'] !== $currentMd5) {
                        Log::info("Config changed: {$listener['dataId']}");
                        
                        // 调用回调函数
                        call_user_func($listener['callback'], $config);
                        
                        // 更新MD5
                        $listener['md5'] = $currentMd5;
                        
                        // 清除缓存
                        $cacheKey = "nacos_config_{$listener['dataId']}";
                        Cache::forget($cacheKey);
                    }
                } catch (\Exception $e) {
                    Log::error("Config listener error: {$listener['dataId']}", [
                        'error' => $e->getMessage()
                    ]);
                }
            }
            
            sleep(5); // 5秒轮询一次
        }
    }
}

📝 三、配置迁移方案

3.1 配置文件拆分建议

基础应用配置 (dbb_live_api.properties):

# 应用基础配置
APP_NAME=Laravel
APP_ENV=production
APP_DEBUG=false
APP_URL=https://api.example.com
LOG_CHANNEL=daily
LOG_LEVEL=info
TIMEZONE=Asia/Shanghai

# JWT配置
JWT_SECRET=your_jwt_secret_here
JWT_ALGO=HS256
JWT_TTL=60
JWT_REFRESH_TTL=20160

# 是否上报异常
REPORT_EXCEPTION=true

# WebSocket地址
WS_SERVER=ws://127.0.0.1:9502

# 是否开启Telescope
TELESCOPE_ENABLED=false

# 维护模式
APP_MAINTENANCE=false
APP_MAINTENANCE_PHONE=

# 当前服务器标识
CURRENT_SERVER=production-001

数据库配置 (database.properties):

# 主数据库配置
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=dbb_live
DB_USERNAME=root
DB_PASSWORD=password
DB_PREFIX=tbl_

# 旧数据库配置
DB_CONNECTION_OLD=mysql
DB_HOST_OLD=127.0.0.1
DB_PORT_OLD=3306
DB_DATABASE_OLD=dbb_old
DB_USERNAME_OLD=root
DB_PASSWORD_OLD=password
DB_PREFIX_OLD=tbl_

# 用户关注分表配置
USER_FOLLOWER_DB_COUNT=1
USER_FOLLOWER_TABLE_COUNT=200
USER_FOLLOWER_DB_HOST_0=127.0.0.1
USER_FOLLOWER_DB_DATABASE=dbb_shop
USER_FOLLOWER_DB_PORT=3306
USER_FOLLOWER_DB_USERNAME=root
USER_FOLLOWER_DB_PASSWORD=password
USER_FOLLOWER_DB_PREFIX=tbl_

Redis配置 (redis.properties):

# 默认Redis配置
REDIS_HOST=127.0.0.1
REDIS_PASSWORD=null
REDIS_PORT=6379
CACHE_DRIVER=redis

# 直播相关Redis配置
REDIS_LIVE_HOST=127.0.0.1
REDIS_LIVE_USERNAME=null
REDIS_LIVE_PASSWORD=null
REDIS_LIVE_PORT=6379
REDIS_LIVE_CACHE_DB=0

# 队列配置
QUEUE_CONNECTION=redis

第三方服务配置 (third_party.properties):

# 阿里云OSS
ALI_ACCESS_KEY_ID=
ALI_ACCESS_SECRET=
ALI_REGION_ID=
OSS_ROLE_ARN=
ALIYUN_OSS_ACCESS_ID=
ALIYUN_OSS_ACCESS_SECRET=
ALIYUN_OSS_ENDPOINT=
ALIYUN_OSS_ACCESS_BUCKET=
ALIYUN_OSS_DOMAIN=

# 腾讯云配置
COS_ACCESS_APP_ID=
COS_ACCESS_SECRET_ID=
COS_SECRET_SECRET_KEY=
COS_DEFAULT_REGION=
COS_BUCKET=
COS_URL=

# 腾讯IM
IM_SDK_APP_ID=
IM_SECRET_KEY=
IM_IDENTIFIER=
IM_REGION=
IM_CALLBACK_TOKEN=

# 腾讯云点播
VOD_SUBAPPID=
VOD_SECRETID=
VOD_SECRETKEY=
VOD_REGION=
VOD_URL=
VOD_DEFINITION=

# 腾讯云直播
TENCENTCLOUD_LIVE_SECRETID=
TENCENTCLOUD_LIVE_SECRETKEY=
TENCENTCLOUD_LIVE_APPID=
TENCENTCLOUD_LIVE_BIZID=
TENCENTCLOUD_LIVE_KEY=
TENCENTCLOUD_LIVE_PUSH=
TENCENTCLOUD_LIVE_PULL=
TENCENTCLOUD_LIVE_PUSH_TTL_DAY=7
TENCENTCLOUD_LIVE_TEMPLATE=appauto

# 支付相关
PAY_DOMAIN=
PAY_CENTER_KEY=doudie
NOTIFY_COIN_RECHARGE=
PAYMENT_REGISTER_URL=
PAYMENT_DISABLE_URL=
APPLE_URL=https://buy.itunes.apple.com/verifyReceipt
APPLE_PASSWORD=

# 短信服务
SMS_ALIYUN_ACCESS_KEY_ID=
SMS_ALIYUN_ACCESS_KEY_SECRET=
SMS_ALIYUN_SIGN_NAME=

# ES配置
ES_HOST=
ES_PORT=9200
ES_USERNAME=
ES_PASSWORD=

# RabbitMQ配置
RABBITMQ_HOST=
RABBITMQ_PORT=5672
RABBITMQ_USER=
RABBITMQ_PASSWORD=
RABBITMQ_VHOST=/

🚀 四、部署实施步骤

步骤1: 安装Nacos服务器

# 下载Nacos
wget https://github.com/alibaba/nacos/releases/download/2.2.3/nacos-server-2.2.3.tar.gz
tar -xvf nacos-server-2.2.3.tar.gz
cd nacos/bin

# 单机模式启动
sh startup.sh -m standalone

# 访问Nacos控制台
# http://localhost:8848/nacos
# 默认账号密码: nacos/nacos

步骤2: 创建命名空间

登录Nacos控制台,创建三个命名空间:

  • develop - 开发环境
  • test - 测试环境
  • production - 生产环境

步骤3: 安装PHP依赖

# 进入项目目录
cd c:\Users\DCKJ\Downloads\dbb_live_api-master

# 安装Nacos SDK
composer require nacos-group/nacos-sdk-php

步骤4: 创建配置文件

按照上述方案创建以下文件:

  1. config/nacos.php - Nacos配置
  2. app/Providers/NacosServiceProvider.php - 服务提供者
  3. app/Console/Commands/NacosConfigCommand.php - 管理命令
  4. app/Services/NacosConfigListener.php - 配置监听器

步骤5: 注册服务提供者

修改 config/app.php:

'providers' => [
    // ... existing providers
    App\Providers\NacosServiceProvider::class,
],

步骤6: 更新.env配置

.env文件中添加Nacos相关配置:

# Nacos配置中心
NACOS_ENABLED=true
NACOS_HOST=127.0.0.1
NACOS_PORT=8848
NACOS_USERNAME=nacos
NACOS_PASSWORD=nacos
NACOS_NAMESPACE_ID=production
NACOS_GROUP=DEFAULT_GROUP
NACOS_DATA_ID_APP=dbb_live_api
NACOS_DATA_ID_DATABASE=database
NACOS_DATA_ID_REDIS=redis
NACOS_DATA_ID_THIRD_PARTY=third_party
NACOS_FORMAT=properties
NACOS_ENABLE_LISTENER=false
NACOS_CACHE_TTL=300

步骤7: 同步配置到Nacos

# 同步.env配置到Nacos
php artisan nacos:config sync

# 或手动发布配置
php artisan nacos:config publish --data-id=dbb_live_api --content="$(cat .env)"

步骤8: 验证配置加载

# 获取配置
php artisan nacos:config get --data-id=dbb_live_api

# 清除配置缓存
php artisan cache:clear

# 重启应用

🔍 五、配置管理最佳实践

5.1 配置分级管理

优先级(从高到低):
1. 本地.env文件 (开发调试用)
2. Nacos应用私有配置
3. Nacos环境配置
4. Nacos公共配置

5.2 敏感信息加密

在Nacos中存储敏感信息时,建议使用加密:

创建 app/Services/NacosEncryption.php:

<?php

namespace App\Services;

class NacosEncryption
{
    private $key;

    public function __construct()
    {
        $this->key = env('NACOS_ENCRYPTION_KEY', env('APP_KEY'));
    }

    public function encrypt($value)
    {
        return openssl_encrypt($value, 'AES-256-CBC', $this->key, 0, substr($this->key, 0, 16));
    }

    public function decrypt($value)
    {
        return openssl_decrypt($value, 'AES-256-CBC', $this->key, 0, substr($this->key, 0, 16));
    }
}

5.3 配置变更审计

在Nacos控制台可查看配置变更历史,建议:

  • 所有生产配置变更需要审批
  • 保留配置变更日志
  • 支持配置回滚

5.4 灰度发布策略

// 在NacosServiceProvider中实现灰度逻辑
protected function isGrayRelease()
{
    $serverName = env('CURRENT_SERVER');
    $grayServers = explode(',', env('GRAY_SERVERS', ''));
    
    return in_array($serverName, $grayServers);
}

📊 六、监控与运维

6.1 健康检查

创建 app/Http/Controllers/HealthController.php:

<?php

namespace App\Http\Controllers;

use Illuminate\Support\Facades\Cache;

class HealthController extends Controller
{
    public function check()
    {
        $status = [
            'app' => 'ok',
            'nacos' => 'unknown',
            'database' => 'unknown',
            'redis' => 'unknown',
        ];

        try {
            // 检查Nacos连接
            $nacos = app('nacos');
            $config = $nacos->getConfig(
                config('nacos.data_ids.app'),
                config('nacos.group'),
                config('nacos.namespace_id')
            );
            $status['nacos'] = 'ok';
        } catch (\Exception $e) {
            $status['nacos'] = 'error: ' . $e->getMessage();
        }

        try {
            // 检查数据库
            \DB::connection()->getPdo();
            $status['database'] = 'ok';
        } catch (\Exception $e) {
            $status['database'] = 'error';
        }

        try {
            // 检查Redis
            Cache::put('health_check', time(), 10);
            $status['redis'] = 'ok';
        } catch (\Exception $e) {
            $status['redis'] = 'error';
        }

        return response()->json($status);
    }
}

6.2 配置监控脚本

创建 app/Console/Commands/NacosMonitorCommand.php:

<?php

namespace App\Console\Commands;

use Illuminate\Console\Command;
use App\Services\NacosConfigListener;

class NacosMonitorCommand extends Command
{
    protected $signature = 'nacos:monitor';
    protected $description = '监听Nacos配置变化';

    public function handle()
    {
        $this->info('Starting Nacos config monitor...');
        
        $listener = new NacosConfigListener();
        
        // 监听应用配置
        $listener->addListener(
            config('nacos.data_ids.app'),
            config('nacos.group'),
            function ($config) {
                $this->info('App config changed, reloading...');
                // 这里可以执行配置重载逻辑
                \Artisan::call('config:clear');
                \Artisan::call('cache:clear');
            }
        );

        $listener->listen();
    }
}

📋 七、回滚方案

如果Nacos出现问题,提供以下回滚策略:

7.1 本地配置降级

NacosServiceProvider 中添加降级逻辑:

protected function loadNacosConfig()
{
    try {
        // 尝试从Nacos加载
        $this->fetchFromNacos();
    } catch (\Exception $e) {
        \Log::error('Nacos unavailable, fallback to local config');
        
        // 降级到本地.env文件
        $this->loadFromLocalEnv();
    }
}

protected function loadFromLocalEnv()
{
    $envFile = base_path('.env');
    if (file_exists($envFile)) {
        $this->info('Using local .env configuration');
        // .env已自动加载,无需额外操作
    }
}

7.2 紧急关闭Nacos

# 在.env中设置
NACOS_ENABLED=false

八、验收检查清单


📚 九、相关文档

  1. Nacos官方文档: https://nacos.io/zh-cn/docs/what-is-nacos.html
  2. nacos-sdk-php: https://github.com/nacos-group/nacos-sdk-php
  3. Laravel配置管理: https://laravel.com/docs/9.x/configuration

posted @ 2025-10-23 10:33  完颜振江  阅读(4)  评论(0)    收藏  举报