资讯专栏INFORMATION COLUMN

在Docker中使用Xdebug

jerry / 3361人阅读

摘要:说明开发和调试环境为本地中的,环境为本地下的。再次在容器中抓取端口数据包连接的源地址已经正确再次使用的断点调试时,控制台如下所以,使用进行远程调试时,需要选择合适的调试模式,在下建议使用远程模式。

首发于 樊浩柏科学院

我们经常会使用 PhpStorm 结合 Xdebug 进行代码断点调试,这样能追踪程序执行流程,方便调试代码和发现潜在问题。博主将开发环境迁入 Docker 后,Xdebug 调试遇到了些问题,在这里整理出 Docker 中使用 Xdebug 的方法和注意事项。

说明:开发和调试环境为本地 Docker 中的 LNMP,IDE 环境为本地 Win10 下的 PhpStorm。这种情况下 Xdebug 属于远程调试模式,IDE 和本地 IP 为 192.168.1.101,Docker 中 LNMP 容器 IP 为 172.17.0.2。
问题描述

在 Docker 中安装并配置完 Xdebug ,并设置 PhpStorm 中对应的 Debug 参数后,但是 Debug 并不能正常工作。

此时,php.ini中 Xdebug 配置如下:

xdebug.idekey = phpstorm
xdebug.remote_enable = on
xdebug.remote_connect_back = on
xdebug.remote_port = 9001        //PhpStorm监听本地9001端口
xdebug.remote_handler = dbgp
xdebug.remote_log = /home/tmp/xdebug.log

开始收集问题详细表述。首先,观察到 PhpStorm 的 Debug 控制台出现状态:

Waiting for incoming connection with ide key ***

然后查看 Xdebug 调试日志xdebug.log,存在如下错误:

I: Checking remote connect back address.
I: Checking header "HTTP_X_FORWARDED_FOR".
I: Checking header "REMOTE_ADDR".
I: Remote address found, connecting to 172.17.0.1:9001.
W: Creating socket for "172.17.0.1:9001", poll success, but error: Operation now in progress (29).
E: Could not connect to client. :-(
分析问题

查看这些问题表述,基本上可以定位为 Xdebug 和 PhpStorm 之间的 网络通信 问题,接下来一步步定位具体问题。

排查本地9001端口

Win 下执行 netstat -ant命令:

协议    本地地址       外部地址        状态           卸载状态
TCP  0.0.0.0:9001   0.0.0.0:0     LISTENING       InHost

端口 9001 监听正常,然后在容器中使用 telnet 尝试同本地 9001 端口建立 TCP 连接:

$ telnet 192.168.1.101 9001

Trying 192.168.1.101...
Connected to 192.168.1.101.
Escape character is "^]".

说明容器同本地 9001 建立 TCP 连接正常,但是 Xdebug 为什么会报连接失败呢?此时,至少可以排除不会是因为 PhpStorm 端配置的问题。

排查Xdebug问题

回过头来看看 Xdebug 的错误日志,注意观察到失败时的连接信息:

I: Remote address found, connecting to 172.17.0.1:9001.
W: Creating socket for "172.17.0.1:9001", poll success, but error: Operation now in progress (29).
E: Could not connect to client. :-(

此时,在容器中使用 tcpdump 截获的数据包如下:

$ tcpdump -nnA port 9001
# 尝试建立连接,但是失败了
12:20:34.318080 IP 172.17.0.2.40720 > 172.17.0.1.9001: Flags [S], seq 2365657644, win 29200, options [mss 1460,sackOK,TS val 833443 ecr 0,nop,wscale 7], length 0
E..<..@.@.=...........#)...,......r.XT.........
............
12:20:34.318123 IP 172.17.0.1.9001 > 172.17.0.2.40720: Flags [R.], seq 0, ack 2365657645, win 0, length 0
E..(.]@.@..M........#).........-P....B..

可以确定的是, Xdebug 是向 IP 为 172.17.0.1 且端口为 9001 的目标机器尝试建立 TCP 连接,而非正确的 192.168.1.101 本地 IP。到底发生了什么?

首先,为了搞懂 Xdebug 和 PhpStorm 的交互过程,查了 官方手册 得知,Xdebug 工作在远程调试模式时,有两种工作方式:

1、IDE 所在机器 IP 确定/单人开发

图中,由于 IDE 的 IP 和监听端口都已知,所以 Xdebug 端可以很明确知道 DBGP 交互时 IDE 目标机器信息,所以 Xdebug 只需配置 xdebug.remote_host、xdebug.remote_port 即可。

2、IDE 所在机器 IP 未知/团队开发

由于 IDE 的 IP 未知或者 IDE 存在多个 ,那么 Xdebug 无法提前预知 DBGP 交互时的目标 IP,所以不能直接配置 xdebug.remote_host 项(remote_port 项可以确定),必须设置 xdebug.remote_connect_back 为 On 标识(会忽略 xdebug.remote_host 项)。这时,Xdebug 会优先获取 HTTP_X_FORWARDED_FOR 和 REMOTE_ADDR 中的一个值作为通信时 IDE 端的目标 IP,通过Xdebug.log记录可以确认。

I: Checking remote connect back address.
I: Checking header "HTTP_X_FORWARDED_FOR".
I: Checking header "REMOTE_ADDR".
I: Remote address found

接下来,可以知道 Xdebug 端是工作在远程调试的模式 2 上,Xdebug 会通过 HTTP_X_FORWARDED_FOR 和 REMOTE_ADDR 项获取目标机 IP。Docker 启动容器时已经做了 80 端口映射,忽略宿主机同 Docker 容器复杂的数据包转发规则,先截取容器 80 端口数据包:

$ tcpdump -nnA port 80
# 请求信息
13:30:07.017770 IP 172.17.0.1.33976 > 172.17.0.2.80: Flags [P.], seq 1:208, ack 1, win 229, options [nop,nop,TS val 1250713 ecr 1250713], length 207
E....=@.@..............P..    .+.......Y......
........GET /v2/room/list.json HTTP/1.1
Accept: */*
Cache-Control: no-cache
Host: localhost
Connection: Keep-Alive
User-Agent: Apache-HttpClient/4.5.2 (Java/1.8.0_152-release)
Accept-Encoding: gzip,deflate

可以看出,数据包的源地址为 172.17.0.1,并非真正的源地址 192.168.1.101,HTTP 请求头中也无 HTTP_X_FORWARDED_FOR 项。

说明:172.17.0.1 实际为 Docker 创建的虚拟网桥 docker0 的地址 ,也是所有容器的默认网关。Docker 网络通信方式默认为 Bridge 模式,通信时宿主机会对数据包进行 SNAT 转换,进而源地址变为 docker0,那么,怎么在 Docker 里获取客户端真正 IP 呢?。
定位根源

最后,可以确定由于 HTTP_X_FORWARDED_FOR 未定义,因此 Xdebug 会取 REMOTE_ADDR 为 IDE 的 IP,同时由于 Docker 特殊的网络转发规则,导致 REMOTE_ADDR 变更为网关 IP,所以 Xdebug 同 PhpStorm 进行 DBGP 交互会失败。

解决问题

由于 Docker 容器里获取真正客户端 IP 比较复杂,这里使用 Xdebug 的 远程模式 1 明确 IDE 端 IP 来规避源 IP 被修改的情况,最终解决 Xdebug 调试问题。

模式 1 的 Xdebug 主要配置为:

//并没有xdebug.remote_connect_back项
xdebug.idekey = phpstorm
xdebug.remote_enable = on
xdebug.remote_host = 192.168.1.101
xdebug.remote_port = 9001
xdebug.remote_handler = dbgp

重启 php-fpm,使用php --ri xdebug确定无误,使用 PhpStorm 重新进行调试。

再次在容器中 tcpdump 抓取 9001 端口数据包:

# 连接的源地址已经正确
14:05:27.379783 IP 172.17.0.2.44668 > 192.168.1.101.9001: Flags [S], seq 3444466556, win 29200, options [mss 1460,sackOK,TS val 1462749 ecr 0,nop,wscale 7], length 0
E..<2.@.@..........e.|#).Nc|......r.nO.........
..Q.........

再次使用 PhpStorm 的 REST Client 断点调试 API 时, Debug 控制台如下:

所以,使用 Xdebug 进行远程调试时,需要选择合适的调试模式,在 Docker 下建议使用远程模式 1。

其他注意事项

Xdebug 版本和 PHP 版本一致

并不是每个 Xdebug 版本都适配 PHP 每个版本,可以直接使用 官方工具,选择合适的 Xdebug 版本。

本地文件和远端文件映射关系

如上图,在使用 PhpStorm 时进行远程调试时,需要配置本地文件和远端文件的目录映射关系,这样 IDE 才能根据 Xdebug 传递的当前执行文件路径与本地文件做匹配,实现断点调试和单步调试等。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/27628.html

相关文章

  • Docker使用Xdebug

    摘要:说明开发和调试环境为本地中的,环境为本地下的。再次在容器中抓取端口数据包连接的源地址已经正确再次使用的断点调试时,控制台如下所以,使用进行远程调试时,需要选择合适的调试模式,在下建议使用远程模式。 首发于 樊浩柏科学院 我们经常会使用 PhpStorm 结合 Xdebug 进行代码断点调试,这样能追踪程序执行流程,方便调试代码和发现潜在问题。博主将开发环境迁入 Docker 后,Xd...

    pakolagij 评论0 收藏0
  • PhpStorm连接docker容器内的php XDebug进行断点调试

    摘要:连接容器内的进行断点调试进行断点调试尽管不像其他语言那样方便,但是有些是有确实有其用处,比如调试循环内的数据异常时。 PhpStorm连接容器内的XDebug进行断点调试 php进行断点调试尽管不像其他语言那样方便,但是有些是有确实有其用处,比如调试循环内的数据异常时。在php于phpstorm都安装在同一环境下时,配置phpstorm的xdebug调试并不是多困难的事情,但是如果你使...

    XGBCCC 评论0 收藏0
  • dockerphp xdebug调试开发

    摘要:这样就配置好了安装插件监听地址开启小电话以后,如果访问会自动进入断点中的模式,这样我们的开发环境的断点调试就已经配置好了。 docker-compose环境来自:https://github.com/zhaojunlik...原文:http://blog.oeynet.com/post/9... 说明 在开发中,断点调试是我们最快能找出Bug代码问题的所在,那么在docker中如何使用...

    import. 评论0 收藏0
  • dockerphp xdebug调试开发

    摘要:这样就配置好了安装插件监听地址开启小电话以后,如果访问会自动进入断点中的模式,这样我们的开发环境的断点调试就已经配置好了。 docker-compose环境来自:https://github.com/zhaojunlik...原文:http://blog.oeynet.com/post/9... 说明 在开发中,断点调试是我们最快能找出Bug代码问题的所在,那么在docker中如何使用...

    kyanag 评论0 收藏0
  • 推荐代码调试工具 Xdebug

    摘要:写代码总绕不过需要调试,除了外,我们还是需要借助进行调试。这里的使用,是分别整合到和下。安装还是基于神级武器。至于下一步如何更好的使用,就看各自的实际项目和开发需要了。 写代码总绕不过需要调试,除了 UnitTest 外,我们还是需要借助 Xdebug 进行调试。 所以今天来说说如何基于本地 Docker 环境下,使用 Xdebug。 这里的使用,是分别整合到 VS Code 和 PH...

    MartinHan 评论0 收藏0

发表评论

0条评论

jerry

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<