🐘

WSL2のみで動くDockerでxdebugを使ったリモートデバッグができない問題の解決

2021/10/18に公開

みなさんこんにちは。
最近WSL2とDocker Engineの組み合わせでコンテナ内にあるPHPアプリのリモートデバッグができない問題に突き当たりました。
今回の記事ではこの問題を解決して、xdebugで再び快適なPHP開発ができるようにする方法を解説します。

前提条件

この記事は以下の前提条件で検証されました。

  • Windows 10
  • WSL2 Ubuntu 20.04
  • Docker Engine 20.10.8
  • PHP 7.3.3
  • xdebug 3.1.0
  • Visual Studio Code 1.60.1
    • Remote - WSL拡張機能を使った開発

1. xdebugのサーバー側設定を修正

php.iniにあるxdebugの設定項目xdebug.client_hosthost.docker.internalになっていることを確認しましょう。
既に設定済みの場合はこの手順を飛ばしてください。

  1. php.iniを開きます。
    • php.iniの場所を忘れた場合はphp -iniコマンドで見つけられます。
  2. xdebug.client_host(xdebug 2.xの人はxdebug.remote_host)をhost.docker.internalに設定します。
 [xdebug]
 xdebug.mode=debug
 xdebug.start_with_request=yes
+xdebug.client_host=host.docker.internal
 xdebug.discover_client_host=false
 xdebug.log=/tmp/xdebug.log
 xdebug.client_port=9000

2. docker-compose.ymlの修正

  1. デバッグ対象のPHPアプリのコンテナ定義が記述されているdocker-compose.ymlを開きます。
  2. そしてymlの内容を下記のように修正します。
services:
    hoge:
        image: php_app
+       extra_hosts:
+           - "host.docker.internal:host-gateway"
  1. docker-compose up -dなどのコマンドでサービス群を立ち上げ直します。

docker側の設定は以上で終了です。

3. xdebugのクライアント側設定を修正

  1. Visual Studio Codeでxdebugを使ってリモートデバッグをしたいプロジェクトを開きます。
  2. launch.jsonを開き下記のように修正します。
 {
   "version": "0.2.0",
   "configurations": [
     {
       "name": "Listen for XDebug",
       "type": "php",
       "request": "launch",
-      "hostname": "localhost",
+      "hostname": "0.0.0.0",
       "port": 9000
     }
   ]
 }

PHPStormを使ったリモートデバッグ設定のやり方はmicronn氏の
https://zenn.dev/micronn/articles/5f3cd1d94f99fd
が参考になります。

これでリモートデバッグができるようになりました。
お疲れ様でした。

裏話:Docker Engineにおけるhost.docker.internalの扱い

Docker Desktopでは自動設定されていたhost.docker.internalですが、Linux上のDocker Engineでは自動設定されません。
Docker Engineのrelease noteには

Support host.docker.internal in dockerd on Linux moby/moby#40007

と書かれているため 「host.docker.internalが自動設定される」と認識しそうになりますが違います。

release noteにリンクのあるプルリクエストに

This PR allows containers to connect to Linux hosts
by appending a special string "host-gateway" to --add-host
e.g. "--add-host=host.docker.internal:host-gateway" which adds
host.docker.internal DNS entry in /etc/hosts and maps it to host-gateway-ip

と書かれていることから、自動設定がサポートされたのではなく 「host.docker.internalを明示的に特殊な文字列(host-gateway)で設定できるようになった。」 というのが詳細のようです。

Discussion