Доброго времени суток, Хабр!
Еще год назад мой процесс отладки кода в PHP заключался в двух строчках:
Периодически, конечно, приходилось использовать более «сложные» конструкции:
Нет, что вы! Я знал — в наше время не подобает культурному программисту заниматься этим
Но, честно говоря, я всегда боялся того, что не понимаю. В том числе ипринтеров xDebug, в особенности, как все это дело настроить. В один прекрасный день у меня получилось это сделать на своей машине и в локальном проекте — радости не было предела. Спустя много месяцев я столкнулся с новой проблемой, как заниматься отладкой в PHPstorm через xDebug, если проект собирается удаленно докером через CI.
Если Вы так же, как и я, испытываете трудности с настройкой разных штук, добро пожаловать под кат, я расскажу о своем опыте настройки окружения отладки с такими страшными словами, как Docker, xDebug, CI.
Для тех, кто не любит воду и хочет перейти непосредственно к сути настройки.
Над катом я немного слукавил, я занимался кустарной отладкой не только потому, что боялся настроить что-либо, и не потому что слишком глупый, а просто потому, что у меня не было необходимости в чем-то более удобном. Чаще всего я работал над проектами, локально на своем довольно мощном компьютере, да и задачи были не настолько сложными, чтобы процесс отладки начал занимать достаточно весомую позицию.
В какой-то момент, я для себя осознал, что мне уже просто неудобно, и попытался подружить xDebug и PHPstorm при работе над локальным проектом. Беда в том, что большинство документаций и гайдов, которые я нашел, подразумевают, что читающий их человек довольно хорошо разбирается в предметной области и все понимает, в моем случае это было не так и на свою первую настройку xDebug я в сумме потратил 4-5 часов за 2 вечера. Это было довольно тяжело морально, я чувствовал себя бесконечно тупым. Тем не менее, настроить получилось, все работало!
Да, стало удобней, локально-дома, но на основной работе я занимался сайтами удаленно, и чаще всего у меня не было возможности либо выгрузить сайт локально (из-за слабой машины или неудобного процесса развертывания), либо влиять на настройки сервера из-за хостингов, поэтому вносил правки «на живую» и отладкой занимался через html-комментирование print_r (на той работе это было «нормально», хоть и не горжусь этим опытом).
Однако, 3 месяца назад я перешел в более крутую компанию и стал заниматься действительно серьезным проектом с высокой нагрузкой. И тут для меня многое изменилось. Инфраструктура и процесс разработки примерно такие: есть свой сервер GitLab, у каждого проекта есть свой репозиторий, в Jira приходят задачи, по номерам задачи создаешь ветку, при создании ветки с помощью CI автоматически создается своя песочница с сайтом, где ты спокойно работаешь, каждый push пересобирает ветку, по окончанию работ отдаешь на код-ревью, вливаешь ветку в мастер.
Все круто за исключением одного НО, каждый пересбор ветки в моем случае занимает примерно 10 секунд. В процессе самой разработки это несущественное время, так как я уже перешел ту стадию, когда приходилось проверять работоспособность кода чуть ли не каждую строчку из-за неуверенности и малого опыта. Однако, когда я переходил к отладке, эти 10 секунд начали играть ощутимую роль. Процесс подобной отладки выглядел в итоге так:
По приблизительным подсчетам, готовая к мержу ветка имела примерно 20% полезных коммитов и 80% коммитов отладки. Допустим, я закончил работу над веткой с 300 коммитами, из них 240 коммитов по сути просто отжирали 40 минут моего рабочего времени (и это только время ожидания сборки ветки, не учитывая те секунды, которые складываются в минуты, на то, чтобы добавить 2 строчки и потом их удалить).
В какой-то момент мне это надоело и я решил-таки настроить xDebug, чтобы процесс отладки стал менее затратным. К несчастью, мои нынешние коллеги либо не пользовались этой технологией (жду шутки про «Устроился в крутую компанию, где никто не пользуется xDebug'ом»), либо не знали\не помнили, как подружить IDE с xDebug'ом, в случае когда ветка собирается удаленно через CI, а так как я ни разу не devOps и как я упомянул выше, процесс настройки чего-либо является для меня достаточно мучительным процессом, это вылилось примерно в 6 часов чистого времени, чтобы наконец все заработало, и я понимал процесс, и это было бы достаточно удобно.
Я не буду вдаваться в подробности, как прикручивать CI, Docker, в общем, как собрать инфраструктуру, предполагается, что это уже все готово и осталось только настроить свое личное окружение.
Допустим, наш репозиторий имеет примерно такую структуру:
Для начала нам нужно проверить, есть ли в текущем образе сам xDebug, для этого можете воспользоваться phpinfo();
Если xDebug уже включен в сборку — отлично, если нет, то ознакомьтесь с этим источником, который помог мне непосредственно в самой настройке, однако я пошел немного по другому пути.
Для того, чтобы в итоге все заработало, нам важны 2 настройки xDebug:
В итоговой сборке удаленной ветки remote_enable должен быть включен, а в remote_host должен быть присвоен IP вашего компьютера в сети. Давайте включим эти настройки в наш билд.
Для начала нужно узнать где хранятся настройки php, они могут располагаться либо в /usr/local/etc/php/conf.d/php.ini, либо сам файл .ini может быть назван иначе, в моем случае это /usr/local/etc/php/conf.d/php-settings.ini. Узнать это можно из настроек собираемого образа.
Создаем в нашей ветке свои дополнительные настройки через тот же файл php-settings.ini, а расположим его в ./build_env/php/php-settings.ini
Прописываем в нем 2 вышеупомянутые настройки:
Далее нам нужно добавить этот файл к «родительским» настройкам образа. Я делаю это через volumes путем добавления в ./build_env/docker-compose/docker-compose.tmpl строчки:
Примерно так в итоге выглядит docker-compose.tmpl в моем проекте:
При следующей сборке ветки, можно проверить привязались ли новые настройки через тот же phpinfo();, если да — отлично, если нет — Вам не повезло и придется пройти тот же путь, что проделал я в первый раз :(
Далее нужно настроить сам PHPstorm. Я решил не использовать DBgp Proxy, чтобы не настраивать маппинги во всплывающем окне каждый раз. В моем случае я использую шаблон сервера, который будет содержать в себе необходимые маппинги.
Переходим в Settings / Preferences | Languages & Frameworks | PHP | Servers
Сохраняем эти настройки, менять мы их будем каждый раз, когда работаем с новой веткой. Например, если сегодня работаю с веткой web-2233 то поменяю маппинг на /var/www/builds/путь_до_билда/web-2233
Теперь довольно важный и не самый очевидный момент. Когда мы начинаем дебаг, PHPstorm должен понимать, какие локальные файлы соответствуют файлам на удаленном сервере. Если сервер не передал ему конкретную установку, то появится всплывающее окно, в котором нужно проставить соответствия путей вручную. Для того, чтобы PHPstorm сразу брал маппинги от сервера с названием BRANCH нужно добавить в нашу сборку переменную окружения PHP_IDE_CONFIG
В ./build_env/docker-compose/docker-compose.tmpl создаем новую переменную окружения в environment:
В .gitlab-ci.yml задаем эту переменную:
Нам не нужны расширения для браузера, не нужно передавать в get-параметры URL XDEBUG_SESSION_START=IDE_KEY, не нужно добавлять дополнительные конфигурации.
Достаточно просто включить прослушку и обновить страницу сайта, как только мы наткнемся на первый брекпоинт, выполнение приложение остановится на нем
Спасибо за внимание, надеюсь эта статья будет полезна и кто-нибудь сэкономит время, не наступая на те же грабли, что и я :)
Источники, которые я использовал при первичной настройке:
https://gist.github.com/chadrien/c90927ec2d160ffea9c4
https://confluence.jetbrains.com/display/PhpStorm/Docker+Support+in+PhpStorm#DockerSupportinPhpStorm-DebuggingthePHPwebapplicationrunningintheDockercontainer
Еще год назад мой процесс отладки кода в PHP заключался в двух строчках:
var_dump($variable);
die();
Периодически, конечно, приходилось использовать более «сложные» конструкции:
console.log(data);
echo json_encode($variable, JSON_UNESCAPED_UNICODE);
exit();
Нет, что вы! Я знал — в наше время не подобает культурному программисту заниматься этим
древним ремеслом
шутка про другое древнейшее ремесло
Но, честно говоря, я всегда боялся того, что не понимаю. В том числе и
Если Вы так же, как и я, испытываете трудности с настройкой разных штук, добро пожаловать под кат, я расскажу о своем опыте настройки окружения отладки с такими страшными словами, как Docker, xDebug, CI.
Для тех, кто не любит воду и хочет перейти непосредственно к сути настройки.
Почему стоит уйти от заплесневевших методов отладки и перейти на адекватные технологии?
Над катом я немного слукавил, я занимался кустарной отладкой не только потому, что боялся настроить что-либо, и не потому что слишком глупый, а просто потому, что у меня не было необходимости в чем-то более удобном. Чаще всего я работал над проектами, локально на своем довольно мощном компьютере, да и задачи были не настолько сложными, чтобы процесс отладки начал занимать достаточно весомую позицию.
В какой-то момент, я для себя осознал, что мне уже просто неудобно, и попытался подружить xDebug и PHPstorm при работе над локальным проектом. Беда в том, что большинство документаций и гайдов, которые я нашел, подразумевают, что читающий их человек довольно хорошо разбирается в предметной области и все понимает, в моем случае это было не так и на свою первую настройку xDebug я в сумме потратил 4-5 часов за 2 вечера. Это было довольно тяжело морально, я чувствовал себя бесконечно тупым. Тем не менее, настроить получилось, все работало!
Да, стало удобней, локально-дома, но на основной работе я занимался сайтами удаленно, и чаще всего у меня не было возможности либо выгрузить сайт локально (из-за слабой машины или неудобного процесса развертывания), либо влиять на настройки сервера из-за хостингов, поэтому вносил правки «на живую» и отладкой занимался через html-комментирование print_r (на той работе это было «нормально», хоть и не горжусь этим опытом).
Однако, 3 месяца назад я перешел в более крутую компанию и стал заниматься действительно серьезным проектом с высокой нагрузкой. И тут для меня многое изменилось. Инфраструктура и процесс разработки примерно такие: есть свой сервер GitLab, у каждого проекта есть свой репозиторий, в Jira приходят задачи, по номерам задачи создаешь ветку, при создании ветки с помощью CI автоматически создается своя песочница с сайтом, где ты спокойно работаешь, каждый push пересобирает ветку, по окончанию работ отдаешь на код-ревью, вливаешь ветку в мастер.
Все круто за исключением одного НО, каждый пересбор ветки в моем случае занимает примерно 10 секунд. В процессе самой разработки это несущественное время, так как я уже перешел ту стадию, когда приходилось проверять работоспособность кода чуть ли не каждую строчку из-за неуверенности и малого опыта. Однако, когда я переходил к отладке, эти 10 секунд начали играть ощутимую роль. Процесс подобной отладки выглядел в итоге так:
- Добавляю 2 строчки
- Пушу коммит
- Жду 10 секунд
- Проверяю, смотрю, что не так
- Repeat
По приблизительным подсчетам, готовая к мержу ветка имела примерно 20% полезных коммитов и 80% коммитов отладки. Допустим, я закончил работу над веткой с 300 коммитами, из них 240 коммитов по сути просто отжирали 40 минут моего рабочего времени (и это только время ожидания сборки ветки, не учитывая те секунды, которые складываются в минуты, на то, чтобы добавить 2 строчки и потом их удалить).
В какой-то момент мне это надоело и я решил-таки настроить xDebug, чтобы процесс отладки стал менее затратным. К несчастью, мои нынешние коллеги либо не пользовались этой технологией (жду шутки про «Устроился в крутую компанию, где никто не пользуется xDebug'ом»), либо не знали\не помнили, как подружить IDE с xDebug'ом, в случае когда ветка собирается удаленно через CI, а так как я ни разу не devOps и как я упомянул выше, процесс настройки чего-либо является для меня достаточно мучительным процессом, это вылилось примерно в 6 часов чистого времени, чтобы наконец все заработало, и я понимал процесс, и это было бы достаточно удобно.
Процесс настройки
Я не буду вдаваться в подробности, как прикручивать CI, Docker, в общем, как собрать инфраструктуру, предполагается, что это уже все готово и осталось только настроить свое личное окружение.
Допустим, наш репозиторий имеет примерно такую структуру:
Для начала нам нужно проверить, есть ли в текущем образе сам xDebug, для этого можете воспользоваться phpinfo();
Если xDebug уже включен в сборку — отлично, если нет, то ознакомьтесь с этим источником, который помог мне непосредственно в самой настройке, однако я пошел немного по другому пути.
Настраиваем php.ini
Для того, чтобы в итоге все заработало, нам важны 2 настройки xDebug:
- xdebug.remote_enable
- xdebug.remote_host
В итоговой сборке удаленной ветки remote_enable должен быть включен, а в remote_host должен быть присвоен IP вашего компьютера в сети. Давайте включим эти настройки в наш билд.
Для начала нужно узнать где хранятся настройки php, они могут располагаться либо в /usr/local/etc/php/conf.d/php.ini, либо сам файл .ini может быть назван иначе, в моем случае это /usr/local/etc/php/conf.d/php-settings.ini. Узнать это можно из настроек собираемого образа.
Создаем в нашей ветке свои дополнительные настройки через тот же файл php-settings.ini, а расположим его в ./build_env/php/php-settings.ini
Прописываем в нем 2 вышеупомянутые настройки:
xdebug.remote_enable = on
xdebug.remote_host = IP.ВАШЕГО.КОМПЬЮТЕРА.ВСЕТИ
Далее нам нужно добавить этот файл к «родительским» настройкам образа. Я делаю это через volumes путем добавления в ./build_env/docker-compose/docker-compose.tmpl строчки:
- ${PROJECT_DIR}/build_env/php/php-settings.ini:/usr/local/etc/php/conf.d/php-settings.ini
Примерно так в итоге выглядит docker-compose.tmpl в моем проекте:
При следующей сборке ветки, можно проверить привязались ли новые настройки через тот же phpinfo();, если да — отлично, если нет — Вам не повезло и придется пройти тот же путь, что проделал я в первый раз :(
Настраиваем маппинги в PHPstorm
Далее нужно настроить сам PHPstorm. Я решил не использовать DBgp Proxy, чтобы не настраивать маппинги во всплывающем окне каждый раз. В моем случае я использую шаблон сервера, который будет содержать в себе необходимые маппинги.
Переходим в Settings / Preferences | Languages & Frameworks | PHP | Servers
- Создаем шаблон сервера
- Name: BRANCH
- host: любой, он не влияет
- port: любой, он не влияет
- Debugger: xDebug
- Ставим галку на Use path mappings
- Проставляем соответствующие маппинги, рабочие локальные папки должны соответствовать папкам на сервере, где располагаются собранные ветки, в моем случае собранные билды находятся в папке /var/www/builds/your_namespace/your_project/your_branch
Сохраняем эти настройки, менять мы их будем каждый раз, когда работаем с новой веткой. Например, если сегодня работаю с веткой web-2233 то поменяю маппинг на /var/www/builds/путь_до_билда/web-2233
Добавляем новую переменную окружения, чтобы IDE автоматически подтягивала маппинги
Теперь довольно важный и не самый очевидный момент. Когда мы начинаем дебаг, PHPstorm должен понимать, какие локальные файлы соответствуют файлам на удаленном сервере. Если сервер не передал ему конкретную установку, то появится всплывающее окно, в котором нужно проставить соответствия путей вручную. Для того, чтобы PHPstorm сразу брал маппинги от сервера с названием BRANCH нужно добавить в нашу сборку переменную окружения PHP_IDE_CONFIG
В ./build_env/docker-compose/docker-compose.tmpl создаем новую переменную окружения в environment:
PHP_IDE_CONFIG: ${PHP_IDE_CONFIG}
В .gitlab-ci.yml задаем эту переменную:
- export PHP_IDE_CONFIG="serverName=BRANCH"
Готово!
Нам не нужны расширения для браузера, не нужно передавать в get-параметры URL XDEBUG_SESSION_START=IDE_KEY, не нужно добавлять дополнительные конфигурации.
Достаточно просто включить прослушку и обновить страницу сайта, как только мы наткнемся на первый брекпоинт, выполнение приложение остановится на нем
Спасибо за внимание, надеюсь эта статья будет полезна и кто-нибудь сэкономит время, не наступая на те же грабли, что и я :)
Источники, которые я использовал при первичной настройке:
https://gist.github.com/chadrien/c90927ec2d160ffea9c4
https://confluence.jetbrains.com/display/PhpStorm/Docker+Support+in+PhpStorm#DockerSupportinPhpStorm-DebuggingthePHPwebapplicationrunningintheDockercontainer