Debug your PHP applications running on docker with vscode
21 Feb 2018Introduction
Setting up debugging tools in a docker environment is rarely as easy as it should. Here is a short tutorial to get it done in PHP with the Xdebug extension. If you are in a hurry you can quickly get all files used in this tutorial from this github repository.
Setting up the php application running on docker
A prerequisite to this tutorial is to have a PHP application running on docker. If it’s already set up feel free to skip this section. For the sake of simplicity I will place all files directly in the project root directory. Obviously I would advise against this and you should rather tidy things up in a folder containing all docker related files.
This recipe will contain:
- A
docker-compose.yml
file for our web server running php along with nginx:
version: '3.7'
services:
php_app:
build:
context: .
dockerfile: Dockerfile-php-app
volumes:
- ./:/var/www/html
nginx_app:
image: nginx:1.18.0-alpine
ports:
- 8080:80
volumes:
- ./:/var/www/html
- ./app.conf:/etc/nginx/conf.d/default.conf:ro
depends_on:
- php_app
- The corresponding Dockerfile
I named it Dockerfile-php-app
to make it explicit it’s for the PHP image and not the nginx one.
FROM php:7.4-fpm-alpine
# php configuration
COPY php.ini /usr/local/etc/php/
- Along with a
php.ini
file
Its content does not matter at the moment but the file is required as we will need to append the Xdebug configuration later on.
[PHP]
;;;;;;;;;;;;;;;;;;;
; About php.ini ;
;;;;;;;;;;;;;;;;;;;
; PHP's initialization file, generally called php.ini, is responsible for
; configuring many of the aspects of PHP's behavior.
error_reporting = E_ALL;
log_errors = On;
display_errors = On;
error_log = /dev/stderr;
- Then the nginx configuration to render our php
The file name is app.conf
as referenced in the docker-compose file.
server {
root /var/www/html;
access_log /dev/stdout;
error_log /dev/stderr;
charset utf-8;
location / {
# try to serve file directly, fallback to index.php
try_files $uri /index.php$is_args$args;
}
location ~ ^/index.php(/|$) {
fastcgi_pass php_app:9000;
fastcgi_split_path_info ^(.+\.php)(/.*)$;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
}
- Finally a dummy
index.php
file with a few instructions will do:
<p>Let's do some math.</p>
<ul>
<?php
for ($i = 0; $i < 10; $i++) {
echo sprintf("<li>%s * 5 = %s</li>", $i, $i*5);
}
?>
</ul>
Run docker-compose up -d
and browse http://localhost:8080/. You should be good to go.
Setting up Xdebug with vscode
The first thing we need to do is to update our docker image to include Xdebug. Let’s add these 3 lines to Dockerfile-php-app
:
...
# Xdebug configuration
RUN apk add --no-cache $PHPIZE_DEPS # dependencies needed by pecl
RUN pecl install xdebug && docker-php-ext-enable xdebug
Then let’s touch our php.ini file by appending the xdebug configuration:
;xdebug configuration
xdebug.remote_enable = 1
xdebug.remote_port = 9099
xdebug.remote_autostart = 1
xdebug.remote_connect_back = 0
xdebug.remote_host = 192.168.0.30
Run docker-compose build
to get the latest version of your image.
Set the remote host to whatever your internal network IP is. On my ubuntu laptop, running hostname -I | awk '{print $1}'
on the command line prints it.
Run docker-compose up -d
a second time.
Last but not least, you will have to update your vscode configuration. First install the PHP Debug extension by Felix Becker. Then in vscode select the debug
tab, then click Add Configuration..
and select the PHP
environment. This will open the launch.json
file. Erase its content with the following:
{
"version": "0.2.0",
"configurations": [
{
"name": "Listen for XDebug",
"type": "php",
"request": "launch",
"port": 9099,
"pathMappings": {
"/var/www/html/": "${workspaceRoot}"
}
}
]
}
Add a breakpoint in index.php
and hit Listen for XDebug. Browse http://localhost:8080/. Vscode should pop and the code will be at your breakpoint! Make sure vscode is opened for the directory containing all these files but not a parent directory. Else the relative path will be wrong and vscode won’t budge.
Known issues
According to the Xdebug documentation, Xdebug will still not start a debugging session automatically when a script is run. I did not myself experience any issue. A good way to test is to launch the debugger, then run the following:
$ docker-compose exec php_app php index.php
If nothing happens, update the php_app service in the docker-compose.yml
file by adding an environment variable:
services:
php:
...
environment:
XDEBUG_CONFIG: idekey=session_name
Run these commands once again to check if everything is fine:
$ docker-compose up -d
$ docker-compose exec php_app php index.php
Multiple PHP containers
What if your application is composed of multiple PHP backends? In this case you will need to have them running in other docker containers, and the xdebug port (9099 for now) will conflict. A solution to this problem is to make good use of the Dockerfile ARG instruction.
This is what you get with 2 different php docker images and 2 docker-compose service accordingly:
- Here is the
docker-compose.yml
file
version: '3.7'
services:
php_app_1:
build:
context: .
dockerfile: Dockerfile-php-app
args:
XDEBUG_PORT: 9042
volumes:
- ./:/var/www/html
php_app_2:
build:
context: .
dockerfile: Dockerfile-php-app
args:
XDEBUG_PORT: 9043
volumes:
- ./:/var/www/html
With the following instructions in Dockerfile-php-app, running docker-compose build
will result in different docker images with different Xdebug ports.
...
ARG XDEBUG_PORT
RUN sed -i "s/xdebug.remote_port = 9099/xdebug.remote_port = $XDEBUG_PORT/g" /usr/local/etc/php/php.ini
Eventually, for each of your codebase, change the value of the port in your vscode debugger configuration:
{
"version": "0.2.0",
"configurations": [
{
"name": "Listen for XDebug",
"type": "php",
"request": "launch",
"port": 9043,
"pathMappings": {
"/var/www/html/": "${workspaceRoot}"
}
}
]
}
If you found this tutorial helpful, star this repo as a thank you! ⭐