Отладка PHP в Docker контейнере

06.02.2022

После предыдущих приключений с Gitlab-CI и кастомизацией Visual Studio Code как IDE для PHP мне захотелось иметь переносимую среду разработки с использованием PHP, чтобы не настраивать среду на рабочей машине, точнее чтобы любой человек мог подключится к разработке проекта с минимальными усилиями по организации среды. Так начались новые приключения ...

В итоге получится запускать скрипты в docker контейнере, а дебажить их на хостовой машине с использованием VS Code

Настоятельно рекомендуется ознакомиться со предыдущими постами вот и вот, потому что текущая статья будет отчасти основываться на некоторых моментах из приведенных в ссылках.

Файловая структура

  • .docker - директория данных для файла docker-compose-dev.yml
    • php
      • dev
        • entrypoint.sh - файл с bash кодом для старта работы контейнера
      • Dockerfile - конфиг образа PHP контейнера
      • xdebug.ini - настройки дебагера PHP
  • .vscode - директория настроек для VS Code
    • launch.json - файл настроек для отладки
  • src - директория с исходниками на PHP
  • composer.json
  • docker-compose-dev.yml - файл композиции контейнеров для Docker Compose

Конфигурация

В .docker/php/dev/entrypoint.sh записываем следующее:

•••
bash
#!/bin/bash # устанавливаем нужные библиотеки php composer install # бесконечный цикл чтобы контейнер не останавливался while true; do sleep 10; done;

docker-compose-dev.yml заполним следующим образом:

•••
yml
version: '3.0' services: mysql: image: mysql:5.7 container_name: mdk-mysql-dev volumes: - ./docker-data/mysql/data:/var/lib/mysql environment: MYSQL_ROOT_PASSWORD: root command: ['mysqld', '--character-set-server=utf8mb4', '--collation-server=utf8mb4_unicode_ci'] networks: - app-network php: build: context: ./.docker/php args: uid: 1000 user: runner container_name: mdk-php-dev depends_on: - mysql volumes: - ./:/opt/mdk/ - ./.docker/php/xdebug.ini:/usr/local/etc/php/conf.d/xdebug.ini - ./.docker/php/dev/entrypoint.sh:/usr/bin/entrypoint.sh command: /bin/bash -c "/usr/bin/entrypoint.sh" networks: - app-network networks: app-network: driver: bridge ipam: driver: default config: - subnet: 192.168.0.1/24

Почти также как и в прошлый раз, однако теперь имена контейнеров container_name изменились и сеть app-network обзавелась дополнительными настройками: создаем подсеть для docker контейнеров с IP 192.168.0.1 с диапазоном адресов от 192.168.0.1 до 192.168.0.254 (посчитать можно через IP калькулятор). Теперь каждому контейнеру будет присвоен свой IP адрес, который также будет доступен на хост машине.

Можно поступить проще и прокинуть из контейнера порт на хост машину, и тогда для отладки на хост машине можно использовать localhost:port.

Теперь заполним .docker/xdebug.ini:

•••
ini
xdebug.remote_handler = dbgp xdebug.log = xdebug.log # IP адрес композиции контейнеров xdebug.client_host = 192.168.0.1 # порт на котором будет работать xdebug xdebug.client_port = 9003 xdebug.mode = coverage,debug

Если при работе скриптов xdebug в лог будет писать что-то подобное:

•••
plaintext
[7] Log opened at 2022-02-06 10:17:44.246659 [7] [Config] INFO: Trigger value for 'XDEBUG_TRIGGER' not found, falling back to 'XDEBUG_SESSION' [7] [Config] INFO: Trigger value for 'XDEBUG_SESSION' not found, so not activating [7] Log closed at 2022-02-06 10:17:49.312342

Тогда надо в .docker/xdebug.ini добавить xdebug.start_with_request = yes (документация).

В .vscode/launch.json пишем:

•••
json
{ "version": "0.2.0", "configurations": [ { "name": "Listen for Xdebug", "type": "php", "request": "launch", // IP адрес композиции контейнеров "hostname": "192.168.0.1", // порт "port": 9003, "log": true, // сопоставление файлов на сервере (ключ) с файлами на локальной машине (значение) "pathMappings": { "/opt/mdk/": "${workspaceFolder}" } } ] }

Кроме workspaceFolder есть другие переменные.

Запуск

Теперь можно запускать:

•••
bash
$ docker-compose -f docker-compose-dev.yml up --build

Открываем в VS Code нужный файл, ставим в нужном месте breakpoint и запускаем отладку.

Заходим в docker контейнер с PHP и запускаем нужный PHP скрипт:

•••
bash
$ docker exec -it mdk-php-dev /bin/bash runner@2d825db6f657:/opt/mdk$ php -f pathfile.php

Запуск скриптов в контейнере из VS Code

Мы уже рассмастривали tasks в VS Code. Можно поступить аналогичным образом для запуска скриптов/тестов (в зависимости от того что нужно).

Например, настроим задачи запуска unit тестов для вех файлов тестов и только для текущего. Для этого создадим файл .vscode/tasks.json и напишем следующее:

•••
json
{ "version": "2.0.0", "tasks": [ // запуск всех тестов { "label": "Run unit tests all", "type": "shell", "command": "docker", "args": [ "exec", "-it", "mdk-php-dev", "/bin/bash", "-c", "vendor/bin/phpunit --colors=always --coverage-html --bootstrap tests/Unit/bootstrap.php tests/Unit/" ], "group": "test", "presentation": { "reveal": "always", "panel": "new" } }, // запуск текущего открытого файла в VS Code на тест { "label": "Run unit test current file", "type": "shell", "command": "docker", "args": [ "exec", "-it", "mdk-php-dev", "/bin/bash", "-c", "vendor/bin/phpunit --colors=always --coverage-html coverage-report-html --bootstrap tests/Unit/bootstrap.php ${relativeFile}" ], "group": "test", "presentation": { "reveal": "always", "panel": "new" } } ] }

В VS Code идем в Terminal => Run tasks и выбираем один из наших task.

Итог

Подобное приходилось настраивать и в контексте работы с CMS (разработка модуля для CMS в docker контейнерах, о чем поговорим в следующих статьях) и это оказывается удобно и просто. Удаленная отладка (конечно не совсем удаленная, но все-таки) с xdebug вполне работоспособна.