voskobovich
@voskobovich
PHP Developer | 8+ years exp.

Как подключиться к Xdebug запущенному в Docker контейнере на удаленной машине?

Коллеги, прошу помощи в отладке соединения от моей локальной машины к удаленному xdebug серверу.

Имею сервер разработки (далее host.dev) на котором в Docker контейнере запущен PHP-FPM с xdebug на ОС Linux Alpine. Так как стандартный порт xdebug 9000 зарезервирован под PHP-FPM, то для xdebug был выделен порт 9001.

Версии

PHP 7.1.0 (cli) (built: Dec 27 2016 19:41:35) ( NTS )
Copyright (c) 1997-2016 The PHP Group
Zend Engine v3.1.0-dev, Copyright (c) 1998-2016 Zend Technologies
with Zend OPcache v7.1.0, Copyright (c) 1999-2016, by Zend Technologies
with Xdebug v2.5.1-dev, Copyright (c) 2002-2016, by Derick Rethans


Содержмое файла /usr/local/etc/php/conf.d/xdebug.ini, лежащего внути контейнера, следующее:
; NOTE: The actual debug.so extention is NOT SET HERE but rather (/usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini)

xdebug.remote_autostart=1
xdebug.remote_enable=1
xdebug.remote_connect_back=0
;xdebug.cli_color=0
xdebug.profiler_enable=0
xdebug.remote_handler=dbgp
xdebug.remote_mode=req

xdebug.remote_port=9001
xdebug.remote_host=localhost
xdebug.idekey=PHPSTORM

xdebug.remote_log="/tmp/xdebug.log"


Соответственно порт 9001 проброшен из контейнера на хост машину.
Вот часть конфигурации php контейнера в docker-compose.yml
php:
    build:
      context: ./docker/containers/php
      dockerfile: Dockerfile-dev
    volumes:
      - ./:/var/www/html
      - ./docker/containers/php/config/xdebug.ini:/usr/local/etc/php/conf.d/xdebug.ini
    ports:
      - "9001:9001"


Вывод команды docker ps для php контейнера подтверждает проброс порта.
В колонке PORTS напроти php контейнера - 9000/tcp, 0.0.0.0:9001->9001/tcp

На этом этапе я должен уже уметь с host.dev подключаться к xdebug и работать.

Теперь, мне необходимо с моей локальной машины подключаится к Xdebug на host.dev.
Но, вся проблема в том, что моя локальная машина находиться за роутером на котором проброс портов не работает. Вместо того, чтобы решать проблему с роутером я начал искать другой путь, и нашел его.

В интернете рекомендуют юзать Remote Port Forwarding от SSH и описано это здесь https://help.ubuntu.com/community/SSH/OpenSSH/Port...
По этому же мануалу у меня получилась следующее
ssh -R 9001:localhost:9001 user@host.dev
После этой команды, как я понял, порт 9001 с host.dev должен быть забинден на мою локальную машину. Таким образом я получаю прямой доступ к xdebug со своей локальной машины.

Как понимаете, не работает :(

В логах xdebug я вижу ошибки, но гугление не помогает.

Log opened at 2017-01-29 11:22:36
I: Connecting to configured address/port: localhost:9001.
W: Creating socket for 'localhost:9001', poll success, but error: Operation in progress (29).
W: Creating socket for 'localhost:9001', poll success, but error: Operation in progress (29).
E: Could not connect to client. :-(
Log closed at 2017-01-29 11:22:36


Моя IDE PHPStorm настроена стандартным способом.
1. Изменен порт у Xdebug
1c9e918cb38f4b068a4203725d3a30d3.png
2. Настроен DBGp Proxy
353b0ee8731f4dd990caaa6e5384df51.png
3. Настроен удаленный сервер с маппингом локальных и удаленных директорй
65bc76b5af3941fa977cc5ec59cac071.png
Так как у меня мультидоменное приложение, то настроен сервер для одного домена. Как сделать универсально я не нашел.
Прошу заметить, что мое работает на порту 8080. Именно этот порт проброшен из nginx слушающего 80 порт внутри Docker-контейнера на хост машину. Поэтому при настройке сервера я указанл порт 8080.
4. Настроен для проекта PHP Remote Debug на созданный в п.3 сервер
15dfe7c73fdc4a25a100f97a6d4537ee.png
5. Далее выбираю конфигурацию и начинаю ждать дебаг-сессию
33ac2be675b34e66bc19837c21c8e473.png
Вроде все логично, и правильно.

Ну и наконец-то в браузере установлен Xdebug Helper для Chrome в котором и включен дебаг
141cbee88f564c00832766e1f56206a6.png

Кто-то знает в чем-дело?
  • Вопрос задан
  • 3809 просмотров
Пригласить эксперта
Ответы на вопрос 1
voskobovich
@voskobovich Автор вопроса
PHP Developer | 8+ years exp.
Вот развернутый ответ на мой вопрос.

Рассмотрим ситуацию со стороны удаленного сервера на котором запущен докер контейнер.
Докер уже позаботился о бОльшей части проблемы и сделал все роуты так, что ты из контейнера можно было пинговать интерфейс eth0, через который должен поступать интернет на серверную машину. Мало того, из контейнера можно пинговать любой хост на докер-хосте, кроме 127.0.0.1 самого хоста - по вполне понятным причинам (127.0.0.1 из контейнера будет lo интерфейс самого контейнера).
Допустим IP на eth0 вашего хоста 10.45.6.87. То есть пинг из докер контейнера на 10.45.6.87 должен проходить успешно.
А раз eth0 это выход во внешний мир, значит можно xdebug`у сказать, что клиент будет на хосту 10.45.6.87 порт 9000, пусть там его ждет. Мы же потом сделаем туда SSH тунель.

Создаем тунель.
Пробрасываем удаленный порт через SSH-тунель на локальную машину
ssh -R 9000:localhost:9000 user@server.com
и рассчитываем на то, что в итоге бинд на удаленной стороне будет выглядеть так
10.45.6.87:9000 => 127.0.0.1:9000
но мы сильно ошибаемся :)
И эта ошибка стоит нам кучи времени.

Давайте посмотрим что нам скажет netstat -plnt.
А сказать он должен, что после запуска тунеля, на удаленной машине мы имеем бинд на
127.0.0.1:9000, а не 10.45.6.87:9000 как ожидали.
То есть, получается, что xdebug ждет клиента на 10.45.6.87:9000, а после открытия тунеля клиент оказывается на 127.0.0.1:9000.
Беда в том, что забиндить клиента мы можем только на локальный хост.
Так написано в доке man ssh.

Из контейнера мы 127.0.0.1:9000 докер-хоста увидеть не можем, а значит остается только сделать роутинг пакетов с 10.45.6.87:9000 на 127.0.0.1:9000 внутри удаленной машины.
Сделать это можно множеством способом, в том числе и iptables. Лично я сделал еще один SSH тунель внутри своего сервера вот так:

1. В конфигах xdebug указываем
xdebug.remote_port = 9001
xdebuh.remote_host = 10.45.6.87

2. На свою локальную машину через тунель с виртуалки прокидываем порт 9000.
ssh -R 9000:127.0.0.1:9000 user@server.com
3. На локальной машине создаем тунель с порта 9000 на 9001
ssh -g -L 9001:localhost:9000 -f -N 127.0.0.1
Вот и все.

Но стоит учесть, что это решение рассчитано только на одного разработчика и полно костылей.
Так что через пару дней после понятия проблемы я поднял на том же сервере OpenVPN сервер в докере и проблема отпала сама собой.
Поясняю. VPN создает виртуальную локальную сеть. Моя локальная машина и моя виртуалка которая находится на серверах хостинг-провайдера оказывается в одной локальной сети. А раз так. В таком случае, я могу из docker-контейнера запущеном на виртуалке пинговать свою локальную машину. Значит Xdebug будет подключаться сразу к моей локальной машине без всяких пробросов и костылей.

При таком раскладе можно настроить Xdebug двумя способами.
Первый.
Xdebug будет стучаться на конкретный IP.
xdebug.remote_port = 9000
xdebug.remote_host = <IP локальной машины>

Это полезно когда вы один разработчик на проекте и нужно отлаживать консольные скрипты.

Второй.
Xdebug будет стучаться на IP с которого пришел запрос.
xdebug.remote_connect_back=1
xdebug.remote_port = 9000

Удобно, когда работает команда разработчиков, но не удобен когда нужно отладить консольный скрипт. При запуске скрипта в консоли нужно передавать Xdebug`у IP локальной машины разработчика, чтобы он знал куда отдавать дебаг-логи.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы