===== PhpStorm + Docker + Xdebug =====
В этой небольшой статье я опишу рабочее решение настройки Xdebug для использования его при отладке в PhpStorm с использованием удаленного интерпретатора PHP, работающего внутри Docker-контейнера.
В итоге получится конфигурация на базе окружения в Docker-контейнерах, которая позволит производить отладку Web-приложения, консольного приложения, запускаемых из консоли и запускаемых из PhpStorm.
==== docker-compose ====
# Версия docker-compose
version: '3'
# Список наших сервисов (контейнеров)
services:
nginx:
# используем последний стабильный образ nginx
image: nginx:latest
#restart: always
# маршрутизируем порты
ports:
- "80:80"
- "443:443"
- "9000:9000"
# монтируем директории, слева директории на основной машине, справа - куда они монтируются в контейнере
volumes:
- ../../hosts:/etc/nginx/conf.d
- ../../www:/var/www
- ../../logs:/var/log/nginx
- ../../tmp:/tmp
#название нашего контейнера
container_name: nginx7.2
networks:
- internal
php:
# у нас свой образ для PHP, указываем путь к нему и говорим что его надо собрать
build: ../../images/php
#restart: always
# монтируем директорию с проектами
volumes:
- ../../www:/var/www
- ../../tmp:/tmp
container_name: php7.2
#указываем сеть
networks:
- internal
db:
image: mysql
command: --default-authentication-plugin=mysql_native_password
#restart: always
environment:
MYSQL_ROOT_PASSWORD: 2619192
ports:
- 3306:3306
#название нашего контейнера
container_name: mysql8.0
volumes:
- ../../mysql/mysql8.0:/var/lib/mysql
- ../../mysql/dump:/data
#указываем сеть
networks:
- internal
#Создаем внутреннюю сеть в docker
networks:
internal:
driver: bridge
ipam:
driver: default
config:
- subnet: 192.168.230.0/28
==== Dockerfile ====
На самом деле, поставленная задача достаточно тривиальная. Все решения, которые мне удавалось находить ранее, были завязаны на IP-адресе хоста и их невозможно было использовать остальными членами команды, так как в каждом новом случае IP-адрес хоста был случайный и каждому члену команды приходилось бы менять IP-адрес на свой в общем файле конфигурации бандла, что крайне неудобно.
Решение проблемы оказалось достаточно простым. Я просто создал общую сеть для бандла в docker-compose (192.168.230.0/28) и таким образом добился одинакового IP-адреса хоста (192.168.230.1) на всех машинах членов команды разработки.
Если Вы используете MacOS или Windows, то вместо адреса 192.168.230.1 **Вам нужно будет указать host.docker.internal в приведенном ниже Dockerfile**.
# Для начала указываем исходный образ, он будет использован как основа
FROM php:7.2-fpm
# Необязательная строка с указанием автора образа
MAINTAINER PHPtoday.ru
# RUN выполняет идущую за ней команду в контексте нашего образа.
# В данном случае мы установим некоторые зависимости и модули PHP.
# Для установки модулей используем команду docker-php-ext-install.
# На каждый RUN создается новый слой в образе, поэтому рекомендуется объединять команды.
RUN apt-get update && apt-get install -y \
curl \
wget \
git \
libfreetype6-dev \
libjpeg62-turbo-dev \
libmcrypt-dev \
libpng-dev \
libicu-dev \
libmemcached-dev \
libbz2-dev \
libssh2-1 \
libssh2-1-dev \
libssl-dev \
librabbitmq-dev \
libxml2-dev \
libxslt-dev \
&& docker-php-ext-install -j$(nproc) bcmath bz2 calendar exif intl zip opcache soap iconv mbstring mysqli pdo_mysql zip \
&& docker-php-ext-configure gd --with-freetype-dir=/usr/include/ --with-jpeg-dir=/usr/include/ \
&& docker-php-ext-install -j$(nproc) gd \
&& docker-php-ext-install xsl
#если php5.6 устанавливаем RUN pecl install https://xdebug.org/files/xdebug-2.5.5.tgz && docker-php-ext-enable xdebug
#если php7.2 устанавливаем RUN pecl install https://xdebug.org/files/xdebug-2.8.0.tgz && docker-php-ext-enable xdebug
RUN pecl install xdebug && docker-php-ext-enable xdebug
RUN pecl install ssh2-1.1.2
RUN docker-php-ext-enable xdebug ssh2
RUN echo "error_reporting = E_ALL" > /usr/local/etc/php/php.ini
RUN echo "output_buffering = 4096">> /usr/local/etc/php/php.ini
RUN echo "post_max_size = 256M">> /usr/local/etc/php/php.ini
RUN echo "upload_max_filesize = 256M">> /usr/local/etc/php/php.ini
RUN echo "date.timezone = Europe/Moscow">> /usr/local/etc/php/php.ini
RUN echo "display_startup_errors = On">> /usr/local/etc/php/php.ini
RUN echo "display_errors = On">> /usr/local/etc/php/php.ini
RUN echo "expose_php = Off">> /usr/local/etc/php/php.ini
#Параметры xdebug для корректной работы
#Включение режима удаленной отладки.
RUN echo "xdebug.remote_enable=1">> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini
#Адрес компьютера, на котором расположен клиент отладчика.
#Настройка игнорируется, если значение xdebug.remote_connect_back установлено в 1
RUN echo "xdebug.remote_connect_back=0">> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini
RUN echo "error_reporting=E_ALL">> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini
RUN echo "display_startup_errors=On">> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini
RUN echo "display_errors=On">> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini
#Ключ для удаленных отладчиков.
#Необходим для старта сессии удаленной отладки.
RUN echo "xdebug.idekey=PHPSTORM">> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini
#Порт, по которому xDebug пытается подключится к удаленному отладчику.
RUN echo "xdebug.remote_port=9000">> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini
#Автоматический старт сеанса отладки без GET/POST запроса.
#Обычно для старта сессии необходим специальный GET/POST запрос.
#Если значение установлено в 1, xDebug будет пытаться начать сеанс отладки
#и подключение к клиенту без GET/POST параметров.
#RUN echo "xdebug.remote_autostart=1">> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini
#Максимальный уровень вложенности элементов в массиве или свойстве объекта.
RUN echo "xdebug.var_display_max_depth = -1">> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini
#Максимальное число выводимых элементов массива или свойств объекта.
RUN echo "xdebug.var_display_max_children = -1">> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini
#Максимальная длина выводимых строк.
RUN echo "xdebug.var_display_max_data = -1">> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini
#Адрес компьютера, на котором расположен клиент отладчика.
#Настройка игнорируется, если значение xdebug.remote_connect_back установлено в 1
RUN echo "xdebug.remote_host=host.docker.internal">> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini
#Протокол отладчика.
#Xdebug 2.1 и поздние версии поддерживают только DBGp!
RUN echo "xdebug.remote_handler = dbgp">> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini
RUN chmod 777 /var/log
RUN pecl install mongodb && docker-php-ext-enable mongodb
RUN pecl install amqp && docker-php-ext-enable amqp
# # # RUN pecl install redis && docker-php-ext-enable redis
RUN pecl install memcached && docker-php-ext-enable memcached
#Устанавливаем ImageMagick и необходимые библиотеки
#RUN apt install -y libmagickwand-dev --no-install-recommends
RUN apt-get update && apt-get install -y libmagickwand-6.q16-dev --no-install-recommends \
&& ln -s /usr/lib/x86_64-linux-gnu/ImageMagick-6.8.9/bin-Q16/MagickWand-config /usr/bin \
&& pecl install imagick \
&& echo "extension=imagick.so" > /usr/local/etc/php/conf.d/ext-imagick.ini
#RUN pecl install imagick && docker-php-ext-enable imagick
#rm -rf /var/lib/apt/lists/*
#RUN apt install -y imagemagick php-imagick
RUN pecl install dbase && docker-php-ext-enable dbase
# Куда же без composer'а.
RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
# Установить midnight-commander
RUN apt-get install -y mc
#7zip
RUN apt-get install -y p7zip p7zip-full
# ping
RUN apt-get install iputils-ping -y
#RUN apy-get install php7.2-cgi
#Codeception
RUN composer global require codeception/codeception
# Добавим свой php.ini, можем в нем определять свои значения конфига
#ADD php.ini /usr/local/etc/php/conf.d/40-custom.ini
ADD php.ini /usr/local/etc/php/php.ini
#ADD php.ini /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini
# Указываем рабочую директорию для PHP
WORKDIR /var/www
# Запускаем контейнер
# Из документации: The main purpose of a CMD is to provide defaults for an executing container. These defaults can include an executable,
# or they can omit the executable, in which case you must specify an ENTRYPOINT instruction as well.
CMD ["php-fpm"]
Следует обратить внимание на установку xdebug:
#если php5.6 устанавливаем RUN pecl install https://xdebug.org/files/xdebug-2.5.5.tgz && docker-php-ext-enable xdebug
#если php7.2 устанавливаем RUN pecl install https://xdebug.org/files/xdebug-2.8.0.tgz && docker-php-ext-enable xdebug
RUN pecl install xdebug && docker-php-ext-enable xdebug
И настройки ([[:docker:xdebug:xdebug.ini|описание настроек]])
#Параметры xdebug для корректной работы
RUN echo "xdebug.remote_enable=1">> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini
RUN echo "xdebug.remote_connect_back=0">> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini
RUN echo "error_reporting=E_ALL">> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini
RUN echo "display_startup_errors=On">> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini
RUN echo "display_errors=On">> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini
RUN echo "xdebug.idekey=PHPSTORM">> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini
RUN echo "xdebug.remote_port=9000">> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini
#RUN echo "xdebug.remote_autostart=1">> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini
RUN echo "xdebug.var_display_max_depth = -1">> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini
RUN echo "xdebug.var_display_max_children = -1">> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini
RUN echo "xdebug.var_display_max_data = -1">> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini
RUN echo "xdebug.remote_host=host.docker.internal">> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini
RUN echo "xdebug.remote_handler = dbgp">> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini
Теперь просто запускаем бандл docker-контейнеров:
$ docker-compose up -d
==== Настройка phpstorm ====
Настройка отладки в PhpStorm типичная для подобных ситуаций. Необходимо в настройках (File — Settings) проделать следующее:
=== Добавить Docker сервер ===
Если он у Вас еще не добавлен, конечно. Для этого откройте настройки: «Build, Execution, Deployment» — Docker. Затем нажмите плюсик, чтобы добавить новое подключение к докеру.
{{ :docker:xdebug:phpstorm:windows10:xdebug1.png?600 }}Если PhpStorm не смог установить соединение через порт 2375 - [[:docker:daemon:настройка_в_windows|Настраиваем docker на прием входящих подключений через порт 2375.]]
=== Добавить внешний интерпретатор ===
Откройте настройки: **«Languages & Frameworks» — PHP**
Справа от CLI Interpreter нажмите кнопку с тремя точками.
{{ :docker:xdebug:phpstorm:windows10:xdebug2.png?600 |Выбор версии PHP и добавление интерпретатора}}
В открывшемся окне CLI Interpreters нажмите плюс слева вверху и выберите там **From Docker….**
Далее нужно выбрать **Docker** (либо в новых версиях PhpStorm можно также выбрать **Docker Compose**). Второй вариант мне показался удобней, так как в этом случае я вижу контейнеры только данного проекта, а не все существующие на хосте (у меня их довольно много).
Два варианта на выбор:
{{ :docker:xdebug:phpstorm:windows10:xdebug3.png?600 |Docker}}Docker
{{ :docker:xdebug:phpstorm:windows10:xdebug4.png?600 |Docker Compose}}Docker Compose
Не забывайте правильно указывать наименование образа или сервиса. Нажмите ОК, после чего будет произведена попытка добавления выбранного интерпретатора из Docker.
В случае удачи, вы увидите следующее окно (здесь видно, что была определена версия PHP, конфигурационный файл PHP, а также, что очень важно, версия Xdebug. Переименуйте интерпретатор в нечто более понятное, например, как на скриншоте ниже.
Начиная с версии PhpStorm 2019.1 появилась возможность выбора, каким образом запускать тесты в контейнере. Если у вас контейнер с постоянно работающей службой, такой как **php-fpm**, то выбирайте **Connect to existent container**. Если же у вас в качестве интерпретатора используется **php-cli**, который не выполняется постоянно, то выберите опцию **Always start a new container**. Нажмите OK.
{{ :docker:xdebug:phpstorm:windows10:xdebug5.png?600 |Настройка интерпретатора PHP}}
Теперь Вы должны увидеть следующее: {{ :docker:xdebug:phpstorm:windows10:xdebug6.png?600 |Path mappings берется из docker-compose.yml}}
Нажмите Apply.
=== Проверить конфигурацию Xdebug ===
Откройте настройки: **«Languages & Frameworks» — PHP — Debug**. И нажмите на ссылку **Validate**.
{{ :docker:xdebug:phpstorm:windows10:xdebug7.png?600 |Нажмите Validate для проверки настройки}}
Откроется окно, в котором Вы должны указать полный путь к web-корню (в нашем примере это подкаталог проекта **phpinfo**) и адрес сервера (в нашем примере порт 80 контейнера nginx транслируется в порт 80 хоста, поэтому в адресе порт не указывается. Если Вы транслировали в другой порт хоста — укажите обязательно его, например, [[http://127.0.0.1:8080|http://127.0.0.1:8080]]). Нажмите Validate.
{{ :docker:xdebug:phpstorm:windows10:xdebug8.png?600 |Результаты проверки Xdebug}}
Если у Вас результат проверки выглядит так же, то Вы все настроили правильно. Закройте окно Validate Debugger Configuration.
Если у Вас проблема с валидацией имени сервера, значит вы в настройках сервера nginx не указали 127.0.0.1 в качестве одного из server_name. Если проблема с загрузкой php.ini, значит вы использовали другой способ конфигурирования PHP вместо загрузки php.ini в каталог контейнера /usr/local/etc/php/ — это не страшно, если Вы понимаете, что делаете.
=== Добавить PHP сервер ===
Откройте настройки: **«Languages & Frameworks» — PHP — Servers** и нажмите плюсик, чтобы добавить новый.
Укажите имя сервера **Docker** (должно совпадать с переменной окружения PHP_IDE_CONFIG в docker-compose.yml) и хост 127.0.0.1. Затем ниже включите опцию Use path mappings и укажите соответствие между локальным каталогом проекта и этим же каталогом проекта внутри Docker-контейнера. Это соответствие изначально настраивается в docker-composer.yml для службы php-fpm в разделе volumes. Затем нажмите OK.
{{ :docker:xdebug:phpstorm:windows10:xdebug9.jpg?600 |Новый PHP сервер с отображением локального каталога на каталог контейнера}}
=== Добавить конфигурацию для запуска PHP Web ===
Остался последний штрих — добавление конфигурации запуска. Мы добавим простую Web-страницу.
В главном меню Run перейдите в Edit configurations…
{{ :docker:xdebug:phpstorm:windows10:xdebug10.jpg?600 }}
В открывшемся окне нажимайте плюсик вверху слева и выбирайте PHP Web page. Укажите имя для данной страницы, например, phpweb, затем укажите сервер, с которым связана эта страница (мы создали его на предыдущем шаге) и нажмите OK. {{ :docker:xdebug:phpstorm:windows10:xdebug11.png?600 }}
Далее жмем жука
{{ :docker:xdebug:phpstorm:windows10:xdebug13.png }}
=== Добавить конфигурацию для запуска PHP script ===
В главном меню Run перейдите в Edit configurations…
{{ :docker:xdebug:phpstorm:windows10:xdebug10.jpg?600 }}
В открывшемся окне нажимайте плюсик вверху слева и выбирайте PHP script.кажите имя для данной страницы, например, phpscript, затем укажите файл который будем запускать из консоли, и контейнер с php.
{{ :docker:xdebug:phpstorm:windows10:xdebug12.png?600 }}
Далее жмем жука
{{ :docker:xdebug:phpstorm:windows10:xdebug13.png }}