Use Xdebug in phpstorm to connect to Docker

We often use PhpStorm combined with Xdebug for code breakpoint debugging, so that we can track the program execution process, facilitate code debugging and find potential problems. After the blogger moved the development environment to Docker, Xdebug debugging encountered some problems. Here are the methods and precautions for using Xdebug in Docker. php

Note: The development and debugging environment is LNMP in the local Docker, and the IDE environment is PhpStorm under the local Win10. In this situation, Xdebug belongs to the remote debugging mode, the IDE and local IP are 192.168.1.101, and the LNMP container IP in Docker is 172.17.0.2.

Problem Description

After installing and configuring Xdebug in Docker, and setting the corresponding Debug parameters in PhpStorm, Debug does not work normally.

At this point, php.inithe Xdebug configuration is as follows: git

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

Start collecting detailed statements of the problem. First, observe the status of PhpStorm's Debug console: github

Waiting for incoming connection with ide key ***

Then check the Xdebug debug log xdebug.log, there is the following error: docker

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. :-(

analyse problem

Looking at these problem expressions, you can basically locate a network communication  problem between Xdebug and PhpStorm  , and then locate the specific problem step by step.

Check the local 9001 port

Execute netstat -antcommand under Win  : network

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

Port 9001 is listening normally, and then use telnet in the container to try to create a TCP link with the local port 9001: phpstorm

$ telnet 192.168.1.101 9001

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

It means that it is normal to create a TCP link between the container and the local 9001, but why does Xdebug report the link failure? At this point, at least it can be ruled out that the problem will not be due to the PhpStorm side configuration. socket

Troubleshoot Xdebug issues

Looking back at the error log of Xdebug, pay attention to the link information when the failure is observed: tcp

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. :-(

At this time, the data packets intercepted by tcpdump in the container are as follows:

$ 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..(.]@[email protected]........#).........-P....B..

To be sure, Xdebug is trying to create a TCP link to the target machine with IP 172.17.0.1 and port 9001, instead of the correct local IP of 192.168.1.101. In the end what happened?

First of all, in order to understand the interaction process between Xdebug and PhpStorm, I checked the  official manual and  learned that when Xdebug works in remote debugging mode, there are two working methods:

1. The IP of the machine where the IDE is located/single-person development

In the figure, because the IDE's IP and listening port are known, the Xdebug side can clearly know the IDE target machine information during DBGP interaction, so Xdebug only needs to configure  xdebug.remote_host and xdebug.remote_port  .

2. The IP of the machine where the IDE is located is unknown/team development

Because the IDE's IP is unknown or there are multiple IDEs, Xdebug cannot predict the target IP of DBGP interaction in advance. Therefore, you cannot directly configure the xdebug.remote_host item (remote_port can be confirmed). You must set  xdebug.remote_connect_back  to the On flag (it will be ignored). xdebug.remote_host item). At this time, Xdebug will first obtain one of  HTTP_X_FORWARDED_FOR  and  REMOTE_ADDR  as the target IP of the IDE during communication, which Xdebug.logcan be confirmed by recording.

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

Next, you can know that the Xdebug end is working in remote debugging mode 2. Xdebug will obtain the target machine IP through the HTTP_X_FORWARDED_FOR and REMOTE_ADDR items. When Docker starts the container, port 80 has been mapped, ignoring the complicated packet forwarding rules between the host and the Docker container, and intercepting the container's port 80 packets first:

$ 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....=@[email protected]..    .+.......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

It can be seen that the source address of the data packet is  172.17.0.1 , not the real source address 192.168.1.101, and there is no HTTP_X_FORWARDED_FOR item in the HTTP request header.

Note: The address of 172.17.0.1, the virtual bridge docker0 actually established for Docker, is also the default gateway of all containers. The Docker network communication method defaults to the Bridge mode. During communication, the host will perform SNAT conversion on the data packet, and the source address will become docker0. Then,  how to get the real IP of the client in Docker? .

Locate the root cause

Finally, it is certain that because HTTP_X_FORWARDED_FOR is not defined, Xdebug will take REMOTE_ADDR as the IP of the IDE. At the same time, because of Docker's special network forwarding rules, REMOTE_ADDR is changed to the gateway IP. Therefore, the DBGP interaction between Xdebug and PhpStorm will fail.

Solve the problem

Because it is more complicated to obtain the real client IP in the Docker container, here we use Xdebug's  remote mode 1 to  clarify the IDE IP to avoid the source IP being modified and finally solve the Xdebug debugging problem.

The main configuration of Xdebug in mode 1:

//并无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

Restart php-fpm, use php --ri xdebugit correctly, use PhpStorm to debug again.

Capture the 9001 port data packet in the container again by tcpdump:

# 链接的源地址已经正确
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.@[email protected].|#).Nc|......r.nO.........
..Q.........

When using PhpStorm's REST Client breakpoint debugging API again, the Debug console is as follows:

Therefore, when using Xdebug for remote debugging, you need to choose a suitable debugging mode. It is recommended to use remote mode 1 under Docker.

Other notes

  • Xdebug version is the same as PHP version

Not every version of Xdebug is adapted to every version of PHP. You can directly use  official tools to select the appropriate version of Xdebug.

  • Mapping between local files and remote files

As shown in the figure above, when using PhpStorm for remote debugging, it is necessary to configure the directory mapping relationship between local files and remote files, so that the IDE can match the current executable file path passed by Xdebug with the local file to achieve breakpoint debugging and single-step debugging Wait.

Guess you like

Origin blog.csdn.net/JineD/article/details/111477301