在 Laravel 6 中,环境变量的覆写实现的变通方案(env()、config())

1、在生产环境中遇见一个 Bug,当一个容器全新部署后,在第一次运行时,其环境变量的取值,感觉并非容器的环境变量,而是 null。在第二次运行时,其环境变量的取值才正确。在第一次运行时,导致 CDN 请求响应 403。如图1

图1

2、由于容器的环境变量允许覆写,其大致实现流程如下:
(1)从 Vault 获取到某容器的所有环境变量数组
(2)待修改的环境变量合并到第(1)步中获取的环境变量数组中
(3)将新的环境变量数组更新到 Vault
(4)同版本更新容器使环境变量生效

3、环境变量的使用,实际是在 Laravel 的配置文件使用了函数:env()。

'debug' => env('APP_DEBUG', false),

4、在第一次运行时,其环境变量的取值,缓存 $json 为 null,从接口响应 $json 中获取的环境变量,会将环境变量进行覆写。

putenv("{$key}={$value}");
$_ENV[$key] = $value;

5、但是,此时,基于环境变量生成的配置项,即 config 目录下的配置文件,已经被执行了,所以,config 配置项仍然是旧的。

// 主题素材CDN
'theme-asset-cdn' => [
 'driver' => 's3',
 'key' => env('THEME_ASSET_CDN_AWS_ACCESS_KEY_ID'),
 'secret' => env('THEME_ASSET_CDN_AWS_SECRET_ACCESS_KEY'),
 'region' =>  env('THEME_ASSET_CDN_AWS_DEFAULT_REGION', 'us-east-2'),
 'bucket' => env('THEME_ASSET_CDN_BUCKET', 'object-theme-assets'),
 'root' => env('THEME_ASSET_CDN_ASSET_PREFIX', 'static/xxx/'),
],

6、因此,在第一次运行时,感觉上便像 $json 并未立即被应用至环境变量中。环境变量的覆写实现的变通方案,实际是可通过再次覆写 config() 实现。此时,给用户的感觉便是新的环境变量值已经覆盖了旧的环境变量值。

$newConfig = [
 'theme.view_storage' => $json['VIEW_STORAGE'] ?? config('theme.view_storage'),
];
config($newConfig);

7、不过,此方案很是冗余,一旦有新增加的配置项,那么皆需要在 $newConfig 中同步增加相应的配置项。代码实现冗余。尝试替代的方案,基于新的环境变量重新加载配置项。但是,此方案会导致模块目录中的配置项丢失,以及在重新加载之前基于 config()函数自定义的配置项丢失。留待后续完善。如图2

图2

$key = 'THEME_ASSET_CDN_BUCKET';
$value = 'object-theme-assets00';
putenv("{$key}={$value}");
$_ENV[$key] = $value;
config(['theme.view_storage' => 'ss']);
$loadConfiguration = new LoadConfiguration();
$loadConfiguration->bootstrap(app());
Log::debug(
 'theme.v2.tenant.manager.1',
 [
  'env.THEME_ASSET_CDN_BUCKET' => env('THEME_ASSET_CDN_BUCKET'),
  'theme.view_storage' => config('theme.view_storage') ?? null,
  'theme_asset.versioning' => config('theme_asset.versioning') ?? null,
  'theme_asset.cdn_url' => config('theme_asset.cdn_url') ?? null,
  'theme_asset.filesystem.disk' => config('theme_asset.filesystem.disk') ?? null,
  'filesystems.disks.theme-asset-cdn' => config('filesystems.disks.theme-asset-cdn') ?? null,
 ]
);
[2023-03-21 18:08:56] local.DEBUG: theme.v2.tenant.manager.1 {
    "env.THEME_ASSET_CDN_BUCKET": "object-theme-assets00",
    "theme.view_storage": "database",
    "theme_asset.versioning": null,
    "theme_asset.cdn_url": null,
    "theme_asset.filesystem.disk": null,
    "filesystems.disks.theme-asset-cdn": {
        "driver": "s3",
        "key": "111111111111",
        "secret": "22222222222",
        "region": "us-east-2",
        "bucket": "object-theme-assets00",
        "root": "static/xxx/"
    }
} 
永夜