部署Laravel项目时遇到的问题

话说在Jenkins自动部署Laravel项目时,要生成一个Docker镜像,之前都好好的,开发人员更新代码后,Dockerfile里的“composer install”命令死活通不过,错误信息如下:

—————————————————–

> @php artisan package:discover

In Connection.php line 664:

SQLSTATE[HY000] [2002] php_network_getaddresses: getaddrinfo failed: Name or service not known (SQL: select * from `admin_permissions_xxx`)

—————————————————————————————————————————-

看这信息,应该是DNS解析错误,估计是.env文件的数据库配置有问题,但是git clone把旧版本代码拿下来,同样的.env配置却能顺利“composer install”,看起来就是旧版本在执行install命令时没有去连接数据库,而新版本代码会去连接生产环境数据库,但是按我们的部署方案,镜像是在开发环境生成的,这时候去连接生产环境数据库,而且使用的是内部域名(在.env文件中设置),显然连不上。但让人纳闷的是,为嘛Laravel项目在执行“composer install”时要去连接数据库,百思不得姐……

实在没辙了,就在提示的地方:Connection.php line 664,插入下面的代码,看看调用栈:

function generateCallTrace()
{
$e = new Exception();
$trace = explode(“\n”, $e->getTraceAsString());
// reverse array to make steps line up chronologically
$trace = array_reverse($trace);
array_shift($trace); // remove {main}
array_pop($trace); // remove call to this method
$length = count($trace);
$result = array();

for ($i = 0; $i < $length; $i++)
{
$result[] = ($i + 1) . ‘)’ . substr($trace[$i], strpos($trace[$i], ‘ ‘));
}

return “\t” . implode(“\n\t”, $result);
}

var_dump(generateCallTrace());

看到了项目代码被调用的地方,再往上可以看到从 App\Providers\RouteServiceProvider->map() 下来的,于是知道RouteServiceProvider是在执行“composer install”时就被调用了,要生成路由。新版的代码里面,我们的路由规则是从数据库里读取出来的,因此这时需要连接生产环境的数据库,.env里面的数据库连接信息就被用上了,但是此时临时的Dokcer容器却是在开发环境运行,活该连不上,同时也清楚了为嘛旧版本可以install成功新版本不可以了。解决办法就是不在Dockerfile里面执行“composer install”,而是等到Docker镜像在生产环境里起来后再执行,这时候用.env里面设置的内部域名去访问数据库就OK了。还有一种方法,就是在RouteServiceProvider里面添加“protected $defer = true;”,使这个Provider延迟加载,也可以成功“composer install”,但两种方法的优缺点,还要进行一些测试才看的出来。

发表评论

电子邮件地址不会被公开。