业务架构:前端
部署细节:
两容器均部署在同一机器上,经过 docker-compose
编排,而且经过link
方式连接。node
在有次更新代码时,发现前端可以打开,可是全部接口请求全是502(Bad GateWay)
python
查看前端容器compose_ui_1
的日志,刷了一大波502(Bad GateWay)
nginx
UI没问题的话,第一反映就是 compose_api_1
跪了,因此直接去容器看看日志docker
容器日志看起来很正常,没有崩溃,并且这个日志就好像历来没收到请求那样,可是很明显我前端确定有访问的,感受很奇怪。将接口取出来单独访问试试看:flask
接口单独访问结果仍是很残暴的502(Bad GateWay)
,感受仍是不太可信,是否是端口或者主机什么访问错误了?
本机开启 wireshark 抓包确认下请求的主机和端口:segmentfault
这样就很确保前端compose_ui_1
访问的主机和端口是正确的,并且确切结果是502(Bad GateWay)
,这样只能从compose_api_1
下手排查了。后端
以前也是遇到类似的问题,由于compose_api_1
是经过uwsgi
部署的python flask
,那会老是用法以为有点问题,改过uwsgi
配置以后消停了一会。如今又卷土重来了。api
先判断下compose_api_1
是否是真的跪了。。。虽然对这个没抱什么但愿。。。缓存
直接访问 后端api 接口
额。。。尴尬。。。仿佛冤枉错好人了。这不对吧,抓包看看再次确认下先:
仿佛真的是。。。再 see see 容器日志:
额。。。好吧。。。我错了,compose_api_1
没跪。
因而问题来了。。。后端接口没问题,前端访问出错了,见鬼了?
有种预感是容器的特性致使的问题。希望不要。。
先进去compose_ui_1
容器抓包分析下,看看整个请求链有没有问题:
彷佛发现了点猫腻,Flags[R.]
是表明 tcp连接 被 reset
重置 了,可是为何无缘无故重置呢?
看到 172.17.0.5.8080
返回的, 先 telnet
问问先:
What???这就很迷了,首先这个 172.17.0.5.8080
哪来的呢?其次就是为毛端口不通?
忽然想到一个很重要的问题:
容器之间是怎么知道它要把请求发给谁呢 ?
在前面已经交代过,这两个容器是经过 link
的方式连接的,像下面这样:
谷歌搜了下 link
工做原理:
link机制经过环境变量的方式提供了这些信息,除此以外像db的密码这些信息也会经过环境变量提供,docker将source container中定义的环境变量所有导入到received container中,在received container中能够经过环境变量来获取链接信息。 使用了link机制后,能够经过指定的名字来和目标容器通讯,这实际上是经过给/etc/hosts中加入名称和IP的解析关系来实现的
因此就是说在 compose_ui_1
的 根据指定的名字并在 /etc/hosts
翻译出具体的ip而后进行通讯咯?
看看容器的名字是啥?
compose_ui_1
的 /etc/hosts
root@e23430ed1ed7:/# cat /etc/hosts 127.0.0.1 localhost ::1 localhost ip6-localhost ip6-loopback fe00::0 ip6-localnet ff00::0 ip6-mcastprefix ff02::1 ip6-allnodes ff02::2 ip6-allrouters 172.17.0.4 detectapi fc1537d83fdf compose_api_1 172.17.0.3 authapi ff83f8e3adf2 compose_authapi_1 172.17.0.3 authapi_1 ff83f8e3adf2 compose_authapi_1 172.17.0.3 compose_authapi_1 ff83f8e3adf2 172.17.0.4 api_1 fc1537d83fdf compose_api_1 172.17.0.4 compose_api_1 fc1537d83fdf 172.17.0.6 e23430ed1ed7
若是真是按照资料所说,那 172.17.0.4:8080
才是 compose_api_1
的地址隐射才对吧?,试下先
虽然返回了 auth product is None
,但其实这是有效的请求。
再看看 compose_api_1
容器的日志:
因此基本没跑了, 为何前端访问直接就是 502, 缘由就是 ui容器向错误的地址发送请求了
那么为何会这样呢?无缘无故抽风了?
刚才根据 host 的记录实验了,按照它的映地址发起接口请求,是没有问题的:
查看下 compose_ui_1
的 nginx
日志
尴尬。。。 nginx
日志竟然直接链接到标准输出和标准错误。。。
那为了简单点,仍是直接用 docker logs 查看吧
看来 nginx
的转发已是错误的,为何会转发到 172.17.0.5, 看看 nginx
关于转发的配置:
这个 detectapi
和 上面贴出的 hosts
表能找到正确的地址 172.17.0.4
呀?搞不明白为何会转发到 172.17.0.5
难道是系统的域名解析错误了?
尼玛这真是太神奇了。
男人的直觉告诉我 nginx
有猫腻!
重启下容器的 nginx
,然而容器也被重启了。。。
再访问页面,竟然能够了。。。
再看看容器的nginx日志,已经转发成功了
这样子的话,其实应该能定位到,问题是出在了 nginx 上面?
只是为何 nginx
会有这样的错误呢?不太应该呀。。 感受应该是 nginx
内部域名解析缓存问题。
而后查了下资料,呵呵,还真有。https://www.zhihu.com/questio...
这就很是尴尬了。对这个问题抱有点怀疑,咨询了资深大佬,而后大佬的回复就是:
若是 proxy_pass 后面跟的域名的话,在 nginx 启动的时候就会初始化好,之后就只会复用这个值;参考:ngx_http_upstream_init_round_robin 函数 若是 proxy_pass 后面跟的是upstream,配置才会走解析和缓存的逻辑;
proxy_pass
真实域名,而是转发到 upstream
配置;compose_ui_1
指定的 compose_api_1
会出错?proxy_pass
若是后面跟真实域名,是真的直接复用仍是有时间缓存?原本想用 gdb
调试下这个问题,然而花了一天时间,毛都没有。不过也有点小收获,那就是如何配置nginx
来支持gdb
:
1.修改编译配置文件:auto/cc/conf
ngx_compile_opt="-c" 改为 ngx_compile_opt="-c -g"
2../configure
时,增长编译参数:--with-cc-opt='-O0'
, 避免编译器优化;
例如:./configure --prefix=/usr/local/nginx --with-cc-opt='-O0' ....
若是不这样的话,编译器会优化代码,致使调试过程当中,循环中的一些变量值没法打印,会报下面的错误:
value optimized out
下面能够看下调试的效果:
nginx worker process 处理入口:ngx_http_static_handler
欢迎各位大神指点交流, QQ讨论群: 258498217
转载请注明来源: https://segmentfault.com/a/11...