Repository: cultuurnet/udb3-backend
Pull request #2014: Enable xdebug in docker
Author: login: grubolsch
Created: 2025-02-26T15:26:52Z | Merged: 2025-04-04T09:20:28Z

### Added
Another attempt to get Xdebug inside our docker setup, with an optional docker profile, so you can quickly switch between both versions.
All instructions can be found inside the readme file.

This is how it will look inside docker engine.
![Screenshot 2025-02-26 at 16 25 09](https://github.com/user-attachments/assets/b56ebf7b-46e7-425a-99a8-fd3c6bacf886)



Diff:
diff --git a/Makefile b/Makefile
index 989be22c61..2b6da6d902 100644
--- a/Makefile
+++ b/Makefile
@@ -9,6 +9,9 @@ down:
 bash:
 	docker-compose exec php bash
 
+bash-xdebug:
+	docker-compose exec php-xdebug bash
+
 config:
 	sh ./docker/config.sh
 
diff --git a/bin/start-xdebug.sh b/bin/start-xdebug.sh
new file mode 100644
index 0000000000..17c1cdc25a
--- /dev/null
+++ b/bin/start-xdebug.sh
@@ -0,0 +1 @@
+export XDEBUG_MODE=debug XDEBUG_SESSION=1 PHP_IDE_CONFIG="serverName=host.docker.internal"
diff --git a/docker-compose.yml b/docker-compose.yml
index b2b85008cc..2b2f452088 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -1,12 +1,9 @@
 services:
-  php:
+  php-base:
     build: docker/php
-    container_name: php.uitdatabank
     volumes:
       - .:/var/www/html:cached
     working_dir: /var/www/html
-    ports:
-      - '8000:80'
     networks:
       uitdatabank-backend:
         aliases:
@@ -28,6 +25,29 @@ services:
       mailpit:
         condition: service_healthy
 
+  php:
+      container_name: php.uitdatabank
+      extends:
+          service: php-base
+      ports:
+          - '8000:80'
+
+  php-xdebug:
+      container_name: php-xdebug.uitdatabank
+      extends:
+          service: php-base
+      profiles:
+          - xdebug
+      build:
+          context: docker/php
+          args:
+              ENABLE_XDEBUG: "true"
+      environment:
+          XDEBUG_MODE: debug
+          XDEBUG_CONFIG: client_host=host.docker.internal
+      ports:
+          - '8001:80'  # Explicitly override to port 8001
+
   mysql:
     image: 'bitnami/mysql:8.0'
     container_name: mysql.uitdatabank
diff --git a/docker/php/Dockerfile b/docker/php/Dockerfile
index 61ab5bee2f..b3a6f34248 100644
--- a/docker/php/Dockerfile
+++ b/docker/php/Dockerfile
@@ -1,5 +1,7 @@
 FROM php:7.4-apache
 
+ARG ENABLE_XDEBUG
+
 RUN apt-get update && apt-get install -y --no-install-recommends git zip unzip libicu-dev libtidy-dev zlib1g-dev libpng-dev libzip-dev supervisor fontconfig-config fonts-dejavu-core libdeflate0 libfontconfig1 libfreetype6 libgif7 libjbig0 libjpeg62-turbo liblcms2-2 libtiff5 libwebp6 libwebpdemux2 sensible-utils ucf
 
 RUN docker-php-ext-install mysqli pdo_mysql bcmath tidy sockets
@@ -32,3 +34,12 @@ RUN sed -ri -e 's!/var/www/html!${APACHE_DOCUMENT_ROOT}!g' /etc/apache2/apache2.
 COPY supervisord.conf /etc/supervisor/conf.d/supervisord.conf
 
 CMD ["/usr/bin/supervisord", "-n", "-c", "/etc/supervisor/conf.d/supervisord.conf"]
+
+COPY xdebug.ini /usr/local/etc/php/conf.d/xdebug.ini
+
+RUN if [ "$ENABLE_XDEBUG" = "true" ] ; then \
+      pecl install xdebug-3.1.5 && \
+      docker-php-ext-enable xdebug ; \
+  else \
+      rm /usr/local/etc/php/conf.d/xdebug.ini ; \
+  fi
diff --git a/docker/php/xdebug-empty.ini b/docker/php/xdebug-empty.ini
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/docker/php/xdebug.ini b/docker/php/xdebug.ini
new file mode 100644
index 0000000000..13400baaa4
--- /dev/null
+++ b/docker/php/xdebug.ini
@@ -0,0 +1,5 @@
+zend_extension=xdebug
+xdebug.mode=debug
+xdebug.output_dir=/profile
+xdebug.client_host=host.docker.internal
+xdebug.start_with_request=trigger
diff --git a/readme.md b/readme.md
index 19f52cf49a..2c157818b9 100644
--- a/readme.md
+++ b/readme.md
@@ -32,6 +32,43 @@ To run the migrations, you can use the following composer script:
 composer migrate
 ```
 
+## Docker with Xdebug
+
+The docker file is provided with an optional profile to enable Xdebug.
+
+The first time you have to build both versions:
+
+### Install without Xdebug
+
+```
+docker-compose up -d
+```
+
+### Install profile with Xdebug
+
+```
+docker-compose --profile xdebug up -d
+```
+
+You don't have to rebuild to switch, *you can just switch between versions in your docker engine*.
+Both version are running at the same time, the image without xdebug at port 8000 and the image with xdebug at port 8001.
+
+### Using xdebug
+To bash inside the xdebug enable container, use 
+```
+make bash-xdebug
+```
+
+Xdebug is configured to run with trigger mode, meaning you have to modify the request to enable xdebug: 
+
+- *API*: ADD XDEBUG_TRIGGER as a GET or POST variable, for example in Postman.
+- *Browser*: install a [browser debugging extension](https://www.jetbrains.com/help/phpstorm/browser-debugging-extensions.html#xdebug-helper-extension)
+- *CLI*: (useful with unit tests):
+```
+make bash-xdebug
+source ./start-xdebug.sh
+```
+
 ## Logs
 
 Logs are located in the `./logs` directory.


Reviews:
user: login: lucwollants
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-02-26T15:37:10Z
user: login: lucwollants
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-02-26T15:38:25Z
user: login: lucwollants
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-02-26T15:39:22Z
user: login: lucwollants
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-02-26T15:41:43Z
user: login: grubolsch
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-02-26T16:21:47Z
user: login: lucwollants
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-02-26T16:33:46Z
user: login: lucwollants
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-02-26T16:40:12Z
user: login: lucwollants
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-02-26T16:42:19Z
user: login: grubolsch
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-03T09:00:39Z
user: login: lucwollants
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-04T08:07:35Z
user: login: lucwollants
body: Nice work! I have only one minor remark left on the location of the `start-xdebug.sh`
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-04-04T08:54:52Z

Review comments:
diff_hunk: @@ -1,12 +1,9 @@
 services:
   php:
path: docker-compose.yml
user: login: lucwollants
body: Maybe call this `php-base` and still use `php` instead of `php-cli` ?
created_at: 2025-02-26T15:37:10Z
author_association: CONTRIBUTOR
diff_hunk: @@ -32,3 +34,15 @@ RUN sed -ri -e 's!/var/www/html!${APACHE_DOCUMENT_ROOT}!g' /etc/apache2/apache2.
 COPY supervisord.conf /etc/supervisor/conf.d/supervisord.conf
 
 CMD ["/usr/bin/supervisord", "-n", "-c", "/etc/supervisor/conf.d/supervisord.conf"]
+
+# Always copy a file, but choose# Always copy a file, but choose xdebug.ini or an empty one xdebug.ini or an empty one
path: docker/php/Dockerfile
user: login: lucwollants
body: This is a weird comment 😊
created_at: 2025-02-26T15:38:25Z
author_association: CONTRIBUTOR
diff_hunk: @@ -32,3 +34,15 @@ RUN sed -ri -e 's!/var/www/html!${APACHE_DOCUMENT_ROOT}!g' /etc/apache2/apache2.
 COPY supervisord.conf /etc/supervisor/conf.d/supervisord.conf
 
 CMD ["/usr/bin/supervisord", "-n", "-c", "/etc/supervisor/conf.d/supervisord.conf"]
+
+# Always copy a file, but choose# Always copy a file, but choose xdebug.ini or an empty one xdebug.ini or an empty one
path: docker/php/Dockerfile
user: login: lucwollants
body: I also wonder why we need to copy the empty `xdebug.ini` file if `ENABLE_XDEBUG` would be false?
created_at: 2025-02-26T15:39:22Z
author_association: CONTRIBUTOR
diff_hunk: @@ -32,6 +32,41 @@ To run the migrations, you can use the following composer script:
 composer migrate
 ```
 
+## Docker with Xdebug
+
+The docker file is provided with an optional profile to enable Xdebug.
+
+The first time you have to build both versions:
+
+### Install without Xdebug
+
+```
+docker-compose up
+```
+
+### Install profile with Xdebug
+
+```
+docker-compose --profile xdebug up
+```
+
+You don't have to rebuild to switch, *you can just switch between versions in your docker engine*.
path: readme.md
user: login: lucwollants
body: How can you switch? Are both PHP containers running, one on port 8000 and one on port 8001 with xdebug enabled?
created_at: 2025-02-26T15:41:43Z
author_association: CONTRIBUTOR
diff_hunk: @@ -32,3 +34,15 @@ RUN sed -ri -e 's!/var/www/html!${APACHE_DOCUMENT_ROOT}!g' /etc/apache2/apache2.
 COPY supervisord.conf /etc/supervisor/conf.d/supervisord.conf
 
 CMD ["/usr/bin/supervisord", "-n", "-c", "/etc/supervisor/conf.d/supervisord.conf"]
+
+# Always copy a file, but choose# Always copy a file, but choose xdebug.ini or an empty one xdebug.ini or an empty one
path: docker/php/Dockerfile
user: login: grubolsch
body: Because 
1) COPY cannot be used inside an if, so I have to write always write the config file 
2) But if the config is there when xdebug is not installed, PHP will give an error because it tries to load a module that does not exists

So solutions was to overwrite the config file with an empty one, in case of no xdebug activated.
created_at: 2025-02-26T16:21:47Z
author_association: CONTRIBUTOR
diff_hunk: @@ -26,6 +23,31 @@ services:
       rabbitmq:
         condition: service_healthy
 
+  php-cli:
+      container_name: php.uitdatabank
+      extends:
+          service: php
+      profiles:
path: docker-compose.yml
user: login: lucwollants
body: Is this correct, should this not always run? I think this breaks the existing setup when not using the xdebug profile
created_at: 2025-02-26T16:33:46Z
author_association: CONTRIBUTOR
diff_hunk: @@ -32,3 +34,15 @@ RUN sed -ri -e 's!/var/www/html!${APACHE_DOCUMENT_ROOT}!g' /etc/apache2/apache2.
 COPY supervisord.conf /etc/supervisor/conf.d/supervisord.conf
 
 CMD ["/usr/bin/supervisord", "-n", "-c", "/etc/supervisor/conf.d/supervisord.conf"]
+
+# Always copy a file, but choose# Always copy a file, but choose xdebug.ini or an empty one xdebug.ini or an empty one
path: docker/php/Dockerfile
user: login: lucwollants
body: You could remove the xdebug config file to solve the PHP error?
created_at: 2025-02-26T16:40:12Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,2 @@
+export XDEBUG_MODE=debug XDEBUG_SESSION=1 PHP_IDE_CONFIG="serverName=host.docker.internal"
+# https://github.com/cultuurnet/udb3-backend/pull/1425/files
path: bin/start-xdebug.sh
user: login: lucwollants
body: I guess this doesn't have much added value?
created_at: 2025-02-26T16:42:19Z
author_association: CONTRIBUTOR
diff_hunk: @@ -32,6 +32,41 @@ To run the migrations, you can use the following composer script:
 composer migrate
 ```
 
+## Docker with Xdebug
+
+The docker file is provided with an optional profile to enable Xdebug.
+
+The first time you have to build both versions:
+
+### Install without Xdebug
+
+```
+docker-compose up
+```
+
+### Install profile with Xdebug
+
+```
+docker-compose --profile xdebug up
+```
+
+You don't have to rebuild to switch, *you can just switch between versions in your docker engine*.
path: readme.md
user: login: grubolsch
body: Yes, added some extra text to make it more clear.
Personally I use it most when running unit tests, i have a seperate bash version to go into.
Also put this in the readme file.
created_at: 2025-04-03T09:00:39Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1 @@
+export XDEBUG_MODE=debug XDEBUG_SESSION=1 PHP_IDE_CONFIG="serverName=host.docker.internal"
path: bin/start-xdebug.sh
user: login: lucwollants
body: This bin folder is only used for the CLI commands, I would place this command inside the `docker` folder, which also contains a `config.sh`
created_at: 2025-04-04T08:07:35Z
author_association: CONTRIBUTOR

PR comments:
user: login: lucwollants
created_at: 2025-02-26T15:44:42Z
body: I wonder how this will behave on Jenkins, because as far as I know Jenkins uses our docker-compose file?
author_association: CONTRIBUTOR
user: login: grubolsch
created_at: 2025-04-03T09:03:37Z
body: > I wonder how this will behave on Jenkins, because as far as I know Jenkins uses our docker-compose file?

Give that the base image is still called "php", nothing has changed in Jenkins.
To be sure, I will ask Kristof to verify before merging.
author_association: CONTRIBUTOR
user: login: lucwollants
created_at: 2025-04-03T09:14:43Z
body: > > I wonder how this will behave on Jenkins, because as far as I know Jenkins uses our docker-compose file?
> 
> Give that the base image is still called "php", nothing has changed in Jenkins. To be sure, I will ask Kristof to verify before merging.

Once the other acceptance test run is done you can easily start a run with parameters and change the default branch to `enable-xdebug-in-docker`
author_association: CONTRIBUTOR
user: login: grubolsch
created_at: 2025-04-03T09:17:16Z
body: You mean you want to use xdebug on the server? That was not the goal of this pr.
author_association: CONTRIBUTOR
user: login: lucwollants
created_at: 2025-04-03T09:18:41Z
body: > You mean you want to use xdebug on the server? That was not the goal of this pr.

No, I mean you can do the verification because committing to the main branch
author_association: CONTRIBUTOR
user: login: grubolsch
created_at: 2025-04-03T09:19:22Z
body: Ahh. I understand.  I will run the tests. :-) 
author_association: CONTRIBUTOR
user: login: grubolsch
created_at: 2025-04-03T10:27:38Z
body: feature tests ran without issues https://jenkins.publiq.be/blue/organizations/jenkins/uitdatabank-acceptance-tests/detail/uitdatabank-acceptance-tests/150/pipeline/
author_association: CONTRIBUTOR