laravel框架接入apollo

1、apollo上创建项目

laravel框架接入apollo

输入各项参数,AppId可以使用项目英文,而应用名称可使用项目中文

laravel框架接入apollo

2、添加需要用到的集群

laravel框架接入apollo

laravel框架接入apollo

laravel框架接入apollo

3、生成秘钥,选择DEV环境的生成并且启用

laravel框架接入apollo

laravel框架接入apollo

4、laravel接入apollo,添加apollo的命令与配置

在app/Console/Commands/目录下创建apollo定时任务文件ApolloCommentCount.php,内容如下

<?php

namespace App\Console\Commands;

use Illuminate\Console\Command;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\Redis;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Storage;


class ApolloCommentCount extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'command:apollo.sync';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = '阿波罗配置同步';

    //AppId
    protected $app_id;

    //链接
    protected $server;

    //集群
    protected $cluster;

    //密钥
    protected $secret;

    //空间
    protected $namespaces;

    /**
     * Create a new command instance.
     *
     * @return void
     */
    public function __construct()
    {
        parent::__construct();
        $this->app_id = config('apollo.app_id');
        $this->server = config('apollo.server');
        $this->cluster = config('apollo.cluster');
        $this->secret = config('apollo.secret');
        $this->namespaces = explode(',', config('apollo.namespace'));
    }

    /**
     * Execute the console command.
     *
     * @return mixed
     */
    public function handle()
    {
        $this->doSync();
    }

    protected function sign($pathWithQuery, $secret, $time)
    {
        $data = join("\n", [$time, $pathWithQuery]);
        $sign = base64_encode(hash_hmac('sha1', $data, $secret, true));
        return $sign;
    }

    protected function doSync()
    {
        try {
            //获取毫秒级时间戳
            $time = (string)sprintf('%.0f', microtime('string') * 1000);
            $cfgs = [];
            foreach ($this->namespaces as $namespace) {
                $pathWithQuery = '/configs/' . $this->app_id . '/' . $this->cluster . '/';
                $url = $this->server . $pathWithQuery;
                $label = $_SERVER['HOSTNAME'] ?? '';
                $releaseKey = Redis::get($pathWithQuery . $namespace . $label);
                $url = $url . $namespace . '?releaseKey=' . $releaseKey;
                $query = $pathWithQuery . $namespace . '?releaseKey=' . $releaseKey;
                $sign = $this->sign($query, $this->secret, $time);
                $header = [
                    'Authorization' => 'Apollo ' . $this->app_id . ':' . $sign,
                    'Timestamp' => $time,
                ];
                $client = new \GuzzleHttp\Client(['timeout' => 3.00, 'headers' => $header]);
                $response = $client->request('GET', $url);
                $body = json_decode($response->getBody()->getContents(), true);
                if ($response->getStatusCode() == 304) {
                    continue;
                }
                $releaseKey = Arr::get($body, 'releaseKey', []);
                Redis::set($pathWithQuery . $namespace . $label, $releaseKey);
                $cfg = Arr::get($body, 'configurations', []);
                if (!$cfg) {
                    continue;
                }
                $cfgs = array_merge($cfgs, $cfg);
            }
            if ($cfgs) {
                foreach ($_ENV as $key => $value) {
                    if(isset($cfgs[$key])){
                        $cfgs[$key] = $cfgs[$key] ?? $_ENV[$key];
                    }
                }
                $items = [];
                foreach ($cfgs as $key => $value) {
                    data_set($items, $key, $value);
                }
                $content = '';
                foreach ($items as $k => $item) {
                    $this->line('Saving [' . $k . ']');
                    $content .= $k . '=' . $item . "\n";
                }
                $fileName = '.env';
                $fileName_back = '.env_back';
                if ($content) {
                    Storage::disk('env')->put($fileName, $content);
                    Storage::disk('env')->put($fileName_back, $content);
                }
            }

        } catch (\Exception $ex) {
            Log::channel('cron')->error('apollo',[$ex->getMessage()]);
        }
    }
}

在config/filesystems.php文件中加入env文件配置,在 disks数组中 加入

'env' => [
     'driver' => 'local',
     'root' => base_path(),
],

在config/logging.php文件中加入cron日志配置

//定时任务的日志配置
'cron' => [
    'driver' => 'daily',
    'path' => storage_path('logs/cron/cron.log'),
    'level' => 'debug',
    'days' => 14,
],

在.env文件中加入apollo配置,{}为变量信息,根据实际情况录入

#apollo地址
APOLLO_SERVER={阿波罗地址}
#apollo的appId
APOLLO_APP_ID={阿波罗的AppId}
#apollo的分支
APOLLO_CLUSTER={阿波罗的分支}
#apollo的空间
APOLLO_NAMESPACE={阿波罗的空间}
#apollo的key
APOLLO_SECRET={阿波罗的秘钥}

laravel框架接入apollo

进入管理秘钥查看秘钥

laravel框架接入apollo

5、将.env中的配置全部添加到apollo上,可以使用文本形式,更加快捷

laravel框架接入apollo

发布一下

laravel框架接入apollo

6、在config目录下添加config文件,内容如下

<?php

return [
    'server' => env('APOLLO_SERVER','http://127.0.0.1:8080'),
    'app_id' => env('APOLLO_APP_ID','SampleApp'),
    'cluster' => env('APOLLO_CLUSTER','dev'),
    'namespace' => env('APOLLO_NAMESPACE','application'),
    'secret' => env('APOLLO_SECRET'),
];

7、在项目目录下运行命令php artisan command:apollo.sync 即可获取,如果运行报错请查看storage/logs/cron目录下的报错日志, 根据日志调试

laravel框架接入apollo

laravel框架接入apollo

这是获取后的数据

8、线上的项目一般都需要实时更新,可以通过定时器来解决,定时运行命令获取配置,docker则进入容器中执行

php artisan command:apollo.sync

一下为进入docker的操作命令

laravel框架接入apollo

9、补充说明,如果没有.env文件要进行创建,复制一份.env.example文件(laravel自带的),改名为.env,修改配置,再加入apollo信息即可

还有记得配置好redis,因为要用到redis,否则会获取配置失败,并且日志中报Connection refused错误

10、tp框架使用方法差不多,可以在app/command中添加Apollo.php文件实现

<?php

namespace app\command;


use think\console\Command;
use think\console\Input;
use think\console\Output;
use think\facade\Cache;
use think\facade\Log;

class Apollo extends Command
{
	//AppId
	protected $app_id;
	
	//链接
	protected $server;
	
	//集群
	protected $cluster;
	
	//密钥
	protected $secret;
	
	//空间
	protected $namespaces;
	
	
	
	public function __construct()
	{
		parent::__construct();
		$this->app_id = config('apollo.app_id');
		$this->server = config('apollo.server');
		$this->cluster = config('apollo.cluster');
		$this->secret = config('apollo.secret');
		$this->namespaces = explode(',', config('apollo.namespace'));
	}
	
	protected function configure()
    {
        // 指令配置
        $this->setName('Apollo');
        // 设置参数
        
    }

    protected function execute(Input $input, Output $output)
    {
	    try {
		    //获取毫秒级时间戳
		    $time = (string)sprintf('%.0f', microtime('string') * 1000);
		    $cfgs = [];
		    foreach ($this->namespaces as $namespace) {
			    $pathWithQuery = '/configs/' . $this->app_id . '/' . $this->cluster . '/';
			    $url = $this->server . $pathWithQuery;
			    $label = $_SERVER['HOSTNAME'] ?? '';
			    $releaseKey = Cache::get($pathWithQuery . $namespace . $label);
			    //$releaseKey = (new \think\cache\driver\Redis)->get($pathWithQuery . $namespace);
			    $url = $url . $namespace . '?releaseKey=' . $releaseKey;
			    $query = $pathWithQuery . $namespace . '?releaseKey=' . $releaseKey;
			    $sign = $this->sign($query, $this->secret, $time);
			    $header = [
				    'Authorization:Apollo ' . $this->app_id . ':' . $sign,
				    'Timestamp:'. $time,
			    ];
			    $body = $this->get_curl($url,$header);
			    if ($body['error'] != 200) {
				    continue;
			    }
			    $releaseKey = $body['releaseKey'];
			    //(new \think\cache\driver\Redis)->set($pathWithQuery . $namespace, $releaseKey);
			    Cache::set($pathWithQuery . $namespace. $label, $releaseKey,3600);
			    $cfg = $body['configurations'];
			    if (!$cfg) {
				    continue;
			    }
			    $cfgs = array_merge($cfgs, $cfg);
		    }
		    if ($cfgs) {
			    foreach ($_ENV as $key => $value) {
				    $cfgs[$key] = $cfgs[$key] ?? $_ENV[$key];
			    }
			    $content = '';
			    foreach ($cfgs as $k => $item) {
				    $output->writeln('Saving [' . $k . ']');
				    $content .= $k . '=' . $item . "\n";
			    }
			    $fileName = '.env';
			    $fileName_back = '.env_back';
			    if ($content) {
				    $gao_file = fopen($fileName,"w+");
				    fwrite($gao_file, $content);
				    fclose($gao_file);
				    $gao_file = fopen($fileName_back,"w+");
				    fwrite($gao_file, $content);
				    fclose($gao_file);
			    }
		    }
		
	    } catch (\Exception $ex) {
		    Log::error('apollo',[$ex->getMessage()]);
	    }
    }
    
    
    function get_curl($url,$header){
	    $curl = curl_init(); //初始化curl
	    curl_setopt($curl, CURLOPT_URL, $url); //抓取指定网页
	    curl_setopt($curl, CURLOPT_USERAGENT, 'Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; Trident/6.0)');
	    curl_setopt($curl, CURLOPT_FOLLOWLOCATION, 1);
	    curl_setopt($curl, CURLOPT_AUTOREFERER, 1);
	    curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);//要求结果为字符串且输出到屏幕上
	    curl_setopt($curl, CURLOPT_TIMEOUT, 30); //超时设置
	    curl_setopt($curl, CURLOPT_HTTPHEADER, $header);
	    ob_start();
	    //执行命令
	    $result = curl_exec($curl);
	    ob_end_clean();
	    $return_code = curl_getinfo($curl, CURLINFO_HTTP_CODE);
	    $result = json_decode($result, true);
	    $result['error'] = $return_code;
	    return $result;
    }
	
	protected function sign($pathWithQuery, $secret, $time)
	{
		$data = join("\n", [$time, $pathWithQuery]);
		$sign = base64_encode(hash_hmac('sha1', $data, $secret, true));
		return $sign;
	}
}

上一篇:设立『自动驾驶虚拟仿真赛道』


下一篇:apollo配置动态生效