WSL2+Docker+VSCode+PHPでXdebugを使用する際のホストにhost.docker.internalは使えない
2021.09.22 追記
最近のアップデートでhost.docker.internalが自動的に名前解決されるようになったため、この記事の対応は不要となりました。
前提
Tool | Verison |
---|---|
Docker | 20.10.6 |
docker-compose | 1.29.1 |
PHP | 7.4.15 |
Xdebug | 3.0.4 |
私に起きたこと
今まで Docker for Windows を用いてローカル環境での開発を行ってきて、少し前からWSL2を用いた Windows Hyper-V 上の Ubuntu 20.04 に移行しました。
するといままで使えていたXdebugが使えなくなりました。
デバッグモードにしても下記のエラーにしかならない…
FastCGI sent in stderr: "PHP message: Xdebug: [Step Debug] Time-out connecting to debugging client, waited: 200 ms. Tried: host.docker.internal
タイムアウトになっているのでXdebugが設定されて動いているのは間違い無さそうですが、VSCodeのデバッガーにアクセスは出来て無さそうです。
何が原因か
Xdebugを設定する場合、こんな設定をすると思います。
xdebug.log=/tmp/xdebug.log
xdebug.mode=debug
xdebug.start_with_request=yes
xdebug.client_host=host.docker.internal
xdebug.client_port=9001
このhost.docker.internal
というホスト名の指定が原因でした。
このホスト名でホストマシン側で動いているVSCodeのデバッガーに通信しにいくわけですが、Dockerの仕様でWindowsまたはmacOSでしか名前解決してくれないようです。
WSLはWindowsの機能ですが、結局動いているのはLinux(今回はUbuntu)上なので使えません!
解決策
直接ホストマシンであるLinuxのローカルIPアドレスを指定すればOKです。
IPの取得
ホストマシンのLinuxで下記を実行する。
$ hostname -I
172.25.14.252 # 実行した環境によるのでこの値はサンプルです
IPの指定
xdebug.client_host
を下記の通り置き換えるだけです。
xdebug.log=/tmp/xdebug.log
xdebug.mode=debug
xdebug.start_with_request=yes
xdebug.client_host=172.25.14.252 # 取得したローカルIPアドレス
xdebug.client_port=9001
Windows・macOS・Linux すべてで使える環境設定にする
私の場合は開発メンバーがどのOSで開発するか統一されていないプロジェクトだったので、下記のようにどのOSでも対応できるようにしました。
ホスト名
host.docker.internal
にします。
xdebug.log=/tmp/xdebug.log
xdebug.mode=debug
xdebug.start_with_request=yes
xdebug.client_host=host.docker.internal
xdebug.client_port=9001
Windows or macOS で使用する
WindowsユーザーとmacOSユーザーは、これまで通り普通にDockerを起動すれば使えます。
Linux で使用する
docker-compose.override.yamlを追加する
私の場合はdocker-composeを使用していたのでdocker-compose.yaml
を上書きするdocker-compose.override.yaml
を追加します。
version: "3" # docker-compose.yamlの値に合わせる
services:
php: # docker-compose.yamlの適用したいコンテナの名称に合わせる
extra_hosts:
- "host.docker.internal:${DOCKER_HOST_IP}" # 変数にして.envファイルで設定する
Gitのソース管理外にする場合
このままだとGitで差分が出てしまいます。
その場合は下記のようにするとLinuxユーザーの環境にのみ適用されて差分にもなりません。
-
docker-compose.yaml
のある階層に移動する - .gitignoreを作成して
docker-compose.override.yaml
を設定する - Gitのソース管理に
docker-compose.override.yaml.example
を追加する
※中身は前述のdocker-compose.override.yaml
と同じ - Linuxユーザーのみ
cp docker-compose.override.yaml.example docker-compose.override.yaml
でローカルに複製する
※docker-compose.override.yaml
というファイル名の場合のみdocker-compose up
した時に自動で適用される仕様を使っています
DOCKER_HOST_IP
を追加する
.envに環境変数docker-compose.override.yaml
と同じ階層に.env
を作成してDOCKER_HOST_IP=ホストマシンのIPアドレス
を記述しておきます。
DOCKER_HOST_IP=172.25.14.252
私は下記のシェルスクリプトを作成して、Linuxユーザーの場合は実行するだけでIPを取得して.env
に追記するようにしました。
#!/bin/bash
# ホストマシンのローカルIPアドレスを取得してdocker-composeの環境変数へ追加する
ip=$(hostname -I)
echo "DOCKER_HOST_IP=${ip[0]% }" >> .env
exit 0
既に.env
にDOCKER_HOST_IP=
が記述されている場合のシェルスクリプト
#!/bin/bash
# ホストマシンのローカルIPアドレスを取得してdocker-composeの環境変数へ追加する
ip=$(hostname -I)
sed -i -e "/^DOCKER_HOST_IP=/s/DOCKER_HOST_IP=.*/DOCKER_HOST_IP=${ip[0]% }/g" .env
exit 0
適用して起動する
あとは普通にdocker-compose up
などで起動すればhost.docker.internal
にホストマシンのローカルIPアドレスが適用されてXdebugが使えるようになります。
Discussion
Linux環境だとこの記事の対応が必要で大変助かりました。
ありがとうございます。