PHP
PhpStorm
xdebug
docker

Docker for Mac 上のコンテナに対して、PhpStorm + xdebug でリモートデバッグ

PhpStorm + xdebug のリモートデバッグの記事もたくさんあるし、それに Docker を使ったものもちらほらあるんだが、Docker for Mac を使うと微妙に事情が違っていたので、うまくいった方法をまとめとく。

前提

以下のような構成であるとします。

  • Docker for Mac を使って、php のコンテナを立ち上げており、xdebug が利用可能になっている
  • PhpStorm を使っている

必要な手順

以下の手順が必要になる。

  • Mac 上のネットワークインタフェース lo0 に対してエイリアスを追加する
  • xdebug.ini を設定する
  • PhpStormを設定する

(注意) DBGp の設定は必要ない

Mac 上のネットワーク・インタフェース lo0 に対してエイリアスを追加する

以下のコマンドをターミナル等で入力して、エイリアスを追加する。

sudo ifconfig lo0 alias 10.254.254.254

xdebug.ini の設定

Docker image を作る際に以下のファイルを COPY するようにするか、RUNで echo させながら追加する等のことをする。

  • (注意) xdebug.so のパスは使っているディストリビューションによって違うかもしれない。以下のものは CentOS のもの
  • (注意) 以下の設定はリモートデバッグをするのに必要最低限度のものなので、プロファイルを取りたい場合等は適宜 xdebug.profiler_enable 等の設定を追加すること
xdebug.ini
zend_extension=/usr/lib64/php/modules/xdebug.so

xdebug.remote_enable = 1
xdebug.remote_autostart = 1
xdebug.remote_host = 10.254.254.254
xdebug.remote_port = 9000
xdebug.idekey = PHPSTORM

PhpStorm の設定をする

設定する画面は3画面

デバッグポートの設定

  1. PhpStorm メニューの Preferences を開き、 Languages & Frameworks -> PHP -> Debug を選択する。
  2. Xdebug の項目があるので、Debug ポートが 9000 で、「Can accept external connections」がチェックされていることを確認する。

PHP-Debug.png

Server の追加

  1. PhpStorm メニューの Preferences を開き、 Languages & Frameworks -> PHP -> Servers を選択する
  2. 「+」 をクリックし、設定を追加する。
  3. Name は設定名なのでわかりやすいものをつける(Host名と合わせておけばいいと思う)
  4. Host名は /etc/hosts 等で名前解決できるようにしたホスト名を設定。名前解決できるようにしていないならば、127.0.0.1 をいれればいい(なぜこれでいいかは後述。もちろんNameVirtualHost を立てている場合は、IPアドレスの設定ではだめなので /etc/hosts で「127.0.0.1 test.dev」という感じにする必要がある)
  5. Port は Docker 上で公開しているものを設定する。例えば 80:80 で公開しているならば 80 を、8080:80 で公開しているならば 8080 を設定する
  6. Debugger は Xdebug を選択する
  7. Use path mappings のチェックを ON にし、プロジェクト上のディレクトリに対して、Docker 上のディレクトリをマッピングしておく

PHP-Servers.png

Run/Debug の設定を行う

  1. Run メニューの Edit Configurations を選択する
  2. 「+」をクリックし、「PHP Remote Debug」のエントリを追加
  3. Name は設定名なのでわかりやすいものをつける(先程つけた Host名と合わせておけばいいと思う)
  4. Servers のプルダウンで先程設定したものが選択できるようになっていると思うので選択する
  5. Ide Key(session id) には PHPSTORM と入力する

Run-Configurations.png

なぜエイリアスを追加しないといけないのか?

Mac 上でも Docker toolbox を使った場合、エイリアスは追加しなくてもリモートデバッグが可能で、Docker for Mac を使った場合のみエイリアスを追加しないとリモートデバッグができない。

Docker toolbox を使った場合は、ホストである Mac は 192.168.99.1 というIPアドレスが割り振られるため、xdebug.remote_host に素直に 192.168.99.1 を割り振ることができる。

また、Docker toolbox の場合は、各コンテナは toolbox(boot2docker) が立ち上げた Virtualbox の docker-engine 上で動いていて、各コンテナのポートは 192.168.99.100 のポートとして公開される。

しかし、Docker for Mac の場合、toolbox のようなものが介在していないため、各コンテナのポートは Mac のアドレス自身で公開されることになる。つまり参照できるのは、DHCP で配られたIPアドレス、もしくは、localのループバックのみとなる。

その為、Docker for Mac の場合、xdebug.remote_host に設定する適当なものがないという状態になる。(DHCPで変わるかもしれない/開発メンバーごとに違うアドレスを設定するのも面倒だし、127.0.0.1 を設定してもコンテナ側で自分自身でループバックしてしまう)

その為、ホストである Mac 側のループバッグインタフェース lo0 に 10.254.254.254 というエイリアスを作成し、ホスト側からみれば自分自身だし、コンテナから見ると別のIPアドレスというふうにみえるものを追加せざるを得ないということになる。

ちなみに、もう一つ罠があって、xdebug.ini の以下のディレクティブは使ってはいけない。

xdebug.ini
xdebug.remote_connect_back = 1

このディレクティブを設定すると、xdebug.remote_host の設定が「無視」されて、$_SERVER['HTTP_X_FORWARDED_FOR'] もしくは $_SERVER['REMOTE_ADDR'] の値を使って、ホスト側に接続しようとする。

xdebug - remote_connect_back

Docker for Mac の場合、これらの値には、コンテナ自体が所属するネットワークのゲートウェイ(通常は 172.17.0.1)が設定され、それはホストであるMacには「届かない」ので、このディレクティブを設定すると確実に失敗する(これの罠を踏んで痛い目にあいました・・・)

最後に

わかってしまえばそりゃそうだという感じなんだが、Docker For Mac がホスト自身で動いてしまうとうのは手軽ではあるんだが、罠があるなとも思った。

あとついでに書いとくと、追加したエイリアスは以下のコマンドで消せます。

sudo ifconfig lo0 -alias 10.254.254.254