bookmark_border无断点,不编程

我对开发环境的基本要求之一是可以下断点单步调试。这很基础,却很重要。

代码自动补全和断点调试功能二选一?
我选断点。

点击函数或变量自动跳转到声明处和断点调试功能二选一?
我选断点。

静态类型推导,编译时类型检查和断点调试功能二选一?
嗯,是个难题。

这样讲应该足以解释断点调试能力在我心中的地位了吧。

为什么突然想起说这件事呢,是因为昨天晚上我为了给我的 php 开发环境安装 xdebug 折腾了一宿,有感而发了。

按说给 php 安 xdebug 能有多难呢?确实不难,我在公司和个人环境里也安过很多次了,基本没遇到过太大困难。可昨天的情况比较特殊,甚至堪称极端,真的是把一个简单的问题拔高到了面试题的水平。

事情的起因是,我想在元旦假期里学习一下 laravel。最新的 laravel 框架要求 php 版本在 7.2 以上,外加一些其他的依赖项。我这个博客是运行在一个 web hosting 服务器上的,想动服务器配置并不容易。我常用的 vps 是朋友买的,我本身是借宿在那里,也不想太破坏他的环境。最终我选择在 vps 上用 docker 实现一个满足 laravel 要求的开发环境,而这正是噩梦的开始。

在 docker 里跑 php,这个 php container 暴露给外界访问的端口就不能是 80 了。假设暴露给外界访问的端口是 8080,我访问这个 docker 内的 php 文件的方式就是 http://my.vps:8080/path/to/file ,看起来有点丑不是么。为了美化这个 url,我修改了 vps 本机的 apache 设置,给这个 8080 端口配置了一个转发用的子目录 docker,这样我可以通过 http://my.vps/docker/path/to/file 的 url 来访问 docker。怎么样,好看多了吧,哈哈!

到这一步做完,我才开始配置 xdebug,而这时,我的 IDE 和目标 php 服务之间已经隔了两层了。

 

冷静!仔细想想,就算不给 apache 配置 ProxyPass,它到 php 之间也是会隔一层的呀,所以这不算是增加难度。呃,但是算上 ProxyPassReverse 设置,我的 http header 在中间被改来改去的,还是增加了不稳定因素。反正先试试再说吧。

一试果然不行,连不通。

那就不着急了,先从头捋一遍通信流程吧。附上我最喜欢的 xdebug 通信流程图。

看样子浏览器到 php/Xdebug 这部分通信时没问题的,问题出在 xdebug 想回拨给我的时候。

查了一下,我用的 PhpStorm 的文档里有远程调试 php 时的指导方案

ssh -R 9000:localhost:9000 username@hostname

思路是让 xdebug 回拨的时候访问服务器端的 9000 端口,同时把服务器端的 9000 端口反向代理到我的 PhpStorm 所在本地主机的 9000 端口,这样服务器端 xdebug 的回拨可以最终被在本地监听 9000 端口的 PhpStorm 接收到,很合理。

不过我的环境里还涉及到了 docker,怎么让 docker 容器内的 xdebug 的连接请求转发到外部宿主上呢?因为我是用 docker-compose 创建的 docker,所以我首先尝试用 docker-compose 自带的 container 到主机的端口映射方法

ports:
  - 9000:9000

结果在 docker 启动时 ssh 的反向代理无法绑定到服务器端的 9000 端口,这招不行。为了确认原因,我在 docker 容器内和宿主服务器上分别用 tcpdump 测试 9000 端口上的通信内容。结果显示 docker 容器内的 9000 端口上确实有通信,但宿主服务器的 9000 端口上没有任何通信。看来 docker-compose 的 ports 是专门用来让宿主访问容器使用的,反过来行不通。

sudo tcpdump -i any port 9000

我知道 mac 版的 docker 容器访问宿主 ip 有一个 docker.for.mac.localhost 的 hostname ,但是在 linux 环境里对应的 host.docker.internal 不知道为什么没有被定义。

算了暴力点直接拿 ip 吧!我在 docker 里做了一个显示请求方 ip 的 php 页面,类似于下面这样:

<?php
echo $_SERVER[REMOTE_ADDR];

取到的 ip 是 172.19.0.1 。之后反复重启 docker 试了几次,ip 没变,应该是问题不大了,就它吧。

用这个配置测了一下,结果 PhpStorem 还是连不上 xdebug。。什么情况!

用 tcpdump 看了一下远端宿主服务器的 9000 端口已经有流量了,但本地用 wireshark 却看不到本机 9000 端口上的流量。PhpStorm 行不行啊,有没有在监听 9000 哦?用 360 流量防火墙看了一下,确实启用 PhpStorm 的监听模式后程序会开始监听 9000 端口,关闭监听模式后程序对 9000 端口的监听也会停止。

会不会是 PhpStorm 没听懂呢?下一个 xdebug 的命令行客户端试了试,没反应。行不行啊?又下了个 linux 版的在服务器上执行 ./dbgpClient -p 9000 ,能收到 xdebug 的回拨,进入调试状态。看来问题出在服务器的通信没有转发给我的本地主机。

为什么呢?没头绪啊。。敲个 sudo netstat -natpl | grep 9000 研究了一下,看到 127.0.0.1:9000 这里突然想起来,ssh 的反向代理默认只接受来自本地的通信,docker-compose 的容器默认是创建一个独立的内网 ip 用来通信的,反正不是 127.0.0.1 。会不会因为这个,所以 ssh 的反向代理没有受理来自 docker 的通信?

google 了一下,修改 ssh 的设置为 GatewayPorts clientspecified 可以让客户端决定服务器端绑定的端口可以接收来自哪些 ip 的通信。于是打开 ssh 配置文件,发现没有 GatewayPorts 的设置,那更好,直接添加在文件末尾,然后重启 ssh 服务。

 sudo vi /etc/ssh/sshd_config
 sudo systemctl restart ssh.service

之后在本地主机上重新执行 ssh 反向代理,这次要设置为允许接收来自外部 ip 的通信:

 ssh -R 0.0.0.0:9000:localhost:9000 username@hostname

这次,终于调通了。

下面是技术总结(太累了就贴张图吧 orz):

补充:

1. 为什么我在本地的 window 主机上可以使用 ssh 命令?
因为用的 Cygwin

2. 对所有 ip 开放端口访问会不会有安全隐患?
确实。应该可以把最后的 0.0.0.0 改成 docker 容器的 ip,如果他有固定 ip 的话。不过我只会在自己需要调试 php 的时候才会创建这个反向代理,我没在用的时候这个安全隐患不存在,我在用的时候有其他人入侵这个端口应该相对比较容易察觉到。这里确实是防范意识不足,偷懒了。之后会采用更安全的连接方式的。

3. apache 的端口代理到子目录会影响 xdebug 调式吗?
不会。无论访问子目录还是直接访问端口,设置在 PhpStorm 里的断点都可以正确生效。

bookmark_border“冷漠” “冷血”还是“冷静”?

标题说的是我自己啦。

从小我就发现我没有别人那么容易兴奋,或者说不容易投入生活?

小时候的表现是和家属院儿里的小朋友一起踢球捉迷藏什么的大家开玩笑似的想耍赖的时候会找我评理,因为我比起胜负心,通常表现得更看重规则吧。

在学校里的表现是我从不使用哪怕本人也认可的有调侃或贬义的外号称呼别人,印象中没有开过别人包含调侃或贬义性质的玩笑,同样也很反感别人对我开这样的玩笑。

呃,这样看起来,似乎只是个不合群的人而已。但我还挺喜欢凑热闹的啊,离不合群还是有些距离的,算小透明吧。

到这里为止,似乎和冷漠冷血没什么关系,但在我看来这里的逻辑都是一样的。我内部处理事情的方式就是让事情符合一个我认可的道理。当这个道理是大多数人也认可的道理时,我就是冷静的,当这个“道理”不是一个主流正能量的观点时,我就是冷漠和冷血的。

比如我曾经在公司午休的时候和中国人同事严肃地分享我认为法律应该允许把小于一定年龄(比如2岁)的婴儿以动物对待的看法。其内在逻辑是,很多人因为意外怀孕生育打乱了自己的人生,不得不想方设法遗弃或杀死自己的孩子然后被发现毁掉人生。有的人家本身愿意养育一个孩子,但当孩子落地时自带了整个家庭倾家荡产也难以治愈的遗传疾病时,受限于法律无法放弃这个孩子重新孕育第二胎,结果整个家庭陷入绝望。牺牲了这些父母和他们的家庭所带来的,是这些婴儿的免死金牌。从公利的角度来讲,他们父母为社会带来的利益的期望远大于为了保护这些婴儿生存社会所付出的代价的期望。从私利的角度来讲,这个家庭放弃这些无法承受的婴儿是对他们最好的选择。完全放弃婴儿的权益也不合理,但婴儿的权益应该附属于他的监护人,类似于宠物。我的设想是,在婴儿未满2岁之前,可以赋予父母对婴儿的处置权,类似于对宠物的限制,不可以虐待,但条件符合的话允许安乐死或出让。对父母之外的人,只要父母要求,婴儿仍然享有人类级别的权利,被外人伤害可以追究伤害人类级别的责任。

这是对我而言可以自洽的道理,但看一起吃午饭的其他人的反应,这似乎并不是受大多数人认可的方案,可以归入冷血范畴了。

最近又开始考虑这个问题,因为我刷微博时发现自己对很多社会新闻并不能产生和下面主流评论一样的愤慨。尤其在经历过很多新闻反转之后,我对我的愤怒更加的谨慎使用了。

有些新闻的事实比较清楚,但属于我的价值观里可以接受其存在的部分,这时候看到评论里一致的批判就会感觉很孤独。我想象如果我有了另一半,我们的宗教政治历史观或者部分其他价值观不完全兼容(which 几乎必然会发生),那我们还能有一个温馨和睦稳定轻松的家庭生活吗?理想的相处方式是求同存异,比如我不相信宗教,但不介意她是基督徒。我不会强迫她接受世界是物理的之类的科学观点,只要她不会在明知我的理性价值观的前提下依然用非理性理由对我进行宗教劝诱。反正互相尊重对方的存在吧,只要不造成损失和伤害。比如我可以接受她信基督,但不能接受她信传销。