Help us understand the problem. What is going on with this article?

Vagrant(+Docker) 上のPHPアプリをデバッグ実行する

More than 1 year has passed since last update.

:worried: デバッガが反応しないんだけど..

仮想環境で開発をしていると、間に挟まるレイヤーのせいで悩まされることが度々あります。
例えば、ホスト側でIDEを実行し、ゲスト側で開発対象のアプリを起動しているような場合、デバッグ実行をするためには適切な設定が必要になります。
ゲストOSからは、デバッガがリモートホストで実行されているように見えるからです。
ここでは、ゲストOSでPHPを実行して、ホストOS上のデバッガでデバッグする方法を紹介します。

想定環境

Vagrant でゲストOSを起動し、ゲストOS上のDockerコンテナでPHPアプリを実行します (Dockerを使わず、ゲストOS上で直接PHPを実行する場合でも、下記の方法でデバッグ実行できるようになるはずです)。

Vagrant のプロバイダには、VirtualBox を使います。
VirtualBox 限定の設定を使うので、他のプロバイダでは他の方法が必要なります。ごめんなさい。

バージョン
macOS 10.13.6
Vagrant 2.1.2
VirtualBox 5.2.16
PHP 7.2.9
Xdebug 2.6.1

デバッガとしては、PHP Debug 拡張をインストールした Visual Studio Code (以下 VS Code) を使いました。

バージョン
VS Code 1.26.1
PHP Debug 1.12.4

Xdebugによるデバッグの仕組み

PHPアプリのデバッグ実行には、Xdebug というPHP拡張を利用します。
Xdebug

PHP ランタイムに組み込まれたXdebugとデバッガが通信することにより、リモートデバッグが実行されます。
PHPアプリとデバッガを両方ともホストOSで起動していれば、特別な設定をしなくても通信が成立して問題なくデバッグできます。
img1.png

PHPアプリをゲストOSで実行する場合、通信先のデバッガが localhost にないので、通信に失敗します。
img2.png

解決策

要するに、XdebugがホストOSのデバッガと通信できるよう、Xdebugを設定すればいいわけです。
方法は2つあります。

:neutral_face: 方法1: xdebug.remote_connect_back を有効にする

Xdebug の設定ファイル (xdebug.ini) で、xdebug.remote_connect_back を有効にします。

xdebug.default_enable = 1
xdebug.remote_autostart = 1
xdebug.remote_connect_back = 1 # <- ここ
xdebug.remote_enable = 1
xdebug.remote_port = 9000

これは、PHPにHTTPリクエストが届いたときに接続元のホストを取得して、Xdebugからそのホストに対して通信を行う設定です。
$_SERVER['HTTP_X_FORWARDED_FOR']$_SERVER['REMOTE_ADDR']から接続元のホストを判定します。
PHPが受け取るHTTPリクエストの通信元は、VirtualBoxのNATアダプタによって変換されていますが、このIPアドレスに対して通信を行うことで、デバッグセッションが成立します。
img3.png

ブラウザからのリクエストをトリガーにしてデバッグする場合はこの設定でOKです。
ただし、CLIなど別の方法で起動したPHPに対しては、この方法ではデバッグを実行することができません。例えば、PHPUnitでユニットテストをするケースなどが該当します。

ブラウザからのリクエストとコマンド実行の両方で、デバッグ実行をしたい場合は、この方法は適しません。
次に説明する方法2の設定を選んで下さい。

:grinning: 方法2: xdebug.remote_host に、10.0.2.2 を指定する

Xdebug の設定ファイル (xdebug.ini) の xdebug.remote_host で、通信先のホストを明示的に指定します。

xdebug.default_enable = 1
xdebug.remote_autostart = 1
xdebug.remote_connect_back = 0 # 無効にする
xdebug.remote_enable = 1
xdebug.remote_host = "10.0.2.2" # <- ここ
xdebug.remote_port = 9000

10.0.2.2 はVirtualBox の NAT アダプターのゲートウェイアドレスです。
Fine-tuning the VirtualBox NAT engine

img4.png

この設定により、Xdebugは常にホスト上のデバッガと通信するようになります (ブラウザからのリクエストとコマンド実行の両方)。
VagrantでDockerを起動して、コンテナ内で PHP を実行する場合でも、この方法でデバッガと通信できます。

デバッガの設定

xdebug.iniの設定で、Xdebugとデバッガは通信できるようになりました。
さらに、仮想環境とホスト側とファイルのパスをマッピングすることで、VS Codeで設定したブレークポイントが有効になります。
例えば、PHPサーバー側(ゲストOS)の /var/wwwを、VS Codeのワークスペースのwwwディレクトリにマッピングするには、.vscode/launch.json を次のように設定します。

{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "Listen for XDebug",
            "type": "php",
            "request": "launch",
            "port": 9000,
            "log": true,
            "pathMappings": {
                "/var/www": "${workspaceRoot}/www"
            }
        },
        ...
    ]
}

補足

Xdebugとデバッガとの通信は、Xdebug(ゲストOS)からデバッガ (ホストOS) に対して送信されるので、ポートフォワーディングなどの設定は必要ありません。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした