Skip to content

微服务访问报 No route to host:一次 firewalld 端口未放行问题排查

一、问题背景

环境中存在两台 ECS:

  • 机器 A

    • 公网 IP:114.xx.xx.xx
    • 内网 IP:172.16.0.41
  • 机器 B

    • 公网 IP:47.xx.xx.xx
    • 内网 IP:172.16.0.42

部署服务及端口:

  • gateway:8080
  • oa-global:9206
  • oa-system:9202

请求流程:

text
浏览器

gateway

通过 Nacos 获取服务内网 IP

转发至目标微服务

二、问题现象

1. gateway 日志报错

两台机器上的 gateway 在跨节点访问 oa-global 时均出现:

text
No route to host 172.16.0.xx:9206

例如:

  • 172.16.0.41 上的 gateway 访问 172.16.0.42:9206 失败
  • 172.16.0.42 上的 gateway 访问 172.16.0.41:9206 失败

2. 本机访问正常,跨机器访问失败

表现为:

  • gateway 访问本机服务端口正常
  • gateway 访问另一台机器相同服务端口失败

3. 对比端口连通性

对两个服务端口进行对比:

  • 9202(oa-system):两台机器互通
  • 9206(oa-global):两台机器互不通

说明两台 ECS 之间的内网并非整体不通,问题更可能集中在 9206 端口。

4. telnet 验证

分别执行:

bash
telnet 172.16.0.41 9206
telnet 172.16.0.42 9206

均返回:

text
No route to host

公网 IP 的 92029206 均未开放,本次服务间通信本身使用的是 ECS 内网地址,因此继续从内网端口连通性方向排查。

三、为什么防火墙问题会表现为 No route to host

看到:

text
No route to host

很容易第一时间理解为:

当前机器没有到目标 IP 的网络路由。

但这个错误并不只会在“真的没有路由”时出现。

Linux 应用通过 Socket 建立 TCP 连接时,底层网络错误最终会以 errno 的形式返回给应用程序。No route to host 通常对应:

text
EHOSTUNREACH

即:

text
Host is unreachable

真正的“没有路由”确实可能产生这个错误,例如:

  • 路由表中没有到目标网络的路由
  • 网关不可达
  • 网络设备无法找到目标主机

但防火墙主动拒绝连接时,也可能产生相同的上层表现。

例如目标服务器上的防火墙规则并不是简单地丢弃数据包,而是使用 REJECT 拒绝请求。此时防火墙可能向请求方返回 ICMP 错误报文。

请求方的 Linux 网络栈收到这类 ICMP 错误后,会把它转换成 Socket 层错误,应用最终就可能看到:

text
No route to host

因此:

text
No route to host

不能简单理解成:

text
一定是路由表有问题

更准确的理解应该是:

当前 TCP 连接无法到达目标主机或目标网络,具体原因还需要继续判断。

在实际排查中,可以结合现象快速缩小范围。

本次问题中:

  • 172.16.0.41172.16.0.42 之间其他端口可以正常通信
  • 9202 可以跨机器访问
  • 只有 9206 无法访问
  • 9206 服务本身已经正常监听
  • 两台机器的 firewalld 都处于启用状态

因此基本可以排除“两台机器之间不存在路由”的可能。

如果真的是 ECS 内网路由问题,那么通常不会只影响:

text
9206

而:

text
9202

却可以正常访问。

这种“同一目标 IP,部分端口正常、部分端口报 No route to host”的现象,应该优先检查:

  1. 主机防火墙
  2. 云安全组
  3. 网络 ACL
  4. 服务监听地址

而不是首先修改系统路由表。

本次最终确认,原因就是目标节点的 firewalld 未放行:

text
9206/tcp

四、排查过程

1. 确认服务监听状态

执行:

bash
ss -lntp | grep 9206

两台机器均确认 Java 进程已经监听 9206 端口。

这里除了确认进程存在,还需要关注具体监听地址。

如果服务只监听:

text
127.0.0.1:9206

那么即使防火墙已经放行,其他机器仍然无法访问。

跨主机提供服务时,通常应该监听类似:

text
0.0.0.0:9206

或者直接监听对应的内网地址。

本次环境中的服务监听正常,因此继续排查主机网络策略。

2. 确认 firewalld 状态

执行:

bash
systemctl status firewalld

两台机器的 firewalld 均处于 active 状态。

3. 确认当前活动 zone

在修改防火墙规则之前,可以先执行:

bash
firewall-cmd --get-active-zones

确认网卡实际使用的 zone。

本次环境使用的是 public zone。

4. 对比防火墙端口放行情况

分别执行:

bash
firewall-cmd --zone=public --list-ports

机器 A 未发现:

text
9206/tcp

机器 B 同样未发现:

text
9206/tcp

此时基本可以确认,oa-global 服务虽然已经正常监听 9206,但两台机器的 firewalld 都没有允许其他节点访问该端口。

五、根因

两台 ECS 上的 oa-global 均正常监听 9206 端口,但 firewalld 没有放行 9206/tcp

因此:

  • 本机访问不经过跨主机网络入口,可以正常访问
  • 跨节点访问目标机器的 9206 时,被目标机器的防火墙规则拒绝
  • gateway 最终表现为:
text
No route to host

需要注意的是:

No route to host 并不一定意味着 Linux 路由表真的不存在目标路由。

在某些防火墙拒绝连接的场景中,客户端同样可能收到类似 No route to host 的错误,因此不能只根据错误文本直接判断为路由故障。

六、解决方案

在两台机器上分别放行 oa-global 使用的 9206/tcp

以下命令假设对应网卡使用的是 public zone:

bash
firewall-cmd --zone=public --add-port=9206/tcp --permanent
firewall-cmd --reload

执行后再次确认:

bash
firewall-cmd --zone=public --list-ports

应能够看到:

text
9206/tcp

七、验证结果

重新测试:

bash
telnet 172.16.0.41 9206
telnet 172.16.0.42 9206

结果均恢复正常。

同时:

  • gateway 跨节点访问恢复
  • oa-global 调用正常
  • 日志中不再出现 No route to host

八、经验总结

这次问题的特点是:

本机访问正常,但相同服务跨机器访问失败。

遇到类似现象时,可以依次确认:

  1. 服务进程是否正常运行
  2. 服务是否监听在正确地址,而不是仅监听 127.0.0.1
  3. 目标端口是否被主机防火墙放行
  4. 云平台安全组是否允许对应流量
  5. 网络 ACL、路由等更底层网络策略是否存在限制

另外,同一组微服务节点的防火墙规则应尽量保持一致,否则很容易出现:

text
A → B 正常
B → A 失败

或者不同服务端口表现不一致的问题。

九、改进建议

  • 使用自动化脚本统一维护各节点防火墙规则
  • 定期巡检节点的 firewalld 配置,避免配置漂移
  • 在服务上线 checklist 中增加端口连通性检查
  • 新增服务端口时,同时确认监听地址、主机防火墙和云安全组配置