OPcacheが有効になっているPHP-FPMをRead Onlyコンテナで動かす


環境

前提

  • OPcache
    • キャッシュ有効化
    • file_cache_onlyが無効
    • lockfile_pathが/tmp
  • PHP-FPM
    • pidへのファイルパスなし
  • Docker
    • Read Only mode

方法

opcacheのロックファイルが作成される/tmpにvolumeをマウントします。

docker run -d -p 9000:9000 --read-only -v $(pwd)/tmp:/tmp php:7.3-fpm-alpine3.12

解説

なぜ/tmpにvolumeをマウントさせるのかを説明します。
opcacheは共有メモリにキャッシュするためにロックファイルが必要です。
zend_shared_alloc_create_lock関数内で、mkstempをコールして/tmpにロックファイルを作成します。
作成失敗の場合は、Unable to create lock fileというエラーメッセージを出力後に異常終了します。

ロックファイルの作成関数
void zend_shared_alloc_create_lock(char *lockfile_path)
{
    int val;

#ifdef ZTS
    zts_lock = tsrm_mutex_alloc();
#endif

    snprintf(lockfile_name, sizeof(lockfile_name), "%s/%sXXXXXX", lockfile_path, SEM_FILENAME_PREFIX);
    lock_file = mkstemp(lockfile_name);
    fchmod(lock_file, 0666);

    if (lock_file == -1) {
        zend_accel_error(ACCEL_LOG_FATAL, "Unable to create lock file: %s (%d)", strerror(errno), errno);
    }
    val = fcntl(lock_file, F_GETFD, 0);
    val |= FD_CLOEXEC;
    fcntl(lock_file, F_SETFD, val);

    unlink(lockfile_name);
}

zend_shared_alloc_create_lockはzend_shared_alloc_startupからコールされ、実行時設定のlockfile_pathを引数として渡します。

zend_shared_alloc_create_lockの呼び出し元
int zend_shared_alloc_startup(size_t requested_size)
{
/* 省略 */

#ifndef ZEND_WIN32
    zend_shared_alloc_create_lock(ZCG(accel_directives).lockfile_path);
#else
    zend_shared_alloc_create_lock();
#endif

Reference