“网络不通”不是一个根因,而是一个未经分层的现象:可能是网卡没有地址、路由选错、ARP/邻居解析失败、DNS 返回了错误地址、防火墙丢包、目标端口未监听、TLS 握手失败、HTTP 代理异常,也可能只是对端禁止 ICMP。ping、telnet、curl、traceroute 的价值不在于四条命令都跑一遍,而在于它们分别验证不同层次,并把故障边界逐步缩小。
本文以使用 systemd、iproute2 和常见 GNU/Linux 用户空间工具的服务器为例。所有尖括号内容都是占位符:<目标域名>、<目标IP>、<目标端口>、<网卡名>、<网关IP>、<服务名>、<命名空间> 分别替换为真实域名、解析后的地址、业务端口、出口接口、默认网关、systemd 单元和 Kubernetes namespace;<源IP>、<本机业务IP>、<客户端IP>、、 替换为对应角色的真实地址;、<容器名>、<已批准的调试镜像> 替换为集群中的真实对象;<目标网段CIDR> 和 <新网关IP> 替换为变更审批中的网段与下一跳。命令语法说明中的 <主机>、<域名>、、<端口> 也应替换为对应目标。IPv6 地址作为 URL 主机时必须用方括号包围,例如 https://[2001:10]:8443/。
任何根因结论都要有至少一条证据链。例如:“域名解析到预期 IP;ip route get 选择预期网卡;到网关的邻居解析正常;TCP SYN 重传且本机 nftables 计数器不增;同网段另一主机也失败”,这些证据才能支持把问题继续交给网络路径或对端。只凭 ping 失败就说“防火墙拦了”,不够。
排查前固定五个要素:源主机或 Pod、目标域名/IP、目标端口、传输协议、故障时间。再确认是所有来源都失败,还是单机失败;是所有端口失败,还是某个服务失败;是持续故障,还是偶发超时。没有这些边界,后续输出无法对照。
先记录时间、主机身份、内核和网络命名空间。容器里的 localhost、路由表和防火墙可能与宿主机完全不同。
bash
date --iso-8601=seconds hostnamectl uname -r systemd-detect-virt --container || true readlink /proc/self/ns/net
如果问题来自容器,应在发生故障的同一个网络命名空间执行测试。宿主机 curl 成功,只能说明宿主机路径正常,不能证明 Pod 的 DNS、NetworkPolicy、服务网格或源地址转换正常。
| 工具 | 主要验证对象 | 成功能证明 | 失败不能直接证明 |
|---|---|---|---|
ping |
ICMP Echo、往返时延、基本可达性 | 对端或中间设备回复 ICMP,双向路径在测试时可用 | TCP 端口一定关闭;对端宕机;DNS 一定异常 |
telnet |
TCP 建连,及可选的明文交互 | 到指定 IP:端口的三次握手成功 | TLS/HTTP 业务一定正常;UDP 正常 |
curl |
DNS、TCP、TLS、HTTP/应用响应 | 从 URL 到应用层的链路在指定条件下完成 |
ping 必须成功;所有客户端都正常 |
traceroute |
逐跳 TTL/Hop Limit 反馈 | 部分路径节点愿意返回超时报文 |
* 所在路由器一定丢业务包;显示路径必然对称 |
推荐顺序不是机械的。如果现象是“HTTPS 返回 502”,直接从 curl -v、服务日志和反向代理开始;如果目标 IP 都不知道,先查 DNS;如果本机没有默认路由,没必要先 traceroute 公网。
ip -br 适合快速浏览,ip -s link 给出错误和丢弃计数。虚拟机显示链路 UP 不代表云安全组正确,但链路 DOWN、没有地址或错误计数持续增长已经足以缩小范围。
bash
ip -br link ip -br address ip -s link show dev <网卡名> ethtool <网卡名> 2>/dev/null | grep -E 'Speed:|Duplex:|Link detected:' || true
物理机 Link detected: no 要检查网线、交换机端口、bond 成员和驱动;虚拟网卡可能不支持 ethtool 的全部字段。接口 RX dropped 增长可能发生在驱动、队列或协议栈,不应直接等同于外部链路丢包。
不要只看默认路由。策略路由、多个路由表、源地址选择和 VRF 都可能改变实际路径。ip route get 会按当前规则模拟一次路由查找。
bash
ip rule show ip route show table main ip route get <目标IP> ip route get <目标IP> from <源IP>
最后一条中的 <源IP> 替换为业务进程实际绑定或 SNAT 前的源地址。如果输出接口、下一跳或 src 与预期不同,先修路由/策略,不要靠 ping 的结果猜测。修改路由属于高风险操作,错误会中断远程连接;必须先保留现有配置、确认带外通道,并优先用临时路由灰度验证。
IPv4 的 ARP 和 IPv6 的 NDP 都通过邻居表呈现。到同网段目标或下一跳时,FAILED、长时间 INCOMPLETE 表明二层解析没有完成。
bash
ip neigh show dev <网卡名> ping -c 3 -W 1 <网关IP> ip neigh show to <网关IP> dev <网卡名>
网关可达而远端不可达,说明本机二层和至少到网关的路径正常;网关也不响应时仍需注意它可能禁 ICMP,可结合邻居状态和抓包判断。不要随意执行 ip neigh flush all,这会影响整机现有连接的邻居解析。若确需清理单条异常缓存,先确认目标和影响,只处理明确条目并在操作后验证。
ping <域名> 失败可能发生在 DNS 之前。先查看系统解析配置,再用系统解析器和指定 DNS 服务器对照。
bash
cat /etc/resolv.conf getent ahosts <目标域名> resolvectl query <目标域名> 2>/dev/null || true dig +time=2 +tries=1 <目标域名> A dig +time=2 +tries=1 <目标域名> AAAA
getent 走 Name Service Switch,更接近应用使用的系统解析行为;dig 默认直接查询 /etc/resolv.conf 指向的 DNS,不一定经过 nsswitch 中的 mDNS、LDAP 或本地缓存。使用 systemd-resolved 时,/etc/resolv.conf 可能指向本地 stub,resolvectl 可显示按接口分配的 DNS 和搜索域。
若怀疑某台 DNS 服务器,显式指定它:
bash
dig @ <目标域名> A +noall +answer +comments dig @ <目标域名> AAAA +noall +answer +comments dig +trace <目标域名>
dig +trace 从根开始迭代查询,可能被企业出口策略拦截,也不代表内部 split-horizon 解析路径;内网域名不要用它作唯一证据。DNS 成功的判断包括返回码、答案、TTL 和地址是否属于当前环境,而不是“有 IP 就算正常”。
先 ping IP,排除 DNS;再 ping 域名,观察它实际选择的地址族和地址。
bash
ping -c 4 -W 2 <目标IP> ping -4 -c 4 -W 2 <目标域名> ping -6 -c 4 -W 2 <目标域名>
在 iputils 版本中,-c 是发送次数,-W 是每个应答等待时间,通常以秒计;BusyBox 的选项语义可能不同,先运行 ping --help。分别强制 IPv4/IPv6 能发现“AAAA 可解析但 IPv6 出口不存在”这类双栈问题。
以下是示例输出,只展示判断方式,并非真实执行结果:
text
64 bytes from 192.0.2.20: icmp_seq=1 ttl=56 time=12.4 ms 4 packets transmitted, 4 received, 0% packet loss, time 3004ms rtt min/avg/max/mdev = 11.9/12.3/12.8/0.3 ms 成功说明目标对 ICMP Echo 作出响应,并且回程可达。TTL 可辅助发现路径变化,但不同操作系统初始 TTL 不同,不能仅凭接收 TTL 精确推断跳数或系统类型。短样本的 0% 丢包也不能证明高峰无抖动。
多网卡主机可能从错误出口发包。使用 -I 明确接口或源地址,与应用实际绑定方式对照。
bash
ping -I <网卡名> -c 4 -W 2 <目标IP> ping -I <源IP> -c 4 -W 2 <目标IP> ip route get <目标IP> from <源IP> 接口测试失败、默认测试成功,常见于该接口无可用路由、策略路由缺失、回程路由不对或源地址被上游过滤。结论需要路由查询和抓包支持。
小包通、大包超时,尤其是 TLS 握手或传输大响应卡住时,应检查路径 MTU。iputils 的 -M do 设置 IPv4 DF 并禁止本地分片,-s 是 ICMP 数据负载长度。以太网 MTU 1500 的 IPv4 ICMP 常用 1472 字节负载作为起点,因为还需 20 字节 IPv4 头和 8 字节 ICMP 头;IPv6 头长度不同。
bash
ping -4 -M do -s 1472 -c 3 -W 2 <目标IP> ping -4 -M do -s 1400 -c 3 -W 2 <目标IP> tracepath <目标IP> ip link show dev <网卡名> 若 1400 成功而 1472 失败,说明需要继续二分负载大小并调查隧道、VPN、云封装或 ICMP Fragmentation Needed 是否被过滤。不要立即把所有主机 MTU 改成 1400;修改 MTU 会影响整个接口上的连接。执行前必须确认路径范围、冗余和回滚值,先在灰度接口验证,操作后复测大包与业务 TLS。
常见结果应这样处理:
Name or service not known:先查 DNS/NSS,不是 ICMP 故障。Network is unreachable:本机没有匹配路由,先查地址、路由和策略。Destination Host Unreachable:看消息由本机、网关还是中间路由器发出;本机发出时常伴随邻居失败。mtr、接口计数和业务时段;ICMP 可能被限速,结果不一定代表 TCP 同等丢包。
虽然 nc 更适合自动化,telnet <主机> <端口> 仍是常见现场工具。它发起 TCP 连接,适合快速区分 timeout、refused 和 connected。不要用它测试 UDP,也不要在明文会话里输入密码、Token 或生产敏感数据。
bash
telnet <目标IP> <目标端口> 常见现象:
Connected to ...:TCP 三次握手已完成。按 Ctrl+] 进入 telnet 命令模式,再输入 quit 退出。Connection refused:通常收到 TCP RST,说明路径基本可达,但该地址端口未监听或防火墙主动拒绝。No route to host:可能是本机路由错误,也可能是防火墙返回了 ICMP prohibited,需结合 ip route get 与抓包。
自动化检查更推荐 netcat。不同实现(OpenBSD netcat、Nmap ncat、BusyBox nc)的选项存在差异,先执行 nc -h。
bash
nc -vz -w 3 <目标IP> <目标端口> timeout 5 bash -c '/<目标端口>'
第二条依赖 Bash 的 /dev/tcp 特性,不适用于 POSIX sh,也不给出完整诊断。两者都只验证 TCP,不验证 TLS 证书、HTTP 状态或响应内容。
如果有目标服务器权限,先看端口、绑定地址和进程。服务只绑定 127.0.0.1 时,本机访问成功、远端必然失败;只绑定 IPv6 是否同时接收 IPv4,取决于 net.ipv6.bindv6only 和应用 socket 选项。
bash
ss -lntp 'sport = :<目标端口>' systemctl status <服务名> --no-pager systemctl show <服务名> -p MainPID -p ActiveState -p SubState journalctl -u <服务名> --since '-30 minutes' -p warning --no-pager
ss -p 查看其他用户进程通常需要 root。没有监听时,应先查服务启动失败、配置端口和进程日志;不要通过开放防火墙解决“进程根本没监听”。
本地回环、主机地址分别测试,可以区分应用绑定与外部路径:
bash
curl --noproxy '*' --connect-timeout 3 http://127.0.0.1:<目标端口>/ curl --noproxy '*' --connect-timeout 3 http://<本机业务IP>:<目标端口>/ nc -vz -w 3 <本机业务IP> <目标端口>
如果服务不是 HTTP,不应用 curl 强测;使用协议对应的健康检查。--noproxy '*' 防止环境代理把“本机测试”送到代理服务器。
抓包涉及业务元数据,可能包含源/目的地址、域名和未加密内容;应遵守权限与留存要求,限制接口、主机、端口、包数和时长。不要无过滤地长期抓取生产流量。
bash
sudo timeout 20 tcpdump -ni <网卡名> -c 100 'host <目标IP> and tcp port <目标端口>' -w /var/tmp/connectivity-check.pcap sudo tcpdump -nn -tttt -r /var/tmp/connectivity-check.pcap 判断依据:反复看到客户端 SYN、没有 SYN-ACK,说明请求已离开抓包点但响应未返回;立即收到 RST 表示端口拒绝;握手完成后客户端发出请求但服务端不回应用数据,重点转向服务进程、TLS 或上游。只在客户端抓包不能精确区分中间哪一跳丢包,必要时在服务端同时抓取并对齐时间。
curl -v 会显示解析、连接、TLS 和请求响应过程,但可能把请求头中的 Authorization、Cookie 等敏感信息写入终端或日志。生产排查优先访问无敏感凭据的健康端点,保存输出前脱敏。
bash
curl --noproxy '*' -v --connect-timeout 3 --max-time 10 https://<目标域名>:<目标端口>/health
--connect-timeout 限制连接阶段,HTTPS 下通常涵盖 DNS 后的 TCP 与 TLS 建立所用时间;--max-time 限制整个传输。--noproxy '*' 强制直连,适合排除 HTTP_PROXY、HTTPS_PROXY 和 NO_PROXY 影响。若业务本来必须经过代理,则应分别测试直连与代理,不要把直连结果当作最终路径。
curl -w 能把排查从“感觉很慢”变成各阶段时长。remote_ip 还能确认实际连接了哪个解析地址。
bash
curl --noproxy '*' -sS -o /dev/null --connect-timeout 3 --max-time 15 -w 'remote_ip=%{remote_ip} http_code=%{http_code} namelookup=%{time_namelookup} connect=%{time_connect} appconnect=%{time_appconnect} starttransfer=%{time_starttransfer} total=%{time_total} ' https://<目标域名>:<目标端口>/health
判断时看差值:time_connect - time_namelookup 近似 TCP 建连阶段;time_appconnect - time_connect 近似 TLS 阶段;time_starttransfer - time_appconnect 主要包含请求发送、服务处理和首字节等待。对 HTTP 明文请求,time_appconnect 通常为 0。一次采样不代表趋势,应在受控频率下多次测试并保留时间戳。
下面脚本连续采样并输出 CSV。它不会忽略错误;失败行记录 curl 退出码,避免只统计成功请求产生幸存者偏差。
bash
#!/usr/bin/env bash set -uo pipefail URL="https://<目标域名>:<目标端口>/health" COUNT=10 INTERVAL=2 printf 'timestamp,exit_code,remote_ip,http_code,dns,tcp,tls,ttfb,total ' for ((i=1; i<=COUNT; i++)); do stamp="$(date --iso-8601=seconds)" metrics="$(curl --noproxy '*' -sS -o /dev/null --connect-timeout 3 --max-time 10 -w '%{remote_ip},%{http_code},%{time_namelookup},%{time_connect},%{time_appconnect},%{time_starttransfer},%{time_total}' "${URL}")" rc=$? printf '%s,%d,%s ' "${stamp}" "${rc}" "${metrics}" sleep "${INTERVAL}" done
脚本没有 set -e,是为了在单次失败后继续采样;保留 set -u 和 pipefail。curl 失败时仍可能输出部分指标,因此必须结合 exit_code 解读。
直接请求 https://<目标IP>/ 会改变 TLS SNI 和 HTTP Host,虚拟主机可能返回错误证书或默认站点。--resolve 才能固定连接 IP,同时保留域名语义。
bash
curl --noproxy '*' -v --resolve '<目标域名>:<目标端口>:<目标IP>' --connect-timeout 3 --max-time 10 https://<目标域名>:<目标端口>/health
若普通请求失败而 --resolve 成功,证据指向 DNS 结果、DNS 缓存或地址族选择;若两者都在 TLS 后返回相同错误,继续查服务端。--resolve 只影响本次 curl,不修改系统 hosts,适合安全验证。
双栈域名可能只坏一个地址族。分别强制测试,并记录实际远端地址:
bash
curl -4 --noproxy '*' -sS -o /dev/null -w 'ip=%{remote_ip} code=%{http_code} total=%{time_total} ' --connect-timeout 3 --max-time 10 https://<目标域名>/ curl -6 --noproxy '*' -sS -o /dev/null -w 'ip=%{remote_ip} code=%{http_code} total=%{time_total} ' --connect-timeout 3 --max-time 10 https://<目标域名>/
只有 IPv6 失败时,检查 IPv6 地址、默认路由、邻居发现、防火墙和上游回程;不要轻率删除 AAAA 记录或全局关闭 IPv6,那会影响其他业务。临时以 -4 验证可以止于客户端层,不是基础设施修复。
curl 报 certificate verify failed 不等于 TCP 不通。可能是证书过期、主机时间错误、中间证书缺失、SNI 不匹配或本机 CA 包异常。不要用 curl -k 作为修复;它会跳过证书验证,只能在明确风险的短时诊断中对照,且不得携带敏感凭据。
bash
date -u timedatectl status openssl s_client -connect <目标域名>:<目标端口> -servername <目标域名> -verify_return_error
openssl s_client 输出可能很长。检查证书主题备用名称、有效期、issuer、链验证返回码和服务端是否发全中间证书。根因必须由证书内容与验证错误支持,而不是把所有 TLS 错误归为“证书过期”。
只提取关键证书字段可用:
bash
openssl s_client -connect <目标域名>:<目标端口> -servername <目标域名> -showcerts /dev/null | openssl x509 -noout -subject -issuer -dates -ext subjectAltName
管道只解析服务端返回的第一张证书;完整链仍应结合 s_client 验证输出。若命令因 OpenSSL 版本不支持 -ext,先查 openssl x509 -help,再分别用 -text 查看。
200 通常说明应用端到端成功,但 301/302 可能跳到错误域名,401/403 表示已到应用或网关鉴权层,404 可能是 Host/path 不匹配,502/503/504 多与反向代理上游或容量相关。用响应头和有限正文定位,避免下载大文件。
bash
curl --noproxy '*' -sS -D /var/tmp/response.headers -o /var/tmp/response.body --range 0-4095 --connect-timeout 3 --max-time 10 https://<目标域名>:<目标端口>/health sed -n '1,40p' /var/tmp/response.headers wc -c /var/tmp/response.body
--range 只有服务端支持 Range 时才限制响应;诊断端点最好本身返回小响应。响应文件可能含敏感信息,检查权限并按组织要求清理。不要把 503 误报为“端口不通”,此时 TCP/TLS 很可能都已成功。
systemd 服务、交互 shell、容器可能使用不同代理设置。只读检查变量和值的来源:
bash
env | grep -iE '^(http|https|all|no)_proxy=' systemctl show <服务名> -p Environment curl -v --connect-timeout 3 --max-time 10 https://<目标域名>/ 2>&1 | grep -E 'Uses proxy env variable|Connected to|Trying '
代理 URL 可能包含凭据,展示和提交工单前必须脱敏。比较 curl --noproxy '*' 与正常 curl:只有代理路径失败时,查代理 DNS、ACL、认证和 NO_PROXY 匹配;不要全局删除代理变量影响包管理器和其他服务。
经典 traceroute 发送逐渐增大 TTL 的探测包,中间路由器若返回 ICMP Time Exceeded,就能显示该跳。默认探测方式因实现不同,Linux 常见版本默认 UDP;网络可能只允许 ICMP 或 TCP,因此应按业务协议对照。
bash
traceroute -n -w 2 -q 1 <目标IP> traceroute -I -n -w 2 -q 1 <目标IP> traceroute -T -p <目标端口> -n -w 2 -q 1 <目标IP>
-n 禁止反向 DNS,避免把 DNS 慢混入路径探测;-w 是等待,-q 是每跳探测次数;-I 使用 ICMP,-T -p 使用指定目的端口的 TCP SYN。不同 traceroute 实现选项有差异,先运行 traceroute --help。TCP 模式通常需要足够权限。
看到某一跳 * 但后续跳继续出现,说明该路由器不回复或限速,不是业务包在那里断了。最后一跳不显示也可能因为目标不回应探测,而 curl 仍成功。路径还可能是非对称、ECMP 或 MPLS,单次 traceroute 只是一条观测。
连续观测更适合 mtr,报告模式便于留证:
bash
mtr --report --report-cycles 20 --no-dns <目标IP> mtr --tcp --port <目标端口> --report --report-cycles 20 --no-dns <目标IP> 中间一跳显示高丢包而后续跳正常,通常是该节点对探测报文限速,不代表转发同样丢包。只有从某跳开始后续所有跳都出现相似丢包,并且端到端业务也受影响,才构成较强证据;还应从反向或其他源点测试。
tracepath 无需特殊权限,且能提示路径 MTU,适合补充:
bash
tracepath -n <目标IP> tracepath6 -n 2>/dev/null || tracepath -6 -n
工具名称随发行版不同;有的系统只有支持 -6 的 tracepath。以本机 --help 为准。
现代发行版可能使用 nftables,也可能通过 iptables 前端管理 nftables。先确定实际规则后端,不要同时修改两套规则造成漂移。
bash
nft list ruleset iptables --version iptables-save firewall-cmd --state 2>/dev/null || true ufw status verbose 2>/dev/null || true 规则输出可能包含内部地址、端口和安全策略,提交外部工单前脱敏。排查重点是输入/输出方向、接口、源/目的地址、状态匹配、默认策略和规则计数器。
用 nftables monitor trace 可以观察包命中路径,但开启 trace 标记本身要修改规则;生产上应限制到单个源/目标/端口,短时执行,并在结束后删除所加诊断规则。若组织已有防火墙控制面,应通过其变更流程,不要手工改。
以下是诊断流程示例,属于高风险配置修改:执行前保存 nft list ruleset,确认远程管理通道不会被匹配,并在控制台准备回滚。meta nftrace set 1 会让匹配包进入 trace。
bash
#!/usr/bin/env bash set -euo pipefail TARGET_IP="<目标IP>" TARGET_PORT="<目标端口>" BACKUP="/var/tmp/nft-before-$(date +%Y%m%d-%H%M%S).nft" nft list ruleset >"${BACKUP}" nft add table inet debug_trace nft 'add chain inet debug_trace output { type filter hook output priority -301; policy accept; }' nft add rule inet debug_trace output ip daddr "${TARGET_IP}" tcp dport "${TARGET_PORT}" meta nftrace set 1 echo "Run in another terminal: nft monitor trace" echo "Cleanup after capture: nft delete table inet debug_trace" echo "Backup: ${BACKUP}"
这段脚本仅覆盖 IPv4 TCP。诊断结束必须执行明确的清理并验证业务;删除的是临时 debug_trace 表,不是生产规则表:
bash
nft list table inet debug_trace nft delete table inet debug_trace nft list ruleset >/var/tmp/nft-after.txt
若脚本在加表后中途失败,仍需手工清理。不要直接用备份文件 nft -f 覆盖当前规则集,除非已确认语义和原子替换方式;错误恢复可能锁死远程连接。优先只删除本次明确创建的临时表。
TCP 请求能到服务端但 SYN-ACK 没回客户端,常见原因是回程路由走错、策略路由缺失、SNAT 不一致或反向路径过滤。服务端同时确认入包和路由决策:
bash
ip route get <客户端IP> ip rule show sysctl net.ipv4.conf.all.rp_filter net.ipv4.conf.default.rp_filter for f in /proc/sys/net/ipv4/conf/*/rp_filter; do printf '%s=%s ' "${f}" "$(cat "${f}")" done
rp_filter=1 是严格模式,非对称路由和多宿主场景可能丢弃合法包;2 为松散模式,0 关闭。实际有效行为还与接口级值和内核规则相关。修改它会改变安全边界,不得为了“试试看”直接关闭。应先用路由、抓包和内核日志证明反向路径检查相关,再经过安全评审在单接口灰度,保留旧值并验证回程。
经过状态防火墙或 NAT 的连接可能受 conntrack 表限制。表满时常见内核日志证据,NAT 还可能耗尽源端口。
bash
sysctl net.netfilter.nf_conntrack_count net.netfilter.nf_conntrack_max 2>/dev/null || true journalctl -k -g 'nf_conntrack.*table full' --since '-2 hours' --no-pager conntrack -S 2>/dev/null || true ss -s sysctl net.ipv4.ip_local_port_range 没有相关 sysctl 可能表示模块未加载或当前命名空间不可见,不要为了查看而在生产随意加载模块。提高表上限会消耗内存,扩展临时端口也必须避开保留端口;优先识别异常短连接、连接池失效、超时过长、攻击流量或 NAT 网关容量。
以下命令中的所有 kubectl 都显式使用 -n <命名空间>。先看 Pod IP、节点、重启和就绪状态,再看 Service、EndpointSlice 与 NetworkPolicy。
bash
kubectl -n <命名空间> get pod -o wide kubectl -n <命名空间> get service kubectl -n <命名空间> get endpointslice kubectl -n <命名空间> get networkpolicy kubectl -n <命名空间> describe pod Service 有 ClusterIP 但 EndpointSlice 没有 ready endpoint,问题在选择器、就绪探针或 Pod 状态,不是外部链路。NetworkPolicy 是否生效取决于 CNI 实现,不能仅凭对象存在下结论。
在故障 Pod 内执行,最贴近应用路径;前提是镜像包含工具且组织允许 exec:
bash
kubectl -n <命名空间> exec -- getent ahosts <目标域名> kubectl -n <命名空间> exec -- curl --noproxy '*' -sS -o /dev/null -w 'ip=%{remote_ip} code=%{http_code} total=%{time_total} ' --connect-timeout 3 --max-time 10 https://<目标域名>/health 若业务镜像没有排障工具,不要临时修改镜像或在生产安装包。可按集群策略使用临时调试容器;它会创建额外进程和网络流量,执行前确认 RBAC、审计和资源限制。
bash
kubectl -n <命名空间> debug pod/ -it --image=<已批准的调试镜像> --target=<容器名>
kubectl debug 的可用参数和临时容器能力取决于 Kubernetes 版本、运行时和安全策略,先运行 kubectl debug --help。<已批准的调试镜像> 必须使用组织仓库中的固定版本或摘要,不能现场拉取来源不明镜像。
getent ahosts 失败:检查 NSS、resolv.conf、本地 resolved、DNS 可达性和查询返回码。ip route get,确认实际出口与源地址。--resolve 成功、普通域名失败:重点查 DNS 结果或地址族。curl -w 判断失败在 TLS 还是首字节。对成功与失败机器做配置差异,而不是继续单机猜测:地址/掩码、路由规则、DNS、代理变量、时间、CA 证书、内核参数、防火墙、云安全组绑定、服务网格 sidecar 和出口 NAT。差异本身不是根因,需用复现实验验证。
下面脚本收集四件套及本机网络状态。它不修改配置,所有命令有限时;因某个工具缺失或单项失败不会停止整次采集。以 root 运行会收集更多进程信息,输出可能含内部拓扑,分享前应脱敏。
bash
#!/usr/bin/env bash set -uo pipefail TARGET_HOST="<目标域名>" TARGET_IP="<目标IP>" TARGET_PORT="<目标端口>" SCHEME="https" OUT_DIR="/var/tmp/netcheck-$(date +%Y%m%d-%H%M%S)" mkdir -p "${OUT_DIR}" exec > >(tee -a "${OUT_DIR}/report.txt") 2>&1 run() { local name="$1" shift printf ' [%s] %s ' "$(date --iso-8601=seconds)" "${name}" timeout 20 "$@" || printf 'command_failed rc=%d ' "$?" } run identity uname -a run links ip -br link run addresses ip -br address run rules ip rule show run routes ip route show table all run route_get ip route get "${TARGET_IP}" run dns_getent getent ahosts "${TARGET_HOST}" run ping ping -c 4 -W 2 "${TARGET_IP}" run tcp nc -vz -w 3 "${TARGET_IP}" "${TARGET_PORT}" run http curl --noproxy '*' -sS -o /dev/null --connect-timeout 3 --max-time 10 -w 'ip=%{remote_ip} code=%{http_code} dns=%{time_namelookup} connect=%{time_connect} tls=%{time_appconnect} total=%{time_total} ' "${SCHEME}://${TARGET_HOST}:${TARGET_PORT}/health" run trace traceroute -T -p "${TARGET_PORT}" -n -w 2 -q 1 "${TARGET_IP}" run sockets ss -s printf ' output_dir=%s ' "${OUT_DIR}"
进程替换 >(...) 要求 Bash。脚本把目标域名和 IP 都作为显式输入,是为了避免 DNS 变化让不同命令测到不同目标。若 nc、traceroute 未安装,脚本会记录失败;不要在故障窗口未经审批安装软件。
偶发网络问题最怕两端时间不准。先检查时间同步,再在客户端与服务端使用同一时间窗查询日志。systemd-journald 的字段可以输出单调或 UTC 时间,便于对齐。
bash
timedatectl show -p NTPSynchronized -p TimeUSec -p Timezone journalctl -u <服务名> --since '2026-08-05 1000' --until '2026-08-05 1000' -o short-iso-precise --no-pager 示例时间必须换成实际故障窗口。客户端 curl 时间、负载均衡访问日志、服务日志和防火墙事件如果无法对齐,就不能可靠判断先后关系。
排障工具是只读为主,修复操作却可能中断连接。以下动作必须按影响范围单独评审:
ip route/ip rule,验证带外控制台,在单台灰度;临时规则先测试,持久化配置另行审查。
路由变更若确需执行,先以自动回滚保护现场。下面是思路明确的连续流程,但命令仍需按发行版网络管理方式适配;ip 的运行时变更不会自动写入 NetworkManager 或 systemd-networkd 配置。
bash
#!/usr/bin/env bash set -euo pipefail TARGET_CIDR="<目标网段CIDR>" NEW_VIA="<新网关IP>" IFACE="<网卡名>" ROLLBACK_FILE="/var/tmp/routes-before-$(date +%Y%m%d-%H%M%S).txt" ip route show table all >"${ROLLBACK_FILE}" ip route get "${NEW_VIA}" >/dev/null # 先创建 120 秒后的回滚任务;确认业务后由变更人员取消对应 transient unit。 systemd-run --unit=route-auto-rollback --on-active=120 /usr/sbin/ip route del "${TARGET_CIDR}" via "${NEW_VIA}" dev "${IFACE}" ip route add "${TARGET_CIDR}" via "${NEW_VIA}" dev "${IFACE}" ip route get "${TARGET_CIDR%/*}" ping -c 3 -W 1 "${NEW_VIA}" echo "Verify service now; cancel rollback only after validation:" echo "systemctl stop route-auto-rollback.timer" echo "route_snapshot=${ROLLBACK_FILE}"
这段脚本假设目标网段原先没有同名路由,因此回滚是删除新路由;若是替换旧路由,不能直接使用。TARGET_CIDR%/* 对一般 CIDR 得到网络地址,但不保证它是可响应主机,只用于展示路由查找。执行前必须根据真实旧路由编写可逆命令,并验证 systemd transient timer 已创建。不能把保存的 ip route show table all 直接当作可执行恢复脚本。
错误。ICMP 可能被目标、防火墙或云策略限制。继续使用 TCP 业务端口、服务端监听和应用健康检查验证。
错误。它只证明 TCP 握手成功。TLS 可能失败,HTTP 可能 503,后端依赖也可能不可用。继续用 curl 或协议专用客户端。
证据不足。节点可能不返回 TTL exceeded,目的仍可能可达。用 TCP traceroute、端到端 curl、双向测试和运营商/云监控交叉验证。
正相反,-k 成功而正常验证失败,说明连接与应用可能正常,但证书信任或名称验证有问题。修复证书链、SAN、CA 或系统时间,不应永久关闭验证。
立即 refused 通常说明收到了 RST 或主动 reject,路径至少部分可达。查目标地址、监听端口、服务状态和防火墙 reject 规则;静默 drop 更常表现为超时。
不可取。全局关闭会扩大攻击面,还会清除你判断具体命中规则的证据。使用规则计数器、有限抓包、临时精确 trace 或单源单端口灰度规则。
一次排障结论至少应包含:
ip route get 的输出及实际源地址。
四件套的正确用法,是让每条命令回答一个有限的问题:ping 看 ICMP 基本可达性,telnet 看 TCP 建连,curl 看 DNS到应用层的完整过程,traceroute 看逐跳反馈。再用 ip route get、ss、日志、规则计数和受控抓包补齐证据,才能把“网络不通”收敛成可修复、可验证、可回滚的具体故障。
全部0条评论
快来发表一下你的评论吧 !