laravel5.5多环境配置

终于开始入了Laravel的坑。公司准备搞一个管理后台,刚开始主要筛选条件是最好使用Yii2框架。音乐目前有一个项目在使用Yii2。但是找了2天发现发现Yii2现有的后台管理框架没有好用的。不过我自己使用了Yii2框架一段时间发现她确实通过配置组件的方式来注入依赖挺好用。但是配置文件大的要死,而且很惊讶的是配置文件里还能写逻辑,确实不能接受。

所以,本着“心中的信仰”尝试了搜索了下Laravel后台系统后发现了这款laravel-admin说实话,一见钟情。于是乎就有了下文的记录。

key-generate

由于公司使用的是Jenkins+Docker的方式部署。涉及开发环境、测试环境、预生产环境、生产环境4个环境配置。Laravel的默认方式(通过.env文件)不适合我们。因为我们开发人员没进入线上服务器的权限,所以对各个环境进行分别配置。

多环境加载原理分析

在网上找了相关教程,发现都是通过修改代码的方式来进行判断环境。

在bootstrap/app.php文件中添加如下判断,在这里将通过获取php.ini中的env的值,然后从而加载不同的配置文件。

1
2
3
4
5
6
7
8
9
//...省略
$env = get_cfg_var('env');
$env = !empty($env) ? $env : 'production';
if(!defined('APP_MODE')){
define('APP_MODE', $env);
}
$app->loadEnvironmentFrom('.env.'.$env);

return $app;

但是在laravel5.5后底层已经做了多环境配置文件的读取逻辑。

env加载由下面的逻辑处理\Illuminate\Foundation\Bootstrap\LoadEnvironmentVariables::class

1
2
3
4
5
6
7
8
9
10
11
12
public function bootstrap(Application $app)
{
if ($app->configurationIsCached()) {
return;
}
$this->checkForSpecificEnvironmentFile($app);
try {
(new Dotenv($app->environmentPath(), $app->environmentFile()))->load();
} catch (InvalidPathException $e) {
//
}
}

如果我们在环境变量中设置了 APP_ENV 变量,那么就会调用函数 checkForSpecificEnvironmentFile 来根据环境加载不同的 env 文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
protected function checkForSpecificEnvironmentFile($app)
{
if (php_sapi_name() == 'cli' && with($input = new ArgvInput)->hasParameterOption('--env')) {
$this->setEnvironmentFilePath(
$app, $app->environmentFile().'.'.$input->getParameterOption('--env')
);
}
if (! env('APP_ENV')) {
return;
}
$this->setEnvironmentFilePath(
$app, $app->environmentFile().'.'.env('APP_ENV')
);
}
protected function setEnvironmentFilePath($app, $file)
{
if (file_exists($app->environmentPath().'/'.$file)) {
$app->loadEnvironmentFrom($file);
}
}

知道了配置文件的加载逻辑,那么我们就可以配置了

开始

因为laravel默认是读取项目根目录下的.env文件。显然这种方式不适合我们。可Laravel5.5已经支持读取.env.xxx这种格式的文件。但是$_SERVER['APP_ENV']必须被设置。

首先建立各环境配置文件

  • .env.local

  • .env.development

  • .env.testing
  • .env.staging
  • .env.production

上面的文件基本都是拷贝.env.example文件中的内容,然后在执行php artisan key:generate —env=xxx来生成各个环境配置APP_KEY

Laravel配置多环境3种方式

通过nginx配置

找到nginx配置文件中的解析php的部分

1
2
3
4
5
6
7
8
9
10
11
location ~ [^/]\.php(/|$)
{
try_files $uri =404;
fastcgi_pass unix:/tmp/php-cgi-72.sock;
fastcgi_index index.php;
include fastcgi.conf;
include pathinfo.conf;

#加入环境配置
fastcgi_param APP_ENV production;
}

这样PHP就可以在$_SERVER超全局数组中获取到'APP_ENV'的值就可以判断读取配置了。

通过php-fpm配置

同样的,找到php-fpm.conf配置文件,加入最后一行

homestead环境对应的为/etc/php/7.2/fpm/pool.d/www.conf

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
[global]
pid = /www/server/php/72/var/run/php-fpm.pid
error_log = /www/server/php/72/var/log/php-fpm.log
log_level = notice

[www]
listen = /tmp/php-cgi-72.sock
listen.backlog = -1
listen.allowed_clients = 127.0.0.1
listen.owner = www
listen.group = www
listen.mode = 0666
user = www
group = www
...

# 加入环境配置
env[APP_ENV] = production

设置系统环境变量配置

这种方式可以给fpm用也可以给cli方式使用。

使用export命令导入环境变量

1
export APP_ENV=local

但是为了方便使用一般都是配置在用户的.bashrc或者.profile文件中。

请注意使用这种方式在fpm方式下还需要在php.ini中将variables_order 设置为 EGPCS

Homestead配置解析

我本地开发使用的是homestead环境,所以看了下homestead的部分代码发现homestead使用的是php-fpm的方式来操作的。

/Users/lePig/Homestead/scripts/homestead.rb大概264行。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# Configure All Of The Server Environment Variables
config.vm.provision "shell" do |s|
s.name = "Clear Variables"
s.path = scriptDir + "/clear-variables.sh"
end

if settings.has_key?("variables")
settings["variables"].each do |var|
config.vm.provision "shell" do |s|
s.inline = "echo \"\nenv[$1] = '$2'\" >> /etc/php/5.6/fpm/pool.d/www.conf"
s.args = [var["key"], var["value"]]
end

config.vm.provision "shell" do |s|
s.inline = "echo \"\nenv[$1] = '$2'\" >> /etc/php/7.0/fpm/pool.d/www.conf"
s.args = [var["key"], var["value"]]
end

config.vm.provision "shell" do |s|
s.inline = "echo \"\nenv[$1] = '$2'\" >> /etc/php/7.1/fpm/pool.d/www.conf"
s.args = [var["key"], var["value"]]
end

config.vm.provision "shell" do |s|
s.inline = "echo \"\nenv[$1] = '$2'\" >> /etc/php/7.2/fpm/pool.d/www.conf"
s.args = [var["key"], var["value"]]
end

config.vm.provision "shell" do |s|
s.inline = "echo \"\n# Set Homestead Environment Variable\nexport $1=$2\" >> /home/vagrant/.profile"
s.args = [var["key"], var["value"]]
end
end
end