终于开始入了Laravel的坑。公司准备搞一个管理后台,刚开始主要筛选条件是最好使用Yii2框架。音乐目前有一个项目在使用Yii2。但是找了2天发现发现Yii2现有的后台管理框架没有好用的。不过我自己使用了Yii2框架一段时间发现她确实通过配置组件的方式来注入依赖挺好用。但是配置文件大的要死,而且很惊讶的是配置文件里还能写逻辑,确实不能接受。
所以,本着“心中的信仰”尝试了搜索了下Laravel后台系统后发现了这款laravel-admin说实话,一见钟情。于是乎就有了下文的记录。
由于公司使用的是Jenkins
+Docker
的方式部署。涉及开发环境、测试环境、预生产环境、生产环境4个环境配置。Laravel的默认方式(通过.env文件)不适合我们。因为我们开发人员没进入线上服务器的权限,所以对各个环境进行分别配置。
多环境加载原理分析
在网上找了相关教程,发现都是通过修改代码的方式来进行判断环境。
在bootstrap/app.php文件中添加如下判断,在这里将通过获取php.ini中的env的值,然后从而加载不同的配置文件。
//...省略
$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
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
文件:
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的部分
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
[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命令导入环境变量
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行。
# 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