web-dev-qa-db-ja.com

PHP-FPMとNGINXを備えたUbuntu18.04 LTSで、Oracle InstantClientを使用してOCI8 PHP拡張機能を有効にするにはどうすればよいですか?

私は最新のPHPパッケージを https://launchpad.net/~ondrej/+archive/ubuntu/php から入手できます)を使用しています。

OCI8拡張機能をビルドしてインストールすると、すべてが正常に表示されますが、PHP-FPM構成で拡張機能を有効にしているにもかかわらず、その存在はphpinfo()からの出力に反映されません。

次の要点は、OCI8 PHP拡張機能の構成、ビルド、およびインストールに使用している正確なプロセスの詳細です。

https://Gist.github.com/cbj4074/fa761f60b6f8db431539d76ebfba828e

まったく同じプロセスと構成がUbuntu16.04 LTSで完全に機能するため、オペレーティングシステムでも、問題のPHPパッケージでも)、Ubuntu 18.04LTSにはいくつかの根本的な違いがあるようです。

少し重要な(そしてこの問題に関連していると思われる)背景情報として、Ubuntu 18.04 LTSでは、拡張機能をすぐにCLI環境にロードできず、次のエラーが発生します。

PHP警告:PHP起動:ダイナミックライブラリを読み込めません '/usr/lib/php/20160303/oci8.so'-libmql1.so:共有オブジェクトファイルを開くことができません:そのようなファイルまたはディレクトリはありません0行目の不明

私はそのように問題を解決しました:

_# echo 'LD_LIBRARY_PATH="/opt/Oracle/instantclient_12_2"' >> /etc/environment
_

PHP-FPM環境構成に_LD_LIBRARY_PATH_を追加すると、同等の問題が解決する可能性があると思いました。

_# echo "env['LD_LIBRARY_PATH'] = /opt/Oracle/instantclient_12_2" >> /etc/php/7.2/fpm/pool.d/www.conf
# systemctl restart php7.2-fpm
_

これにより、指定された_LD_LIBRARY_PATH_値がphpinfo()Environmentセクションの両方に反映されます(PHP-FPM + NGINXを介してレンダリングされ、ブラウザーから要求された場合) )および_PHP Variables_セクション(_$_SERVER['LD_LIBRARY_PATH']_)。

奇妙なことに、PHP-FPMのログがdebugに設定されていても、CLIで発生する_libmql1.so_エラーの痕跡は見られません。 OCI8拡張機能は、サイレントにロードに失敗するだけです。 PHPの_display_startup_errors = On_- FPMの効果的な_php.ini_も。

OCI8拡張機能が同じサーバー上のApacheで機能するかどうかを確認することを選択しましたが、_export LD_LIBRARY_PATH=/opt/Oracle/instantclient_12_2_を_/etc/Apache2/envvars_に追加すれば機能します。不在の場合、Apacheは起動時に文句を言います。

PHP警告:PHP起動:ダイナミックライブラリ 'oci8.so'を読み込めません(試行:/usr/lib/php/20170718/oci8.so(libmql1.so:共有オブジェクトファイルを開くことができません) :そのようなファイルまたはディレクトリはありません)、/ usr/lib/php/20170718/oci8.so.so(/usr/lib/php/20170718/oci8.so.so:共有オブジェクトファイルを開くことができません:そのようなファイルまたはディレクトリはありません) )0行目の不明

_LD_LIBRARY_PATH_とのこのビジネスはUbuntu 16.04 LTSでは必要ありません。ここでの私の観察と、 https://stackoverflow.com/a/45242468/1772379 に関するコメントに基づくと、 Ubuntu17.10およびUbuntu18.04LTSで変更されました。

特にUbuntu18.04 LTSで、他の誰かがこれを試しましたか?

_laravel/Homestead_ボックス6.0.0と_ubuntu/bionic64_ボックスv20180509.0.0の2つの異なるVagrant VMでこれを試しましたが、動作はどちらも同じです。

他のアイデアは大歓迎です!

編集1

パッケージメンテナーのGitHubトラッカーでこの問題について質問しました そして彼は、問題はコンパイル時に適切なRPATHを設定できなかったことが原因であると示唆しました。

私はamが適切な値を設定していると返信で説明していますが、問題は解決されていません。

ただし、Ubuntu18.04でコンパイルされた拡張機能がRUNPATHを使用している(Ubuntu16.04で使用されているRPATHではない)という興味深い詳細に気づきました。 PHP-FPMがRUNPATHを無視し、RPATHのみを検索する場合、この動作を説明します。

編集2

このまだ開かれているレポートは、観察された動作を紹介した優れた候補のように見えます。

https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=859732

RUNPATHではなくRPATHを使用しますか? に関するコメントを通じて発見されました)

編集3

コメント提供者のアドバイスにより、拡張機能をビルドする前にld構成を更新することを再検討したところ、問題は解決しました。私は以前にこれを試しましたが、ビルドの試行の間に何かを見落としていたに違いありません。

_# echo /opt/Oracle/instantclient_12_2 > /etc/ld.so.conf.d/Oracle-instantclient.conf
# ldconfig
_

_LD_LIBRARY_PATH_がこの場合のように機能しない理由はまだわかりませんが、リンカー構成にインスタントクライアントライブラリパスを追加する方が良いアプローチのようです。

編集4

以前の編集で、ldconfigを変更する方が良いアプローチであると述べましたが、影響はシステム全体に及ぶため、変更すると望ましくないライブラリの競合が発生する可能性があることに気付きました(コメント投稿者の良いアドバイスに基づいて)。

後から考えると、ランタイムライブラリリンケージの変更による「巻き添え被害」を_LD_LIBRARY_PATH_を介して実行環境に限定することで最小限に抑えることは理にかなっています。したがって、Ubuntu 18.04LTSでこれが機能しない理由を特定することに意欲的です。

PHP-FPMデーモンがUbuntuの_LD_LIBRARY_PATH_を無視することを明確に確立したと感じています(少なくともUbuntu 16.04 LTSがあります。説明についてはコメントを参照してください)。

ld.so(8)マンページの状態(ランタイムライブラリパスが検索される順序に関連して):

環境変数LD_LIBRARY_PATHを使用します(実行可能ファイルがセキュア実行モードで実行されている場合を除く。以下を参照)。 [原文ママ]その場合は無視されます。

今のところ、パスが無視される他の理由は考えられません。 _secure-execution mode_について、同じ文書には次のように書かれています。

_ Secure-execution mode
       For  security reasons, the effects of some environment variables are voided or modified if the dynamic linker determines that the binary
       should be run in secure-execution mode.  (For details, see the discussion of individual environment variables below.)  A binary is  exe‐
       cuted  in  secure-execution  mode if the AT_SECURE entry in the auxiliary vector (see getauxval(3)) has a nonzero value.  This entry may
       have a nonzero value for various reasons, including:

       *  The process's real and effective user IDs differ, or the real and effective group IDs differ.  This typically occurs as a  result  of
          executing a set-user-ID or set-group-ID program.

       *  A process with a non-root user ID executed a binary that conferred capabilities to the process.

       *  A nonzero value may have been set by a Linux Security Module.
_

まず、PHP実行可能ファイルはこのフラグを表示しないため、セキュア実行モードは有効になっていないようです(_AT_SECURE_ is _0_):

_LD_SHOW_AUXV=1 /usr/sbin/php-fpm7.1 -daemonize --fpm-config /etc/php/7.1/fpm/php-fpm.conf
AT_SYSINFO_EHDR: 0x7ffc569e1000
AT_HWCAP:        178bfbff
AT_PAGESZ:       4096
AT_CLKTCK:       100
AT_PHDR:         0x55ceab0c4040
AT_PHENT:        56
AT_PHNUM:        9
AT_BASE:         0x7f823c77f000
AT_FLAGS:        0x0
AT_ENTRY:        0x55ceab19e360
AT_UID:          0
AT_EUID:         0
AT_GID:          0
AT_EGID:         0
AT_SECURE:       0
AT_RANDOM:       0x7ffc56962349
AT_HWCAP2:       0x0
AT_EXECFN:       /usr/sbin/php-fpm7.1
AT_PLATFORM:     x86_64
_

子FPMプールプロセスが異なる_AT_SECURE_値を示す可能性があることに気付きましたが、出力はPHP-FPMデーモン自体と子プロセスで同じです。親と子はすべて次の値を持ちます。

_# od -t d8 /proc/851/auxv
0000000                   33      140722944548864
0000020                   16            395049983
0000040                    6                 4096
0000060                   17                  100
0000100                    3       93903778242624
0000120                    4                   56
0000140                    5                    9
0000160                    7      140365152313344
0000200                    8                    0
0000220                    9       93903779136352
0000240                   11                    0
0000260                   12                    0
0000300                   13                    0
0000320                   14                    0
0000340                   23                    0
0000360                   25      140722944193929
0000400                   26                    0
0000420                   31      140722944196579
0000440                   15      140722944193945
0000460                    0                    0
_

次に、次のことを考えると、これらの理由はどれも当てはまらないようです。

1)PHP-FPMまたはその子プロセスの実際の有効なユーザーIDまたはグループIDが異なることを示すものはありません(このコマンドのおかげで https://unix.stackexchange.com/a/202359 )::

_# ps -e -o user= -o ruser= | awk '$1 != $2'
systemd+ systemd-timesync
systemd+ systemd-resolve
beansta+ beanstalkd
message+ messagebus
daemon   root
systemd+ systemd-network

# ps -e -o group= -o rgroup= | awk '$1 != $2'
systemd+ systemd-timesync
systemd+ systemd-resolve
beansta+ beanstalkd
message+ messagebus
daemon   root
systemd+ systemd-network
_

2)問題のバイナリには機能がありません(次のコマンドは出力を生成しません):

_# getcap /usr/lib/php/20170718/oci8.so
# getcap -r /opt/Oracle/instantclient_12_2/
_

3)AppArmorが無効になっていることを確認しました(とにかく、PHP-FPMに影響を与えるポリシーはありません):

_# systemctl disable apparmor
Synchronizing state of apparmor.service with SysV service script with /lib/systemd/systemd-sysv-install.
Executing: /lib/systemd/systemd-sysv-install disable apparmor
# reboot
# aa-status
apparmor module is loaded.
0 profiles are loaded.
0 profiles are in enforce mode.
0 profiles are in complain mode.
0 processes have profiles defined.
0 processes are in enforce mode.
0 processes are in complain mode.
0 processes are unconfined but have a profile defined.
_

では、前述の理由のいずれかが原因ではないのに、なぜPHP-FPMは_LD_LIBRARY_PATH_を無視するのでしょうか。

編集5(解決策)

鋭敏なコメント投稿者@ vinc17は、systemdを実行しているシステムでは、_LD_LIBRARY_PATH_などの環境変数が必ずしもsystemdユニットを介して開始されるプロセスに伝播されるとは限らないと指摘しています。 。

言い換えれば、PHP-FPMは_LD_LIBRARY_PATH_を「無視」しているのではなく、プロセスに伝達されていません。また、PHP-FPM構成内で_LD_LIBRARY_PATH_を設定しようとしても、値を使用して有用なことを行うには遅すぎるため、無駄です。

このアドバイスで、_LD_LIBRARY_PATH_をsystemdコンテキスト、つまりPHP-FPMデーモンを開始するユニットファイル(この場合はPHP-)に設定することになりました。 FPMはOCI8拡張機能を正常にロードします。

言うまでもなく、パッケージメンテナーのファイルの編集は避けたいので(将来のアップグレード時の競合を避けるため)、代わりに次のように拡張します。

_# mkdir /etc/systemd/system/php7.1-fpm.service.d
# touch /etc/systemd/system/php7.1-fpm.service.d/environment.conf
_

このファイルに以下を追加します。

_[Service]
Environment=LD_LIBRARY_PATH=/opt/Oracle/instantclient_12_2
_

そして、変更を効果的にするために:

_# systemctl daemon-reload
# systemctl restart php7.1-fpm
_

複数の同時インストールされたPHPバージョンに対応する、より完全な例については、 https://github.com/oerdnj/deb.sury.org/issues)の私の投稿を参照してください。/865#issuecomment-395441936

7
Ben Johnson

まず、 Debianバグ859732 はまったく別の問題です(反対の問題と言ってもいいでしょう):このバグでは、ライブラリのいくつかのバージョンが検索パスに存在します(LD_LIBRARY_PATHで指定されたディレクトリに1つあります)。実行パスで指定されたディレクトリに別のものがあります)が、ダイナミックリンカーによって間違ったものが選択されています。

あなたの場合、問題は、要求されたライブラリが検索パスのどこにも見つからないことです。あなたの場合、メッセージがで始まるので、ライブラリを開こうとしているように見えるのはPHP)であることにも注意してください( dlopen ?経由) 「PHP警告:」。ただし、メカニズムは通常のダイナミックリンクと同じようです。

ライブラリをインストールした後、必要なものは少なくとも次のいずれかです。

  • デフォルトで検索されるディレクトリにライブラリがインストールされている場合、特別なことは何もありません。エラーが発生するため、これは当てはまりません。
  • ライブラリを必要とするソフトウェアのコンパイル時に指定する必要がある実行パスにディレクトリを提供します。問題は、Linuxでは、これはビルドツールによって標準で行われず、他のものを壊さずに正しく行うのは複雑な場合があることです。ただし、dlopenのコンテキストでは、ソフトウェア(ここではPHP)が、ライブラリを配置できる「プラグイン検索パス」と呼ばれるものを設定している場合があります。
  • LD_LIBRARY_PATHにディレクトリを提供します。これはあなたが試したことですが、あなたのLD_LIBRARY_PATHは間違っているようです。ライブラリは通常、lib(または特定の場合にはlib32またはlib64)という名前のサブディレクトリにインストールされます。したがって、export LD_LIBRARY_PATH=/opt/Oracle/instantclient_12_2は間違っているようです。ライブラリoci8.soのフルパス名を検索し、このパス名のディレクトリ部分でLD_LIBRARY_PATHを取得します。

注:straceは、ライブラリを検索するために考慮されるディレクトリを確認するのに役立つ場合があります。 EDIT:lddobjdump -pは、検索パスで何が起こっているかを見つけるための他の便利なツールです。

編集2:実行パスの使用を選択する際のもう1つの注意点は、RPATHを使用すると、間接的なライブラリの依存関係が見つかることです。 RUNPATHが使用されている場合ではありません(したがって、後者の場合、すべての依存関係alsoが他のライブラリに依存している場合は、すべてのライブラリが実行できるように実行パスが必要です。 LD_LIBRARY_PATHに頼らずに見つけられます)。これは、ld.so(8)のマニュアルページの最近のバージョンに記載されています。

バイナリのDT_RUNPATH動的セクション属性で指定されているディレクトリが存在する場合はそれを使用します。このようなディレクトリは、DT_NEEDED(直接依存関係)エントリに必要なオブジェクトを見つけるためにのみ検索され、独自のDT_RUNPATHエントリが必要なオブジェクトの子には適用されません。これは、依存関係ツリー内のすべての子の検索に適用されるDT_RPATHとは異なります。

これがおそらく、LD_LIBRARY_PATHを使用せずに、16.04(RPATHが使用される)では機能したが、18.04(RUNPATHが使用される)では機能しなかった理由です。

1
vinc17