🔧

WSL2+Docker+VSCode+PHPでXdebugを使用する際のホストにhost.docker.internalは使えない

2021/05/15に公開
1

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ユーザーの環境にのみ適用されて差分にもなりません。

  1. docker-compose.yamlのある階層に移動する
  2. .gitignoreを作成してdocker-compose.override.yamlを設定する
  3. Gitのソース管理にdocker-compose.override.yaml.exampleを追加する
    ※中身は前述のdocker-compose.override.yamlと同じ
  4. Linuxユーザーのみcp docker-compose.override.yaml.example docker-compose.override.yamlでローカルに複製する
    docker-compose.override.yamlというファイル名の場合のみdocker-compose upした時に自動で適用される仕様を使っています

.envに環境変数DOCKER_HOST_IPを追加する

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

既に.envDOCKER_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が使えるようになります。

GitHubで編集を提案

Discussion

nozominozomi

最近のアップデートでhost.docker.internalが自動的に名前解決されるようになったため、この記事の対応は不要となりました。

Linux環境だとこの記事の対応が必要で大変助かりました。
ありがとうございます。