PHP 7.3.1 + Xdebug 2.7.0beta1 + opcache で 502 Bad Gateway, exited on signal 11 (SIGSEGV) となる原因と対処方法

## 原因と対応方法

昨日(2019-01-24)時点で、最新の `php 7.3.1` を用いて、 `xdebug` と `opcache` を組み合わせて開発環境を作ろうとした、 `502 Bad Gateway` がたまに発生し、 phpfpm のログを確認すると `exited on signal 11 (SIGSEGV)` が発生していた。

さて、どう対応するかな…と Twitter でつぶやいたところ、 [Derick Rethans](https://twitter.com/derickr) san から mention を頂いた！

<blockquote class="twitter-tweet" data-lang="ja"><p lang="en" dir="ltr">There is a bug in OPcache that conflicts with Xdebug (and causes crashes). This is fixed in GIT, and will be released as part of PHP 7.3.2.</p>&mdash; Derick Rethans (@derickr) <a href="https://twitter.com/derickr/status/1088472138347171840?ref_src=twsrc%5Etfw">2019年1月24日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

続けて、原因と回避策まで！
<blockquote class="twitter-tweet" data-lang="ja"><p lang="en" dir="ltr"><a href="https://t.co/kwVyr00BR7">https://t.co/kwVyr00BR7</a> is the bug, and <a href="https://t.co/YeZZ5U8dTL">https://t.co/YeZZ5U8dTL</a> has a workaround</p>&mdash; Derick Rethans (@derickr) <a href="https://twitter.com/derickr/status/1088472235101294592?ref_src=twsrc%5Etfw">2019年1月24日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

[Derick Rethans](https://twitter.com/derickr) san. Thank you for the information!

というわけで、上記に書かれていることを実行すればとりあえず大丈夫です。

`php 7.3.2` になったら、 https://github.com/php/php-src/commit/325a1139744413420a62d3006c04914587628810 が反映されるので、この問題は生じなくなると思いますよ。

## もうちょっと細かく経緯と対応方法

昨日(2019-01-24)時点の Docker hub 上の `php:7.3-fpm-alpine3.8` をベースに `PHP 7.3 + xdebug + opcache` の開発環境を作ろうとした。

とりあえず、以下のような `Dockerfile` を用意して、 `docker-compose build` して `docker-compose up` してみた。


```Dockerfile
FROM php:7.3-fpm-alpine3.8

RUN apk update \
  && apk upgrade \
  && apk add --no-cache --virtual .gd-deps \
      g++ \
      make \
      autoconf \
  && pecl update-channels \
  && docker-php-ext-install \
      opcache \
  && pecl install xdebug-2.7.0beta1 \
  && rm -rf /tmp/pear ~/.pearrc \
  && docker-php-ext-enable xdebug
# ホントはもっと色々書いてるのですが省略しました。
```

※ **2019-01-28 追記** @tomoyamachi さんの[コメント](https://qiita.com/hokutoasari/items/4db320e519d87186974f#comment-db43efbd6e15c23af9e0) を参考に `echo 'zend_extension=xdebug.so' >  /usr/local/etc/php/conf.d/xdebug.ini` から `docker-php-ext-enable xdebug` に変更。

なお、 php 7.3 で xdebug を使うには、現状 `xdebug-2.7.0beta1` を pecl から install する必要がある。(https://xdebug.org/ の Announcements や https://xdebug.org/updates.php 等を参照のこと: 最初は普通に `pecl install xdebug` って書いててダメだった。ちゃんとドキュメント見るべき…)

※ phpfpm の前に nginx がいる構成なのですが、 nginx 用の Dockerfile は省略してます。

build も up も成功した！

で、ブラウザから、見てみるとどうやら動いてるっぽい！

と、思ったのもつかの間…

設定値が正しく反映されているか `phpinfo()` で、ざっと目視確認しようとファイルを書き換えてリロードしたところ、`502 Bad Gateway`! phpfpm が出力している stderr には `exited on signal 11 (SIGSEGV)`!

え？

再度リロード。

…

普通に表示される。。。え？

再度リード。。

`502 Bad Gateway`! `exited on signal 11 (SIGSEGV)`! えぇぇ！！！！

(試しにその後も何度かリロードしたら再現したりしなかったりを繰り返した。)

となって、あーこれ core dump かよ。。 docker で core dump かよー。。

でも、タイミング次第ってことは多分、 opcache かなぁ。

というわけで、とりあえず、 opcache を Off にしてみることに。

```bash
$ docker-compose exec phpfpm sh
/var/www/app # vi /usr/local/etc/php/conf.d/docker-php-ext-opcache.ini
;zend_extension=/usr/local/lib/php/extensions/no-debug-non-zts-20180731/opcache.so
/var/www/app # kill -USR2 1
```

`docker-compose exec` で稼働中の phpfpm コンテナに入って、 sh を起動し、

対象のファイルを `;zend_extension=(略)` の様にコメントアウトして、

`kill -USR2 1` にて、container 内から phpfpm を再起動。  https://stackoverflow.com/questions/37806188/how-to-restart-php-fpm-inside-a-docker-container

で、ブラウザからリロード確認すると、、

見事に `502 Bad Gateway` と `exited on signal 11 (SIGSEGV)` が消えてなくなりました。

ここで、とりあえず opcache が怪しそうだな、とアタリをつけたのですが、 xdebug も気になります。

特に php 7.3 はリリースしてから日が浅く、 7.3 用の xdebug である 2.7.0beta1 は名前が指し通り、まだ beta 版。

もしかしたら、こっちも怪しいかも？と思い、さっきと逆の手順で opcache を有効にした後、以下の手順で xdebug を無効にしてみました。

```bash
/var/www/app # vi /usr/local/etc/php/conf.d/xdebug.ini
;zend_extension=xdebug.so
/var/www/app # kill -USR2 1
```

で、こちらも見事に `502 Bad Gateway` と `exited on signal 11 (SIGSEGV)` が消えてなくなりました。

ということで、 `opcache` + `Xdebug 2.7.0beta1` + `php:7.3-fpm-alpine3.8` の組み合わせによって何らかのバグを踏んでいる可能性が高そうだと考えました。

※(`opcache` or `xdebug`) + `php:7.3-fpm-alpine3.8` なら問題ない。

で、冒頭の Tweet をしたところ、サクッと [Derick Rethans](https://twitter.com/derickr) san から mention を頂いた次第です。

ありがたい。

その後、 `php:7.3-fpm-alpine3.8` の今の php version を確認すべく以下のコマンドで 7.3.1 であることを確認し、

```bash
$ docker-compose exec phpfpm php -v
PHP 7.3.1 (cli) (built: Jan 11 2019 00:59:32) ( NTS )
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.3.1, Copyright (c) 1998-2018 Zend Technologies
    with Zend OPcache v7.3.1, Copyright (c) 1999-2018, by Zend Technologies
    with Xdebug v2.7.0beta1, Copyright (c) 2002-2018, by Derick Rethans
```

教えていただいた workaround に従い Dockerfile に `opcache.optimization_level=0x7FFFBBFF` を追加しました。

```Dockerfile
FROM php:7.3-fpm-alpine3.8

RUN apk update \
  && apk upgrade \
  && apk add --no-cache --virtual .gd-deps \
      g++ \
      make \
      autoconf \
  && pecl update-channels \
  && docker-php-ext-install \
      opcache \
  && pecl install xdebug-2.7.0beta1 \
  && rm -rf /tmp/pear ~/.pearrc \
  && docker-php-ext-enable xdebug \
  && echo 'opcache.optimization_level=0x7FFFBBFF' >> /usr/local/etc/php/conf.d/opcache.ini
```

※ **2019-01-28 追記** @tomoyamachi さんの[コメント](https://qiita.com/hokutoasari/items/4db320e519d87186974f#comment-db43efbd6e15c23af9e0) を参考に `echo 'zend_extension=xdebug.so' >  /usr/local/etc/php/conf.d/xdebug.ini` から `docker-php-ext-enable xdebug` に変更。

で、 `docker-compose build`, `docker-compose up` したところ、見事正常に動作するようになりました！

めでたしめでたし。

※ **2019-01-28 追記**

もともと、 `echo 'opcache.optimization_level=0x7FFFBBFF' >> /usr/local/lib/php/extensions/no-debug-non-zts-20180731/opcache.so` などという、わけのわからない事を書いていました…正しくは、 `/usr/local/etc/php/conf.d/` の下に .ini です。。
`echo 'opcache.optimization_level=0x7FFFBBFF' >> /usr/local/etc/php/conf.d/opcache.ini` してる部分、もしかしたら、 `/usr/local/etc/php/conf.d/docker-php-ext-opcache.ini` に追記の方が作法的には良いかも知れません。
あるいは、自前で用意した .ini であることを明示したファイル名とか。

### ~~ところで…~~

~~`php7.3 docker` でググると @tomoyamachi さんの https://qiita.com/tomoyamachi/items/991a0d149e9585cac15f という記事が見つかりますが、これも php7.3 + xdebug + opcache なはずなのですが…どうやら正常に動いてるっぽい？~~

~~おそらく上記記事を書かれたときは php 7.3.0 かと思うのですが、 https://bugs.php.net/bug.php?id=77287 の Bug は php 7.3.0 でも発生するっぽい気が。。。(流し読みしただけなので、間違ってたらスミマセン！)~~

~~あるいは https://github.com/tomoyamachi/docker-laravel-fpm-7.3/blob/2f65eb12a6215759c62180585142a4d90bafec91/Dockerfile#L26 にて、 xdebug.so を読み込まないようにコメントアウトしてるから発症しなかった？~~

~~ちょっと後で時間がある時に https://github.com/tomoyamachi/docker-laravel-fpm-7.3 をお借りして手元でも試して見ようと思ってます。~~

※ **2019-01-28 追記** [コメント](https://qiita.com/hokutoasari/items/4db320e519d87186974f#comment-e9c68709f5b8a87532c4)にて、再現性があったとのことなので、上記に打ち消し線を追加しました。また、自分が `echo 'zend_extension=xdebug.so' >  /usr/local/etc/php/conf.d/xdebug.ini` という手抜きな書き方をしていたせいで、 `docker-php-ext-enable xdebug` にて、有効になっていることをすっかり見落としてました…大変失礼しました！:sob: