LoginSignup
38
38

More than 5 years have passed since last update.

OPcache が有効で且つ PHP-FPM を使用した ウェブサーバで、Symlink ベースのデプロイするとコードが反映されない

Posted at

現象

表題の通りですが、現象を噛み砕いて説明します。

筆者は Symlink ベースのデプロイツール ( Ansistrano ) を使用してデプロイをしています。

※ Symlink ベースのデプロイツールは Capistrano や、Deployer なども含まれます。

デプロイが完了したサーバ側のディレクトリ構造は以下のようになります。

tree
.
├── current -> ./releases/20160530055905
├── releases
│   ├── 20160530055905
│   ├── 20160530055658
│   └── 20160530050508
└── shared

デプロイされると、 current ディレクトリはシンボリックリンクとなっており、 releases 以下に、デプロイされた最新のアプリケーションコードを指します。
ウェブサーバやアプリケーションサーバの設定ではドキュメントルートに current ディレクトリを指してます。

この時、 OPcache が有効で且つ PHP-FPM を使用した Web サーバーではコードが反映されないという現象が発生しました。

原因

PHP5.5 以降のコードキャッシュは APC から OPcache を使うようになりました。
APC は、ファイルをキャッシュするために、 inode を用います。 inode はシンボリックを解決し、参照するように働きます。しかし OpCache は inode ベースではありません。 OpCache は、キャッシュする前に絶対ファイルパスを見つけるためにシンボリックリンクを評価するのでデプロイする前のパスを覚えています。

つまり、 PHP がデプロイされた最新のアプリケーションコードへシンボリックリンクを参照せず、その一つ前の世代のアプリケーションコードを参照している ということです。

解決方法

  • Web サーバーのドキュメントルートの設定を直接書き換える
  • OPcache をリセットする
  • PHP-FPM を再起動する

ウェブサーバに nginx を利用している場合の解決方法

nginx は、シンボリックリンクを解決できるように設定することが可能です。
nginx の構成では、おそらく以下のような設定となってます。
以下のような設定の場合、 $document_rootcurrent ディレクトリのシンボリックリンクを解決せずに参照します。

/etc/nginx/nginx.conf
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param DOCUMENT_ROOT $document_root;

以下のように $document_root から $realpath_root を指定するように設定を変更します。
そうすることで current ディレクトリのシンボリックリンクを解決し、 release ディレクトリ配下のアプリケーションコードの絶対パスを参照できるようになります。

/etc/nginx/nginx.conf
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
fastcgi_param DOCUMENT_ROOT $realpath_root;

参考文献

PHP's OPcache and Symlink-based Deploys

38
38
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
38
38