php를 다시 만져야 할 일이 있었고, 당연히 디버거를 써야 할 일도 있었다. 모오던 웹개발에는 윈도우보다는 리눅스가 여러 모로 편리하기 때문에 WSL2를 애용하게 되는데, 언제나 리모트 디버그일수밖에 없는 php는 환경 세팅이 문제다.
개발환경 구성
- php를 로컬에 깔고 싶지는 않으므로 컨테이너를 쓴다.
- windows에서 컨테이너를 쓰자면 당연(?)하게도 Docker desktop을 쓴다.
- 코드는 컨테이너 밖에 클론 받아 놓고 vscode WSL 모드로 편집을 하려고 한다.
이렇게 괴악한 구성을 해 놓고 별 생각 없이 다음과 같이 디버거를 설정하면 어떤 일이 일어나는가?
xdebug.remote_host=docker.host.internal
xdebug.remote_port=7999
# ...
xdebug.remote_log=/tmp/xdebug.log
{
"version": "0.2.0",
"configurations": [
{
"name": "Listen for XDebug",
"type": "php",
"request": "launch",
"port": 7999,
"hostname": "0.0.0.0",
"pathMappings": {
"/app": "${workspaceRoot}/app"
},
}
]
}
Huston, we have a problem..
Docker desktop은 docker.host.internal이 윈도우를 가리키도록 구성한다. 한편, WSL 안에 클론받은 코드베이스에서 code .
로 실행한 vscode에서 디버그를 시작한다. 그러면 포트는 윈도우가 아니라 리눅스 쪽에서 열린다.
$ netstat -nat | grep 7999
tcp 0 0 0.0.0.0:7999 0.0.0.0:* LISTEN
그러니 xdebug의 로그는 이렇게 된다.
I: Connecting to configured address/port: host.docker.internal:7999.
W: Creating socket for 'host.docker.internal:7999', poll success, but error: Operation in progress (29).
E: Could not connect to client. :-(
어떻게든 리눅스 안으로 트래픽을 넣으려고 wsl의 ip address
를 remote_host로 지정해 보았으나 뜻대로 되지 않았고, 비슷한 사례가 WSL github에 이슈로 제기된 것도 보인다. 단순하게 생각하면 도커의 bridge network을 타고 나오는데 wsl에 바로 붙지 못할 이유가 없어 보인다. 그런데 당장 급한 건 이 의문을 해결하는 것 보다 디버거가 동작하게 만드는 것이었으므로 꼼수를 찾다가 stackoverflow에서 이런 아이디어를 보았다.
PS C:\WINDOWS\system32> netsh interface portproxy add v4tov4 listenport=7999 listenaddress=0.0.0.0 connectport=7999 connectaddress={{wsl IP 주소}}
윈도우가 0.0.0.0:7999를 받고 wsl 쪽으로 프록시를 만들어주는 구성이다. (powershell은 관리자 권한으로 실행)
PS C:\WINDOWS\system32> netsh interface portproxy show all
ipv4 수신 대기: ipv4에 연결:
주소 포트 주소 포트
--------------- ---------- --------------- ----------
0.0.0.0 7999 ***.**.***.*** 7999
netsh 구성을 살펴보면
xdebug와 vscode 디버거는 의도대로 브레이크포인트에 멈춰 섰고 컨텍스트를 이상 없이 표시했다. 이로서 한 건 해결.. 은 아니고 이제 디버그를 시작할 수 있게 되었다..
// todo:
- wsl2라는 특수한 환경 떄문에 docker network이 아는 바대로 잘 동작하지 않는 경우가 많다.
- 왜 이 문제가 발생했는지 알아내는 것은 향후의 과제로 삼기로 하자.