为什么具有 uwsgi_psgi 的 Perlbrew PSGI 应用程序导致 "wrong" Perl 包含路径?

Why a Perlbrew PSGI application with uwsgi_psgi causes "wrong" Perl include paths?

我想使用 uWSGI 网关接口部署基于 PSGI 的 Web 应用程序。

为此,我在我的 Debian 服务器上本地安装了 Perlbrew,但没有根访问权限。

perlbrew init
# close shell and reopen new shell
perlbrew self-install
# close shell and reopen new shell
perlbrew self-upgrade
# close shell and reopen new shell
perlbrew install-patchperl
perlbrew install-cpanm
# close shell and reopen new shell
perlbrew install -j 10 perl-5.26.1
perlbrew lib create perl-5.26.1@main
perlbrew switch perl-5.26.1@main
# close shell and reopen new shell

然后我检查使用cpanm -V Perl 环境:

cpanm (App::cpanminus) version 1.7043 (/home/soeren/perl5/perlbrew/bin/cpanm)
perl version 5.026001 (/home/soeren/perl5/perlbrew/perls/perl-5.26.1/bin/perl)

  %Config:
    archname=x86_64-linux
    installsitelib=/home/soeren/perl5/perlbrew/perls/perl-5.26.1/lib/site_perl/5.26.1
    installsitebin=/home/soeren/perl5/perlbrew/perls/perl-5.26.1/bin
    installman1dir=/home/soeren/perl5/perlbrew/perls/perl-5.26.1/man/man1
    installman3dir=/home/soeren/perl5/perlbrew/perls/perl-5.26.1/man/man3
    sitearchexp=/home/soeren/perl5/perlbrew/perls/perl-5.26.1/lib/site_perl/5.26.1/x86_64-linux
    sitelibexp=/home/soeren/perl5/perlbrew/perls/perl-5.26.1/lib/site_perl/5.26.1
    archlibexp=/home/soeren/perl5/perlbrew/perls/perl-5.26.1/lib/5.26.1/x86_64-linux
    privlibexp=/home/soeren/perl5/perlbrew/perls/perl-5.26.1/lib/5.26.1
  %ENV:
    PERL5LIB=/home/soeren/.perlbrew/libs/perl-5.26.1@main/lib/perl5
    PERLBREW_HOME=/home/soeren/.perlbrew
    PERLBREW_LIB=main
    PERLBREW_MANPATH=/home/soeren/.perlbrew/libs/perl-5.26.1@main/man:/home/soeren/perl5/perlbrew/perls/perl-5.26.1/man
    PERLBREW_PATH=/home/soeren/.perlbrew/libs/perl-5.26.1@main/bin:/home/soeren/perl5/perlbrew/bin:/home/soeren/perl5/perlbrew/perls/perl-5.26.1/bin
    PERLBREW_PERL=perl-5.26.1
    PERLBREW_ROOT=/home/soeren/perl5/perlbrew
    PERLBREW_SHELLRC_VERSION=0.82
    PERLBREW_VERSION=0.82
    PERL_LOCAL_LIB_ROOT=/home/soeren/.perlbrew/libs/perl-5.26.1@main
    PERL_MB_OPT=--install_base /home/soeren/.perlbrew/libs/perl-5.26.1@main
    PERL_MM_OPT=INSTALL_BASE=/home/soeren/.perlbrew/libs/perl-5.26.1@main
  @INC:
    FatPacked::93953009226544=HASH(0x557323bd9330)
    /home/soeren/.perlbrew/libs/perl-5.26.1@main/lib/perl5/x86_64-linux
    /home/soeren/.perlbrew/libs/perl-5.26.1@main/lib/perl5
    /home/soeren/perl5/perlbrew/perls/perl-5.26.1/lib/site_perl/5.26.1/x86_64-linux
    /home/soeren/perl5/perlbrew/perls/perl-5.26.1/lib/site_perl/5.26.1
    /home/soeren/perl5/perlbrew/perls/perl-5.26.1/lib/5.26.1/x86_64-linux
    /home/soeren/perl5/perlbrew/perls/perl-5.26.1/lib/5.26.1

一切看起来都不错,所以我安装了 Dancer2 作为首选的 Web 框架,并成功启动了框架测试应用程序:

dancer2 gen --application DemoApp
cd ./DemoApp
plackup ./bin/app.psgi

Plack 内部 HTTP Web 服务器已启动并准备好为应用程序提供服务。

同样,到目前为止一切顺利。但我想使用 uWSGI,而不是在服务链中使用另一个完全成熟的 Web 服务器。

所以我安装了 uwsgi-plugin-psgi 自动附带 uwsgi-core:

apt install uwsgi-plugin-psgi

现在我想启动uWSGI网关接口...:[=​​28=]

uwsgi_psgi --uwsgi-socket 127.0.0.1:5999 --psgi /home/soeren/DemoApp/bin/app.psgi

...应用程序崩溃了:

[uwsgi] implicit plugin requested psgi
*** Starting uWSGI 2.0.14-debian (64bit) on [Fri Feb  9 10:41:20 2018] ***
compiled with version: 6.2.1 20161124 on 07 December 2016 16:14:59
os: Linux-4.9.0-5-amd64 #1 SMP Debian 4.9.65-3+deb9u2 (2018-01-04)
nodename: skde-deu-02.sklink.de
machine: x86_64
clock source: unix
pcre jit disabled
detected number of CPU cores: 8
current working directory: /home/soeren/DemoApp
detected binary path: /usr/bin/uwsgi-core
*** WARNING: you are running uWSGI without its master process manager ***
your processes number limit is 256817
your memory page size is 4096 bytes
detected max file descriptor number: 1024
lock engine: pthread robust mutexes
thunder lock: disabled (you can enable it with --thunder-lock)
uwsgi socket 0 bound to TCP address 127.0.0.1:5999 fd 3
initialized Perl 5.24.1 main interpreter at 0x557337c6fd40
your server socket listen backlog is limited to 100 connections
your mercy for graceful operations on workers is 60 seconds
mapped 72768 bytes (71 KB) for 1 cores
*** Operational MODE: single process ***
Error while loading /home/soeren/DemoApp/bin/app.psgi: Can't locate WWW/Form/UrlEncoded.pm in @INC (you may need to install the WWW::Form::UrlEncoded module) (@INC contains: /home/soeren/DemoApp/bin/../lib /home/soeren/.perlbrew/libs/perl-5.26.1@main/lib/perl5/5.24.1/x86_64-linux-gnu-thread-multi /home/soeren/.perlbrew/libs/perl-5.26.1@main/lib/perl5/5.24.1 /home/soeren/.perlbrew/libs/perl-5.26.1@main/lib/perl5/x86_64-linux-gnu-thread-multi /home/soeren/.perlbrew/libs/perl-5.26.1@main/lib/perl5 /etc/perl /usr/local/lib/x86_64-linux-gnu/perl/5.24.1 /usr/local/share/perl/5.24.1 /usr/lib/x86_64-linux-gnu/perl5/5.24 /usr/share/perl5 /usr/lib/x86_64-linux-gnu/perl/5.24 /usr/share/perl/5.24 /usr/local/lib/site_perl) at /home/soeren/.perlbrew/libs/perl-5.26.1@main/lib/perl5/HTTP/Entity/Parser/UrlEncoded.pm line 5.
BEGIN failed--compilation aborted at /home/soeren/.perlbrew/libs/perl-5.26.1@main/lib/perl5/HTTP/Entity/Parser/UrlEncoded.pm line 5.
Compilation failed in require at /usr/share/perl/5.24/Module/Load.pm line 77.
Can't locate HTTP/Entity/Parser/UrlEncoded in @INC (@INC contains: /home/soeren/DemoApp/bin/../lib /home/soeren/.perlbrew/libs/perl-5.26.1@main/lib/perl5/5.24.1/x86_64-linux-gnu-thread-multi /home/soeren/.perlbrew/libs/perl-5.26.1@main/lib/perl5/5.24.1 /home/soeren/.perlbrew/libs/perl-5.26.1@main/lib/perl5/x86_64-linux-gnu-thread-multi /home/soeren/.perlbrew/libs/perl-5.26.1@main/lib/perl5 /etc/perl /usr/local/lib/x86_64-linux-gnu/perl/5.24.1 /usr/local/share/perl/5.24.1 /usr/lib/x86_64-linux-gnu/perl5/5.24 /usr/share/perl5 /usr/lib/x86_64-linux-gnu/perl/5.24 /usr/share/perl/5.24 /usr/local/lib/site_perl) at /usr/share/perl/5.24/Module/Load.pm line 77.
Compilation failed in require at /home/soeren/.perlbrew/libs/perl-5.26.1@main/lib/perl5/Plack/Request.pm line 17.
BEGIN failed--compilation aborted at /home/soeren/.perlbrew/libs/perl-5.26.1@main/lib/perl5/Plack/Request.pm line 17.
Compilation failed in require at /usr/share/perl/5.24/parent.pm line 16.
BEGIN failed--compilation aborted at /home/soeren/.perlbrew/libs/perl-5.26.1@main/lib/perl5/Dancer2/Core/Request.pm line 6.
Compilation failed in require at /home/soeren/.perlbrew/libs/perl-5.26.1@main/lib/perl5/Dancer2/Core/App.pm line 29.
BEGIN failed--compilation aborted at /home/soeren/.perlbrew/libs/perl-5.26.1@main/lib/perl5/Dancer2/Core/App.pm line 29.
Compilation failed in require at /home/soeren/.perlbrew/libs/perl-5.26.1@main/lib/perl5/Dancer2.pm line 11.
BEGIN failed--compilation aborted at /home/soeren/.perlbrew/libs/perl-5.26.1@main/lib/perl5/Dancer2.pm line 11.
Compilation failed in require at /home/soeren/DemoApp/bin/../lib/DemoApp.pm line 2.
BEGIN failed--compilation aborted at /home/soeren/DemoApp/bin/../lib/DemoApp.pm line 2.
Compilation failed in require at /home/soeren/DemoApp/bin/app.psgi line 10.
BEGIN failed--compilation aborted at /home/soeren/DemoApp/bin/app.psgi line 10.
unable to find PSGI function entry point.
*** no app loaded. going in full dynamic mode ***
*** uWSGI is running in multiple interpreter mode ***
spawned uWSGI worker 1 (and the only) (pid: 9769, cores: 1)

我首先看到的是建筑。虽然其他(cpnamplackup)程序使用 "x86_64-linux" 架构,但只有 uWSGI 使用 "x86_64-linux-gnu-thread-multi"。

"x86_64-linux-gnu-thread-multi" 的 Perl 体系结构文件夹可用,但不包含任何模块。大多数模块都安装在 "root library path" 和 "x86_64-linux" 架构文件夹中。

/home/soeren/.perlbrew/libs/perl-5.26.1@main/lib/perl5
/home/soeren/.perlbrew/libs/perl-5.26.1@main/lib/perl5/x86_64-linux

我试图通过使用 uwsgi_psgi 命令行开关 --perl-local-lib 来解决这个问题,但没有成功:

uwsgi_psgi --uwsgi-socket 127.0.0.1:5999 --psgi /home/soeren/DemoApp/bin/app.psgi --perl-local-lib /home/soeren/.perlbrew/libs/perl-5.26.1@main/lib/perl5
uwsgi_psgi --uwsgi-socket 127.0.0.1:5999 --psgi /home/soeren/DemoApp/bin/app.psgi --perl-local-lib /home/soeren/.perlbrew/libs/perl-5.26.1@main/lib/perl5/x86_64-linux

我也曾尝试过不同的 uWSGI 操作模式(单进程、prefork、线程),但也不走运。

为什么 uWSGI 修改包含路径,我如何启动 uWSGI 使其像其他程序一样工作,或者另外安装该体系结构的模块?

感谢@simbabque,我找到了解决方案。

我的问题是我使用的是系统本机 uwsgi_psgi,它是使用系统 Perl 安装编译的,与我本地的 Perlbrew 安装不兼容。

mailing list thread 建议在 Perlbrew 范围内重新编译 uwsgi 以便能够(仅)与本地 Perlbrew 安装一起工作。

因此,通过执行以下编译,我设法启动了 Perl 应用程序:

curl http://uwsgi.it/install | bash -s psgi /home/soeren/perl5/perlbrew/bin/uwsgi

但是上面显示的命令并不是最好的方法,因为它缺少所有更重要的编译开关(例如 pcre、jit)。

随着时间的推移,我会通过进一步的编译开关改进这个答案。