Xdebug+Ubuntu+Docker+PHP-FPM+VSCodeでステップデバッグしたい
課題
PHP-FPMのDocker containerにXdebug3.1をインストールしたい。
Xdebug3.1でステップデバッグしたい。
VSCodeでXdebugを動かしたい。
環境
OS:Ubuntu20.04 LTS
PHP-FPMとNginxのDocker containerをDocker Composeで動かしています。
記事のターゲット
Ubuntu+Docker+PHP-FPM+VSCode環境下で、Xdebug3系でステップデバッグしたい人に向けた記事です。
Docker+PHP-FPM+VSCodeでの環境構築などは既に出来ている人を対象にしています。
また、Xdebugでリモートデバッグすることを理解している人を対象にしています。DockerでXdebugを使うことはリモートデバッグをすることなので。リモートデバッグのイメージ自体がよく分からない人は、この記事がおすすめです。Xdebug2系の記事なので設定項目は違いますが、とても分かりやすいです。
解決策
実際のプログラム例とともに以下説明します。
Dockerfile
FROM php:8.1-fpm
# PECLでx-debugのインストールする。
RUN pecl install xdebug
PECLを用いて、PHP-FPMコンテナにXdebugをインストールしています。
PECLとは
PECLとは、PHPの拡張モジュールのリポジトリです。
apt-get install php-xdebug
を用いない理由
Xdebugの公式ドキュメントではDebian系はapt-get install php-xdebug
でインストールするように案内されています。しかし、このベースイメージでapt-get install php-xdebug
を実行するとエラーが出ます。PHP-FPM8.1のコンテナはDebian11のスリム版をベースイメージに作られていることが原因かと思います。だから、PECLを用いてインストールしています。
docker-php-ext-enable xdebug
を実行しない理由
pecl install xdebug
の実行後に、docker-php-ext-enable xdebug
を実行することを紹介している記事もあると思います。docker-php-ext-enable xdebug
は/usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini
を作成するだけのコマンドです。docker-php-ext-xdebug.ini
をコンテナにバインドマウントしたい人には不要です。この記事ではdocker-php-ext-xdebug.ini
をカスタマイズしてバインドマウントするので、docker-php-ext-enable xdebug
を実行しません。
docker-compose.yml
version: '3.8'
services:
php:
build:
context: ./
dockerfile: Dockerfile
image: your-image:latest
container_name: your-container
# コンテナの属するネットワークを設定
networks:
your-network:
ipv4_address: 172.18.0.2
volumes:
# Xdebugの設定ファイルをマウント
- type: bind
source: ./docker-php-ext-xdebug.ini
target: /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini
# ネットワークの定義
networks:
your-network:
name: your-network
driver: bridge
ipam:
config:
- subnet: 172.18.0.0/16
gateway: 172.18.0.1
例として、docker-compose.ymlを長々と書きました。
が、この中で重要なのは以下の2点です。
Xdebugの設定ファイルのマウント
docker-php-ext-xdebug.ini
はXdebugの設定ファイルです。
この設定ファイルを/usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini
にバインドマウントして下さい。
docker-php-ext-xdebug.ini
の詳細については後述します。
ネットワークの定義
コンテナとホストコンピューターの間でのリモートデバッグでは、それぞれの住所であるプライベートIPアドレスが重要になります。
ホストコンピューターとPHPコンテナそれぞれにプライベートIPアドレスを定義して下さい。
空いているプライベートIPアドレスであればなんでもいいです。
今回の例では、172.18.0.0/16でネットワークを定義しています。ホストコンピューターには、172.18.0.1を割り当てています。また、PHP-FPMコンテナには、172.18.0.2を割り当てています。
docker-php-ext-xdebug.ini
zend_extension=xdebug
xdebug.mode=debug
xdebug.start_with_request=yes
xdebug.client_host=172.18.0.1
;xdebug.discover_client_host=1
xdebug.client_port=9003
docker-php-ext-xdebug.ini
はXdebugの設定ファイルです。
以下に設定項目の解説を書きます。
zend_extension
zend_extension
はXdebugの実行ファイルのパスの設定項目です。zend_extension=xdebug
がデフォルトですが、上手くいかなかったら変えてみて下さい。
xdebug.mode
xdebug.mode
はXdebugのどの機能を使うかの設定項目です。ステップデバッグだけを使いたい場合は、xdebug.mode=debug
を指定します。var_dump
の機能だけを使いたい時はxdebug.mode=develop
と指定します。複数の機能を使いたい時は、カンマ区切りで指定します。全部の機能を使いたい時は、xdebug.mode=develop,coverage,debug,gcstats,profile,trace
です。
xdebug.start_with_request
xdebug.start_with_request
は、どんなときにXdebugが作動するかの設定項目です。PHPが実行される時はいつでも実行したいので、xdebug.start_with_request=yes
を設定します。
xdebug.client_host
xdebug.client_host
は、docker containerから見たホストコンピューターのプライベートIPアドレスを指定します。
この記事の例の場合は、docker-compose.ymlで定義したgatewayのアドレスの172.18.0.1です。
xdebug.discover_client_host
xdebug.discover_client_host
は、ホストコンピューターのプライベートIPアドレスを自動で検索してくれる設定項目です。xdebug.discover_client_host=1
で自動的に検索してくれます。
xdebug.client_host
とxdebug.discover_client_host
はどちらか一方だけを設定すれば良いです。どちらも設定した場合は知りません。
この例では、xdebug.client_host
を設定しているのでxdebug.discover_client_host
はコメントアウトしていますが、好きな方を使って下さい。
xdebug.client_port
ホストコンピューターが通信に使うportを指定します。デフォルト通りにxdebug.client_port=9003
を指定したら良いと思います。
PHP Debug
PHP Debugは、VSCodeでXdebugを実行する為の拡張機能です。
PHP Debugの設定方法
VSCodeの拡張機能からPHP Debugをインストールして下さい。
VSCodeの左端の『実行とデバッグ』をクリックし、『create a launch.json file』をクリックし、『PHP』を選んで下さい。
launch.jsonを下記のように編集して下さい。
{
"version": "0.2.0",
"configurations": [
{
"name": "Listen for Xdebug",
"type": "php",
"request": "launch",
"port": docker-php-ext-xdebug.iniで設定したポート,
"pathMappings": {
"/コンテナのディレクトリ": "${workspaceRoot}/ホストのディレクトリ"
}
},
]
}
重要なのは、portとpathMappingsです。
portには、docker-php-ext-xdebug.iniで設定したportを指定して下さい。今回の例だと、9003です。
pathMappingsでは、ホストコンピューターのディレクトリとコンテナのディレクトリの対応関係を定義します。ホストとコンテナの対応するパスを書いて下さい。
Firewall
コンテナとホストコンピュータで通信が行われるので、Firewallで通信を許可してください。コンテナからホストコンピューターへの通信さえ許可すれば良いです。
この例だと、コンテナ(172.18.0.2)からホストコンピューター(172.18.0.1:9003)への通信を許可すれば良いです。
Xdebug自体のログについて
Xdebug自体のログを見るには2種類の方法があります。
Dockerのログ
特別な設定をしなくても、docker logs -f コンテナ名
でエラーログを見ることが出来ます。
私自身もこのログを見ながら作業しました。
ちなみに、私の作業中に出たログは下記の通りです。
NOTICE: PHP message: Xdebug: [Step Debug] Time-out connecting to debugging client, waited: 200 ms. Tried: xxx.xxx.xxx.xxx:9003 (through xdebug.client_host/xdebug.client_port) :-(
xxx.xxx.xxx.xxx - 10/Mar/2022:06:57:25 +0000 "GET /index.php" 200
通信が出来ずにタイムアウトしていますね、、、
Firewallで通信を遮断していたことが原因でした、、、
Xdebugのログ
Dockerfileとdocker-php-ext-xdebug.iniに下記の行を加えると、コンテナ内にXdebug固有のログを出力出来ます。
# xdebugのログファイルを作成する
RUN touch /var/log/xdebug.log && chmod a+w /var/log/xdebug.log
xdebug.log=/var/log/xdebug.log
Xdebugのログでは、上記で紹介した私の作業中のログは下記のようになります。
[125] [Step Debug] INFO: Connecting to configured address/port: xxx.xxx.xxx.xxx:9003.
[125] [Step Debug] ERR: Time-out connecting to debugging client, waited: 200 ms. Tried: xxx.xxx.xxx.xxx:9003 (through xdebug.client_host/xdebug.client_port) :-(
最後に
久々にXdebugを使うことになって、若干設定に苦戦しました。
昔はXdebug2系をVagrantでVirtual BoxにいれてEclipseでデバッグしていたので、、、
良い開発ライフを!
Discussion