一、前情提要

本周值班,收到 oncall 反馈:

业务是 HTTP当初是http部署的,导致插件无法校验、无法正常使用。

希望我们配合,让原本的 http + ip 的蓝湖访问方式变更为 域名 + https。

通过沟通,我了解到对方可以使用前置 f5 暴露服务,http 代理转发我们的业务服务器,但是端口,不能使用 80 端口,也就是说只能能通:

app.domain.com:10000

这种地址访问。

虽然不理解为什么不直接使用简单的二级域名解析匹配,而是使用这种用户不友好的方式,但也表示理解。

离谱的是对方后面的要求,既要求 f5 的端口,也要求转发的后端服务的端口,我一度觉得是对方理解有误。

也就是说,你 f5 要用 10000 端口,我后端实际被转发的服务端口也需要给你改造成暴露 10000。

哪有代理自己需要限制端口还需要规定后端服务的端口也需要改造成与之一致的端口的,闻所未闻。

好在最后对方不知是幡然醒悟还是问了他人,自己尝试配置了 f5 后代理原本的后端服务端口,可以使用,没有限制😅

客户配好 f5 后,我这边是需要同步修改下业务配置的接收访问地址的。

随后,客户就提供了远程。


二、问题出现

接下来就是本次离奇问题的排查过程了。

以下ip为化ip(人有化名,ip就是化ip嘛)

首先先简单描述下架构:

  • 服务器 10.0.0.224、10.0.0.225 部署应用服务(docker)

  • 服务器 10.0.0.226 部署数据库和中间件服务(docker)

在执行这个很常规的工单的时候,我像往常一样,按照 sop 执行配置修改,接着应用重启(docker),由于架构的原因,两台应用服务器都要改,先处理了 10.0.0.224,这个时候奇怪的事情发生了:

web(某个业务微服务,这里简称 web)反复重启,无法运行,查看日志,发现是无法连接 es 的端口,这相当奇怪,毕竟我只是改了业务配置,完全没有动到中间件相关内容啊,为什么单纯重启服务容器会突然报错网络问题呢。

重启之前,至少服务是可以用的,重启一下,反而把服务搞挂了?

这就很奇怪,既然 es 挂了,重启就会去连 es,然后就会挂,那他怎么运行这么长时间的?

一看,运行时间 10 个月……

好吧,那也不对啊,重启到底为什么会去连 es 呢?看脚本,看代码,哦,启动会去同步 es 数据

接着我在 10.0.0.255 上也尝试重启同样的容器,结果是 正常的。那不对啊,他怎么会没问题

对比日志,确实只有 10.0.0.224 会报 ES 端口不通。

那我在 10.0.0.255 容器里手动执行同步脚本呢?哦,10.0.0.225也是有问题的,再尝试重启下10.0.0.225上的呢,果然也复现了,同样卡在ES,这才对嘛,至于为什么第一次重启他没同步并和10.0.0.224一样卡在ES,简单问了下业务同学,无关紧要,先不探究

秉承优先恢复使用的出发点,先不根因排查,优先尝试回滚(虽然这个时候还是带着疑问的)。

配置回滚后,还是不行,当然也在预期内,本身也没改动 es 的配置,回滚当然也无济于事。


三、问题排查

既然报 es 不通,先看 es 的暴露端口。

  • 容器内端口:9200

  • 宿主机端口:9222

那就在 10.0.0.224 上:

telnet 10.0.0.226 9222

看看通不通:

不通

那 6379、5432 呢?

→ 都通 😓

先和客户沟通,是否有网络限制,客户明确没有防火墙限制。

这时怀疑是否是 es 本身故障(容器状态正常),尝试重启,重启正常,10.0.0.226本机上 curl 下 es 的接口也正常。

那在 10.0.0.224 上呢:

curl -XGET --user esuser:passwoed 'http://localhost:9222/_cluster/health?pretty'

→ 不通,奇怪。

那就把 es 停了:

docker stop es

用 9222 起个其他服务试试通不通。

尝试:

python3 -m http.server 9222

没有 python3(内网环境,无法安装)。

再试 busybox:

busybox httpd -f -p 9222

也没有。

那就:

while true; do
  echo -e "HTTP/1.1 200 OK\n\nhello" | nc -l -p 9222;
done

可以了,这个时候已经可以看到 logstash 的请求了。

再尝试在 10.0.0.224 上 curl 一下,通。

telnet,也通。

四、问题解决

OK,这个时候整理下思路(问 AI),明确了问题不在 es 上、也不在宿主机端口上。

那就再看防火墙。

过了下中间件的 docker-compose 文件,发现其他都是用的 host 模式(network_mode: host),只有 es 是映射端口(bridge模式)。

netstat -lantp | grep 9222
netstat -lantp | grep 6379

确实:

  • es(9222)用的是 docker-proxy转发

  • redis(6379)是redis-server宿主机进程

再看防火墙:

iptables -L FORWARD -n -v
iptables -S FORWARD

结果:

Chain FORWARD (policy DROP)

这样问题就很清晰了:

阻止了跨节点流量

那就打开呗:

iptables -P FORWARD ACCEPT

再去 10.0.0.226 上愉快的 curl 一下,额 🤔,还是不行。

再整理下思路(问 AI)

排查宿主机 ipv4 转发策略

sysctl net.ipv4.ip_forward

结果:

net.ipv4.ip_forward = 0

果然是禁掉的

改为允许:

sysctl -w net.ipv4.ip_forward=1

再 curl,通了,es 网络问题解决,服务恢复。

最后再把本次工单的本职工作:访问方式变更,给做了,美美的交差去。


这次的踩坑也提醒了博主:在故障排查中,看似毫不相关的现象,也可能有意想不到的关联。排查问题时,还是始终要从问题本身出发,逐层剥离,才能真正找到根因。