防火墙 / 端口 / 网络
本文范围
这篇文章只讲部署运维现场最常见的网络入口排障:服务监听、绑定地址、TCP 连通、DNS/hosts、firewalld、iptables、云安全组、Docker 端口映射、Nginx upstream、K8S Service / Ingress 的基础定位链路。
本文不展开完整计算机网络课程,不深入 BGP、OSPF、Service Mesh、CNI、eBPF、内核协议栈调优和零信任平台建设。K8S、Docker、Nginx 只作为端口不通时的排障边界出现,不在本文里讲完整安装和架构。
读完以后,你应该能把“网络不通”拆成可验证的几段:服务是否监听、本机是否可访问、同网段是否可访问、云边界是否放行、入口代理是否转发、协议层是否报错。
前置条件
跟着本文排障前,建议先具备这些条件:
- 能登录服务端,拥有
sudo权限,且知道目标服务端口和健康检查路径。 - 有另一台同 VPC / 同网段机器,或能从真实客户端发起访问验证。
- 服务器安装了
iproute2、curl、nc或telnet、lsof、dig/nslookup。 - 能查看云安全组、负载均衡、NACL、VPN、专线或内网 ACL 的规则。
- 排障时不要先关闭防火墙;先记录当前规则、验证现象、再做可回滚的临时放行。
先把问题说清楚
线上排障时,经常会听到一句话:“端口不通,防火墙是不是没开?”这句话只说对了一小半。端口不通可能是防火墙,也可能是服务根本没启动,可能是只监听了 127.0.0.1,可能是云安全组没放行,也可能是 Docker 只在容器里暴露了端口,宿主机根本没有映射。
所以遇到网络问题,先不要急着改配置。我们先把请求从客户端到服务端走一遍:域名解析成哪个 IP,请求从哪张网卡出去,云安全组有没有挡住,系统防火墙有没有挡住,宿主机有没有进程监听,监听地址是不是外部可达,Docker / K8S 有没有做转发,Nginx 有没有把请求转到正确后端,最后才看 HTTP、TLS、代理和应用超时。
这一篇只讲部署运维够用的网络排障,不上完整网络课程,也不钻 K8S CNI、Service Mesh、eBPF 这些深水区。我们要解决的是很现场的问题:服务发布后访问不了,应该敲什么命令,命令结果怎么看,看到错误以后下一步查哪里。
这里先记住四句话:
- 本机能访问,不代表外部机器能访问。
ping通,不代表 TCP 端口通。- 端口监听了,不代表监听在对的地址上。
- 安全组放行了,不代表系统防火墙、Docker、Nginx、K8S 都放行了。
排障时一般按三段走:
- 先在服务端本机看服务是不是真的监听。
- 再从同网段或同 VPC 的机器访问服务端内网 IP。
- 最后再从真实客户端、公网域名或入口网关访问。
这样排查有一个好处:每一步都有明确结论。哪一步失败,就先修哪一步,不会在防火墙、DNS、Nginx、Docker 之间来回猜。
下面这张图可以当作设计评审和现场排障的共同底图。评审时沿着它确认“域名指到哪里、路由从哪里出去、哪一层做访问控制、哪个进程监听、HTTP/TLS 在哪一层终止”;排障时则把每个节点换成一条命令或一个控制台规则,逐段证明请求有没有走到下一层。
使用这张图时,不要把“端口开放”当成单点结论。比如 ss 已经看到 0.0.0.0:8080,只能说明监听层成立;如果客户端仍然超时,就要回到云安全组、主机防火墙、路由和抓包。反过来,如果已经 Connected 但返回 502/504,就说明 TCP 已经穿过前面几层,排障重点应该转到入口代理、upstream 可达性和应用处理时间。
先跑一遍最小闭环
我们先拿一个最常见的场景练手:应用发布后,应该通过 http://app.example.com:8080/health 访问健康检查,但现在访问失败。
这个时候不要先改 Nginx,也不要先关防火墙。先登录服务端,看机器自己到底是什么状态。
第一步,看服务端 IP、路由和端口监听:
ip addr
ip route
ss -lntup
ss -lntp '( sport = :8080 )'
sudo lsof -nP -iTCP:8080 -sTCP:LISTEN这里要看三个结果:
ip addr用来看服务器有哪些网卡和 IP,避免把公网 IP、内网 IP、容器网卡 IP 搞混。ip route用来看默认出口和目标网段路由,跨网段、VPN、专线问题经常在这里露头。ss和lsof用来看8080有没有进程监听,监听在127.0.0.1、0.0.0.0还是某个内网 IP 上。
如果 ss -lntp '( sport = :8080 )' 没有任何输出,说明服务端口根本没监听。这个时候不要开防火墙,先去看应用日志、启动命令和配置端口。
第二步,在服务端本机访问:
curl -v --connect-timeout 3 http://127.0.0.1:8080/health
curl -v --connect-timeout 3 http://localhost:8080/health
curl -v --connect-timeout 3 http://<服务器内网IP>:8080/health这三个命令不是重复劳动。127.0.0.1 通,只能说明本机回环地址能访问;内网 IP 通,才说明服务绑定地址对外部链路有机会可达。访问后一般应该看到 HTTP/1.1 200、HTTP/2 200 或业务约定的健康检查响应。如果这里已经 Connection refused,优先回到监听地址和应用端口。
第三步,在另一台机器验证 TCP 和 HTTP:
nc -vz <服务器内网IP> 8080
telnet <服务器内网IP> 8080
curl -v --connect-timeout 3 http://<服务器内网IP>:8080/healthnc -vz 只判断 TCP 能不能建立连接,速度快,适合先判断端口通不通。curl -v 会继续走 HTTP,能看到请求头、响应头、状态码、重定向、代理和 TLS 细节。telnet 是兜底工具,有些老机器没有 nc 时还能用。
如果服务端本机访问正常,另一台机器访问超时,一般查安全组、系统防火墙、路由、网段 ACL、VPN。如果另一台机器直接返回 Connection refused,一般查服务监听地址、端口是否写错、是否被 REJECT 规则拒绝。
第四步,再验证域名解析:
getent hosts app.example.com
dig app.example.com
nslookup app.example.com
curl -v --connect-timeout 3 http://app.example.com:8080/health这里要注意,IP 能访问而域名不能访问,问题通常不在服务端口,而在 DNS、hosts、代理、证书或 Nginx server_name。
第五步,路径和丢包只能作为辅助:
ping -c 4 <服务器内网IP>
traceroute <服务器内网IP>
tracepath <服务器内网IP>ping 通只能说明 ICMP 有回应,不代表 8080/tcp 通;ping 不通也不一定代表服务不可用,因为很多云安全组和企业网络会禁 ICMP。排端口问题,最终还是要回到 nc 和 curl。
端口监听先看 ss
如果只记一个端口监听命令,就记 ss -lntp。netstat 现在还能用,但很多系统已经把它当兼容工具,新的排障习惯建议优先用 ss。
先看当前机器上有哪些 TCP 端口正在监听:
ss -lntp执行后重点看两列:Local Address:Port 和 users。
如果看到类似下面的结果:
LISTEN 0 128 0.0.0.0:8080 0.0.0.0:* users:(("java",pid=2234,fd=66))说明 java 进程正在监听 8080,而且监听在 0.0.0.0 上,外部机器有机会访问这个端口。注意这里只是“有机会”,最终还要看防火墙、安全组和路由。
参数可以这样理解:
| 参数 | 含义 |
|---|---|
-l | 只看监听 socket |
-n | 不做域名和服务名反查,直接显示数字 IP 和端口 |
-t | 只看 TCP |
-u | 只看 UDP |
-p | 显示进程信息,通常需要 root 权限 |
只查 8080 这个端口:
ss -lntp '( sport = :8080 )'
ss -lntup | grep ':8080'如果没有输出,一般有三种情况:
- 服务没启动。
- 服务监听的不是这个端口。
- 服务启动失败,进程已经退出。
这时下一步不是放行端口,而是看应用日志、启动脚本、配置文件里的端口。比如 Java 服务就看启动日志里实际监听的端口;Nginx 就先 nginx -t 再看 error log。
查看连接状态时可以用:
ss -ant
ss -ant state established
ss -ant state syn-sent
ss -ant state time-wait这里要注意:syn-sent 很多,通常说明客户端正在尝试连接但没收到回应,方向可能是对端不可达、防火墙 DROP、路由或安全组。time-wait 多不一定是故障,要结合连接数、端口耗尽和应用现象判断。
有些机器没有 ss,再用 netstat 兜底:
netstat -lntp
netstat -antp如果 ss -p 看不到进程名,通常是权限不够,前面加 sudo。也可以用 lsof 反查端口对应进程:
sudo lsof -nP -iTCP:8080 -sTCP:LISTEN
sudo lsof -nP -i :8080端口被占用时,先看进程是谁,不要直接 kill -9。很多生产事故不是端口占用本身造成的,而是排障时把不该杀的进程杀掉了。
ps -fp <PID>
readlink -f /proc/<PID>/exe
pwdx <PID>
systemctl status <可能的服务名>如果它是 systemd 管理的服务,优先用服务管理命令停止或改端口:
sudo systemctl stop nginx
sudo systemctl status nginx如果确认只是临时开发进程,再考虑结束进程:
kill <PID>
sleep 2
ss -lntp '( sport = :8080 )'访问后应该看到什么?重新执行 ss -lntp '( sport = :8080 )',如果已经没有旧进程,再启动新服务;如果新服务启动后出现新的 LISTEN,再继续用 curl 验证接口。kill -9 是最后手段,它不会给进程清理资源、刷日志、释放锁和优雅下线的机会。
绑定地址比端口更容易被忽略
很多人查端口时只看 8080 在不在,忽略了前面的 IP。实际上,端口号只回答“监听哪个门牌号”,绑定地址回答“这扇门开在哪面墙上”。门只开在 127.0.0.1 上,外面的人当然进不来。
常见 ss 输出:
LISTEN 0 128 127.0.0.1:8080 0.0.0.0:* users:(("java",pid=1234,fd=66))
LISTEN 0 128 0.0.0.0:8080 0.0.0.0:* users:(("java",pid=2234,fd=66))
LISTEN 0 128 10.0.1.15:8080 0.0.0.0:* users:(("java",pid=3234,fd=66))
LISTEN 0 128 [::]:8080 [::]:* users:(("java",pid=4234,fd=66))这几种含义完全不同:
| 监听地址 | 含义 | 典型现象 |
|---|---|---|
127.0.0.1:8080 | 只监听本机回环地址 | 本机 curl 127.0.0.1 正常,外部机器访问失败 |
0.0.0.0:8080 | 监听所有 IPv4 网卡 | 本机、内网、公网入口都有机会访问,仍受防火墙和安全组限制 |
10.0.1.15:8080 | 只监听指定内网 IP | 访问其他网卡 IP 或公网 IP 可能失败 |
[::]:8080 | IPv6 监听 | 是否同时接收 IPv4 取决于系统和应用设置 |
这里要注意:127.0.0.1 不是“本机 IP 的一种写法”,它就是回环地址,只能在本机访问。你在服务器上执行 curl http://127.0.0.1:8080 成功,只能证明服务器自己能访问自己,不能证明你的办公电脑、另一台服务器、Nginx 容器或 K8S 节点能访问它。
127.0.0.1 适合只给本机访问,例如 Nginx 反向代理到本机 Java 服务:
server {
listen 80;
server_name app.example.com;
location / {
proxy_pass http://127.0.0.1:8080;
}
}如果服务需要被其他机器访问,通常要绑定到 0.0.0.0 或明确的内网 IP。常见配置示例:
Spring Boot:
server.port=8080
server.address=0.0.0.0MySQL:
[mysqld]
bind-address=0.0.0.0Redis:
bind 0.0.0.0
protected-mode yesNginx:
server {
listen 0.0.0.0:80;
server_name app.example.com;
}改完配置后,不要只重启完就算结束,一定要回到命令验证:
ss -lntp '( sport = :8080 )'
curl -v http://127.0.0.1:8080/health
curl -v http://<服务器内网IP>:8080/health如果 ss 里还是 127.0.0.1:8080,说明配置没有生效,常见原因是改错配置文件、环境变量覆盖了配置、容器镜像里还有一份旧配置,或者服务实际启动命令指定了其他参数。
生产上要再强调一句:绑定 0.0.0.0 只是让服务具备被外部访问的可能,不等于应该对全网开放。数据库、Redis、MQ、管理后台、调试端口即使绑定内网,也要通过安全组、防火墙、账号权限、认证和来源白名单继续限制。
本机访问和跨机器访问不是一回事
很多排障卡在一句话:“我在服务器上 curl 是好的,为什么外面访问不了?”
因为本机访问只证明本机协议栈、进程监听和应用处理正常,不证明跨机器链路正常。
一般按这三个层次验证,不要省步骤:
# 1. 本机回环
curl -v http://127.0.0.1:8080/health
# 2. 本机访问自己的内网 IP
curl -v http://10.0.1.15:8080/health
# 3. 另一台机器访问服务端内网 IP
curl -v http://10.0.1.15:8080/health
nc -vz 10.0.1.15 8080第一条命令成功,说明应用在本机能处理请求。第二条命令成功,说明服务至少绑定到了本机某个非回环地址。第三组命令成功,才说明跨机器链路也没问题。
结果解释:
| 现象 | 优先怀疑 |
|---|---|
127.0.0.1 通,内网 IP 不通 | 服务只绑定了 127.0.0.1,或本机防火墙拦截内网地址 |
| 服务端内网 IP 通,其他机器不通 | 安全组、系统防火墙、路由、网段 ACL、VPN |
| IP 通,域名不通 | DNS、hosts、代理、证书、域名指向 |
| TCP 通,HTTP 不通 | 应用协议、Host 头、Nginx 配置、TLS、鉴权 |
这里要注意,很多人会先问:“能 ping 通吗?”ping 只能说明 ICMP 层面有回应,不能证明 TCP 端口可用。很多云安全组和企业网络会禁 ICMP,但 TCP 端口仍然正常。反过来,ping 通也不代表 8080/tcp 通。
查端口连通优先用:
nc -vz <host> <port>
curl -v --connect-timeout 3 http://<host>:<port>/没有 nc 时可以用 telnet:
telnet <host> <port>访问后应该看到什么?nc -vz 成功时通常会出现 succeeded 或 open,失败时会看到 refused、timed out 这类提示。telnet 连接成功后会进入一个空白会话,这只代表 TCP 建立成功,不代表 HTTP 返回正确。HTTP 服务仍然要用 curl 看状态码、响应头、重定向、证书和代理。
curl 是网络排障的瑞士军刀
排 HTTP/HTTPS 问题时,curl -v 往往比浏览器更干净。浏览器有缓存、插件、系统代理、HSTS、证书存储和自动重试,适合复现用户体验,但不适合第一时间判断链路。
先用最朴素的方式访问:
curl -v http://app.example.com/
curl -I http://app.example.com/
curl -v --connect-timeout 3 --max-time 10 http://app.example.com/
curl -v -H 'Host: app.example.com' http://10.0.1.15/这里重点看 curl -v 输出里的几类信息:
Trying ...:客户端准备连接哪个 IP 和端口。Connected to ...:TCP 是否已经建立。Host::HTTP 请求里的 Host 头是不是你期望的域名。< HTTP/1.1 200、< HTTP/1.1 301、< HTTP/1.1 502:服务端返回了什么状态码。server certificate、SSL certificate problem:HTTPS 证书是否有问题。
如果卡在 Trying 后面,通常是连接没建起来,查网络、安全组、防火墙。如果已经 Connected,但返回 404/502/504,就不要继续说“端口不通”了,要去查 Nginx、upstream、应用路由或超时。
跳过 DNS,强制指定域名解析到某个 IP:
curl -v --resolve app.example.com:443:10.0.1.15 https://app.example.com/这个命令很适合灰度和排障。它的效果是:请求 Host 仍然是 app.example.com,证书 SNI 也是 app.example.com,但实际连接的 IP 被指定为 10.0.1.15。如果这样访问成功,而普通域名访问失败,问题大概率在 DNS、负载均衡、CDN 或客户端缓存。
看 TLS 证书:
openssl s_client -connect app.example.com:443 -servername app.example.com </dev/null指定 CA:
curl -v --cacert internal-ca.crt https://app.example.com/临时忽略证书:
curl -vk https://app.example.com/-k 只能用于临时定位。生产脚本、健康检查、交付验收不要长期使用 -k,否则证书过期、域名不匹配、中间人代理和错误证书都会被掩盖。一般做法是先用 -k 判断是不是证书问题,再用 --cacert、系统信任仓库或 JDK truststore 把证书链修好。
验证代理影响:
env | grep -i proxy
curl -v --noproxy '*' https://app.example.com/
curl -v --proxy http://proxy.example.com:8080 https://example.com/企业内网里,经常出现“终端浏览器能访问,服务器 curl 不行”或“服务器 curl 走了代理,访问内网域名反而失败”。这时重点看 http_proxy、https_proxy、no_proxy。内网域名、内网 IP 段、K8S Service 域名和本机地址通常要放进 no_proxy。
示例:
export no_proxy="localhost,127.0.0.1,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16,.svc,.cluster.local,.example.internal"DNS、hosts 和解析顺序
域名访问不通时,先确认域名到底解析到了哪里。
getent hosts app.example.com
dig app.example.com
dig +short app.example.com
nslookup app.example.com这里建议先看 getent hosts,再看 dig。getent hosts 更接近应用在 Linux 上通过系统解析得到的结果,因为它会走 NSS 配置,可能会受 hosts 文件影响。dig 更适合直接问 DNS 服务器。两者结果不一致时,不要急着改应用配置,先查 /etc/nsswitch.conf、/etc/hosts、/etc/resolv.conf、systemd-resolved 或企业 DNS 配置。
Linux hosts 示例:
127.0.0.1 localhost
10.0.1.15 app.example.internalWindows hosts 文件位置通常是:
C:\Windows\System32\drivers\etc\hosts改完 hosts 后,命令行验证:
getent hosts app.example.internal
curl -v http://app.example.internal:8080/访问后应该看到什么?getent hosts 应该返回你刚配置的 IP;curl -v 里的 Trying 也应该是这个 IP。如果 getent hosts 对了,但 curl 仍然访问旧 IP,要看是不是代理、应用缓存、浏览器缓存或连接池在影响。
DNS 常见坑:
| 现象 | 原因 | 验证 |
|---|---|---|
| 服务器解析到公网 IP,内网应走内网 IP | 内外网 DNS 没拆分,或机器使用了错误 DNS | dig @<内网DNS> app.example.com |
| 本机改了 hosts,Java 应用仍访问旧 IP | 应用、JVM、连接池或 SDK 有缓存 | 重启应用或查对应 DNS 缓存设置 |
| 浏览器能访问,服务器 curl 不行 | 浏览器走代理或本机 DNS 不同 | curl -v、查看代理设置 |
| K8S Pod 里域名解析失败 | CoreDNS、Service 名称、namespace 或 search domain 问题 | kubectl exec 后 nslookup / getent hosts |
看 DNS 配置:
cat /etc/resolv.conf
resolvectl status 2>/dev/null || true企业内网要特别注意 split-horizon DNS:同一个域名,在办公网、服务器 VPC、容器网络、K8S 集群内可能解析到不同 IP。这不是异常,前提是设计清楚、记录清楚、验证清楚。
firewalld:先区分运行时和永久配置
RHEL 系、CentOS Stream、Rocky Linux、AlmaLinux 等服务器上经常使用 firewalld。排查时先看它是否运行:
systemctl status firewalld
firewall-cmd --state如果这里显示 not running,说明 firewalld 没有参与当前拦截,先不要在 firewalld 上绕圈子;继续查 iptables、nftables、云安全组或其他安全组件。如果是 running,再看当前 zone。
查看默认 zone 和活跃 zone:
firewall-cmd --get-default-zone
firewall-cmd --get-active-zones
firewall-cmd --zone=public --list-all
firewall-cmd --list-ports
firewall-cmd --list-services临时开放端口,适合先做验证:
sudo firewall-cmd --zone=public --add-port=8080/tcp
firewall-cmd --zone=public --list-ports这时马上从客户端执行:
nc -vz <服务器IP> 8080
curl -v --connect-timeout 3 http://<服务器IP>:8080/health如果临时开放后访问恢复,说明系统防火墙确实是拦截点。验证通过后再固化为永久规则:
sudo firewall-cmd --zone=public --permanent --add-port=8080/tcp
sudo firewall-cmd --reload
firewall-cmd --zone=public --list-ports开放端口范围:
sudo firewall-cmd --zone=public --permanent --add-port=9000-9010/tcp
sudo firewall-cmd --reload开放 UDP:
sudo firewall-cmd --zone=public --permanent --add-port=53/udp
sudo firewall-cmd --reload移除端口:
sudo firewall-cmd --zone=public --permanent --remove-port=8080/tcp
sudo firewall-cmd --reload只允许某个来源访问某个端口,可以用 rich rule:
sudo firewall-cmd --zone=public --permanent \
--add-rich-rule='rule family="ipv4" source address="10.0.2.0/24" port protocol="tcp" port="8080" accept'
sudo firewall-cmd --reload临时规则和永久规则的区别非常关键。没有 --permanent 的修改只影响运行时,重启或 reload 后可能丢失。有 --permanent 的修改不会立刻生效,需要 --reload。一种稳妥流程是先临时加规则,验证成功后再固化:
sudo firewall-cmd --zone=public --add-port=8080/tcp
nc -vz <服务器IP> 8080
sudo firewall-cmd --runtime-to-permanent不要为了省事直接关闭防火墙。如果必须短时间关闭用于定位,要记录时间窗口,验证后立即恢复:
sudo systemctl stop firewalld
# 验证问题是否消失
sudo systemctl start firewalld如果关闭 firewalld 后问题消失,说明规则层确实参与了故障;下一步应该收敛为最小放行规则,而不是长期关闭。
iptables:看规则顺序和默认策略
iptables 仍然大量存在于老系统、容器网络、脚本和历史环境里。排查先看规则:
sudo iptables -L -n -v --line-numbers
sudo iptables -S
sudo iptables -t nat -L -n -v --line-numbers这里不要只看有没有 ACCEPT,还要看它在第几行。iptables 是从上往下匹配的,前面如果已经有 DROP 或 REJECT,后面再加 ACCEPT 也可能永远匹配不到。
关键点:
INPUT链影响进入本机的包。OUTPUT链影响本机发出的包。FORWARD链影响转发流量,Docker、网关、K8S 节点经常涉及它。- 规则按顺序匹配,前面的 DROP/REJECT 会让后面的 ACCEPT 没机会生效。
- 默认策略是
ACCEPT还是DROP很关键。
开放 8080:
sudo iptables -A INPUT -p tcp --dport 8080 -j ACCEPT
sudo iptables -L INPUT -n -v --line-numbers-A 是追加到最后。开发测试环境里可能够用,生产环境不要机械照抄。如果前面已经有 DROP 规则,追加到最后可能没用,要插到合适位置:
sudo iptables -I INPUT 1 -p tcp --dport 8080 -j ACCEPT插入后要做两次验证:
sudo iptables -L INPUT -n -v --line-numbers
nc -vz <服务器IP> 8080第一条看规则计数是否增长,第二条看客户端能不能建立 TCP。只看规则存在,不看计数和连通性,很容易误判。
只允许某个网段访问:
sudo iptables -I INPUT 1 -p tcp -s 10.0.2.0/24 --dport 8080 -j ACCEPT删除规则要先看行号:
sudo iptables -L INPUT -n --line-numbers
sudo iptables -D INPUT <行号>持久化方式跟发行版有关:
# Debian / Ubuntu 常见方式
sudo apt-get install -y iptables-persistent
sudo netfilter-persistent save
# RHEL 系旧环境可能使用
sudo service iptables save新发行版底层可能已经使用 nftables,iptables 命令可能是 nft 后端兼容层。确认方式:
iptables --version
sudo nft list ruleset生产环境不要混用多个防火墙管理器。firewalld、iptables、nftables、Docker 自动生成规则如果互相叠加,排障复杂度会快速上升。至少要明确:谁是主配置入口,哪些规则由容器运行时生成,哪些规则由人工维护。
云服务器安全组:它在系统防火墙之前
云服务器的安全组不是 Linux 里的防火墙配置,而是云平台控制面上的网络访问控制。公网或跨机器访问不通时,安全组通常比系统防火墙更先被命中。
现场最常见的情况是:你在服务器上 curl 127.0.0.1 正常,ss 也看到服务监听了,但是从自己电脑访问公网 IP 一直超时。这种现象不要先怀疑应用,大概率要先看云安全组、负载均衡监听、云防火墙或公网入口。
检查安全组时看这几个维度:
| 维度 | 要点 |
|---|---|
| 方向 | 入站规则和出站规则分别检查 |
| 协议 | TCP、UDP、ICMP 不要混淆 |
| 端口 | 单端口、范围、全部端口要看清 |
| 来源 | 0.0.0.0/0、办公网出口 IP、VPC 网段、堡垒机 IP |
| 目标 | 规则绑定的是哪台实例、哪张网卡、哪个安全组 |
| 优先级 | 有些云厂商规则存在优先级或拒绝规则 |
| 多层网络 | 安全组之外可能还有 NACL、云防火墙、WAF、SLB、NAT 网关 |
常见判断:
| 现象 | 优先检查 |
|---|---|
服务器本机 curl 127.0.0.1 正常,公网访问超时 | 安全组入站、系统防火墙、公网 IP、备案和入口转发 |
| 同 VPC 内网 IP 能访问,公网 IP 不能访问 | 公网安全组、公网带宽、NAT、EIP、云防火墙 |
| A 机器能访问,B 机器不能访问 | 来源 CIDR、办公网出口 IP、VPN、ACL |
| 80/443 通,数据库端口不通 | 安全组只放了 Web 端口,或数据库端口被最小化限制 |
安全组不是“全放开方便排障”的地方。生产建议:
- Web 入口只开放
80/tcp、443/tcp给公网。 - SSH 只开放给办公网、堡垒机或 VPN 网段。
- MySQL、Redis、MQ、Elasticsearch、Nacos、管理后台不要对
0.0.0.0/0开放。 - 微服务内部端口只允许 VPC 内必要来源访问。
- 临时排障放行要有过期时间和回收记录。
中国大陆公网还要额外考虑域名备案、接入备案、云厂商拦截策略、WAF、CDN、负载均衡监听和证书验证方式。80/443 配置正确但域名访问异常时,不要只盯着服务器本机。
Docker 端口映射:EXPOSE 不等于发布端口
Docker 里最常见的误判是:Dockerfile 写了 EXPOSE 8080,就以为宿主机可以访问 8080。不是。EXPOSE 更像一张说明书,告诉别人容器里可能用这个端口;真正把容器端口开到宿主机上,要看 docker run -p 或 Compose 的 ports。
先启动一个最简单的例子:
docker run -d --name web -p 8080:80 nginx:1.27这条命令做了两件事:-d 表示后台运行,-p 8080:80 表示宿主机 8080/tcp 转发到容器内 80/tcp。访问 http://宿主机IP:8080/,正常情况下应该看到 Nginx 欢迎页。
这里要注意,如果服务器在企业内网或离线环境,不要默认它能直接拉到 nginx:1.27。一般需要提前把镜像同步到私有仓库,或者用 docker load 导入离线镜像包,再把命令里的镜像名替换成内部仓库地址。
查看映射:
docker ps
docker port web
docker inspect web如果 docker ps 的 PORTS 列没有看到 0.0.0.0:8080->80/tcp 或类似输出,说明宿主机端口没有发布。容器 Up 只能说明容器进程活着,不代表外部能访问。
只绑定本机回环地址:
docker run -d --name web -p 127.0.0.1:8080:80 nginx:1.27这个容器只能被宿主机本机访问,外部机器访问不到。适合只让 Nginx 或本机代理访问,不适合直接对外发布。
默认写法:
docker run -d --name web -p 8080:80 nginx:1.27通常会发布到宿主机所有地址。对 Web 入口可以接受,但对数据库、Redis、MQ、管理后台要非常谨慎。敏感服务应该绑定到内网地址或 127.0.0.1,再配合安全组和防火墙限制来源。
容器端口不通排查:
docker ps --format 'table {{.Names}}\t{{.Status}}\t{{.Ports}}'
docker logs --tail=100 web
docker exec -it web sh
ss -lntp
curl -v http://127.0.0.1:80/这里是在容器内部确认应用到底有没有监听。容器里 curl 127.0.0.1:80 都不通,说明问题在容器内应用,不要先查宿主机防火墙。
宿主机验证:
curl -v http://127.0.0.1:8080/
curl -v http://<宿主机内网IP>:8080/宿主机 127.0.0.1:8080 通,内网 IP 不通,通常是发布地址或防火墙问题。宿主机内网 IP 通,另一台机器不通,再去查云安全组和系统防火墙。
另一台机器验证:
nc -vz <宿主机内网IP> 8080
curl -v http://<宿主机内网IP>:8080/容器里应用也要监听正确地址。容器内服务如果只监听 127.0.0.1,宿主机端口映射也可能访问不到该服务。应用在容器里通常应监听 0.0.0.0。
Compose 示例:
services:
app:
image: example/app:1.0.0
ports:
- "8080:8080"
environment:
SERVER_ADDRESS: "0.0.0.0"容器间通信不要用宿主机映射端口,而应该使用同一个 Docker 网络里的服务名和容器端口:
services:
app:
image: example/app:1.0.0
depends_on:
- redis
environment:
REDIS_HOST: redis
REDIS_PORT: "6379"
redis:
image: redis:7在这个例子里,app 访问 redis:6379,不是访问宿主机的 6379。如果把容器间访问写成宿主机 IP,迁移环境、换网络、进 K8S 后都会变脆。
Redis Cluster、数据库集群、消息队列这类组件还要注意“对外宣告地址”。例如集群节点把自己宣告成 127.0.0.1,其他容器或其他机器就会连回自己本机,集群必然异常。跨容器、跨机器部署时,宣告地址要使用对其他节点可达的内网 IP 或 DNS 名称,相关端口和集群总线端口也要同时放行。
Nginx 入口:先分清入口端口和 upstream 端口
Nginx 通常站在入口层:客户端访问 Nginx 的 80/443,Nginx 再转发到本机、内网、容器或 K8S 服务。
这里一定要分清两类端口:用户访问的是 Nginx 的入口端口,通常是 80 或 443;Nginx 访问的是后端 upstream 端口,可能是 8080、9000、容器服务名或 K8S Service。入口端口通,不代表 upstream 通;upstream 通,也不代表入口安全组已经放行。
最小反向代理:
server {
listen 80;
server_name app.example.com;
location / {
proxy_pass http://127.0.0.1:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}检查配置:
sudo nginx -t
sudo nginx -T | less
sudo systemctl reload nginx
sudo systemctl status nginx一般修改 Nginx 后先执行 nginx -t。如果这里报错,不要 reload;先把语法错误修掉。nginx -T 会展开完整配置,适合排查到底加载了哪个 server、哪个 location。
看监听:
ss -lntp '( sport = :80 or sport = :443 )'看日志:
sudo tail -f /var/log/nginx/access.log
sudo tail -f /var/log/nginx/error.log常见现象:
| 现象 | 优先检查 |
|---|---|
| 访问 Nginx 端口超时 | 安全组、系统防火墙、Nginx 是否监听 80/443 |
| 返回 404 | server_name、location、root/alias、请求路径 |
| 返回 502 | upstream 没监听、端口错、绑定地址错、容器网络错、协议错 |
| 返回 504 | upstream 慢、网络不通、超时参数过短、后端阻塞 |
| HTTPS 证书错误 | 证书链、域名不匹配、SNI、过期、客户端不信任 CA |
排 502 时,不要先改 Nginx 超时,先在 Nginx 所在机器上访问 upstream:
curl -v http://127.0.0.1:8080/health
curl -v http://10.0.1.20:8080/health
nc -vz 10.0.1.20 8080如果这些命令都失败,说明 Nginx 到后端这段链路就不通。这个时候调 proxy_read_timeout 没意义,先让 upstream 进程监听起来,或者修正 Docker/K8S/安全组配置。
如果 upstream 是 Docker 容器,确认 Nginx 跟容器是否在同一网络。如果 Nginx 在宿主机,通常访问宿主机映射端口或容器绑定地址;如果 Nginx 也在 Compose 网络里,优先访问服务名和容器端口。
HTTPS 入口要注意 SNI:
openssl s_client -connect app.example.com:443 -servername app.example.com </dev/null
curl -v --resolve app.example.com:443:10.0.1.15 https://app.example.com/如果用 IP 直接访问 HTTPS,证书域名很可能不匹配;这不是端口问题,而是 TLS 校验正常工作。
K8S Service / Ingress:只讲部署排障边界
K8S 里端口链路更长,但排障仍然按“是否监听、是否转发、是否有后端”来拆。
很多人一遇到 K8S 访问失败,就开始怀疑 CNI。实际现场里,更多问题是 Service selector 写错、Pod 没 Ready、targetPort 不对、Ingress Controller 没起来、节点安全组没开。先把这些基础对象查完,再考虑网络插件深层问题。
典型路径:
Client -> LoadBalancer / NodePort / Ingress -> Service -> EndpointSlice -> Pod -> Container Port -> App先看对象:
kubectl get pods -A -o wide
kubectl get svc -A
kubectl get ingress -A
kubectl get endpoints -A
kubectl get endpointslice -A看某个服务:
kubectl -n default describe svc app
kubectl -n default get endpoints app -o wide
kubectl -n default describe ingress appService 常见类型:
| 类型 | 作用 | 排障重点 |
|---|---|---|
ClusterIP | 集群内访问 | Pod 内 DNS、Service selector、Endpoint 是否存在 |
NodePort | 通过节点端口访问 | 节点安全组、防火墙、NodePort 范围、kube-proxy |
LoadBalancer | 云负载均衡入口 | 云 LB、监听、健康检查、安全组、Service 状态 |
ExternalName | 返回外部 DNS 名称 | DNS 解析和外部服务可达性 |
Service 不会凭空找到 Pod,它靠 selector 匹配 Pod label。Service 没有 Endpoint 时,通常是 selector 错、Pod 没 Ready、端口名不匹配或后端根本没起来。
查看 selector:
kubectl -n default get svc app -o yaml
kubectl -n default get pods --show-labels在集群内验证:
kubectl -n default run netshoot --rm -it --image=nicolaka/netshoot -- /bin/bash
curl -v http://app.default.svc.cluster.local:8080/health
nc -vz app.default.svc.cluster.local 8080这个临时工具 Pod 很好用,但内网集群不一定能直接拉公网镜像。生产或离线环境一般需要提前把排障镜像同步到私有仓库,例如替换成 <内部仓库>/netshoot:tag。如果没有临时工具镜像,使用已有业务 Pod:
kubectl -n default exec -it <pod-name> -- sh
curl -v http://app:8080/health本机临时转发验证:
kubectl -n default port-forward svc/app 18080:8080
curl -v http://127.0.0.1:18080/healthIngress 不是内置魔法。创建 Ingress 资源不等于入口立刻可用,集群里必须有 Ingress Controller,并且外部流量要能到达 Controller。Ingress 主线处理 HTTP/HTTPS 路由,不适合直接承载任意 TCP 协议。数据库、Redis、MQ 这类 TCP 服务通常要用 Service、LoadBalancer、专门网关或云产品暴露。
Ingress 排障:
kubectl get ingressclass
kubectl -n ingress-nginx get pods -o wide
kubectl -n ingress-nginx logs deploy/ingress-nginx-controller --tail=100
kubectl -n default describe ingress app
curl -v -H 'Host: app.example.com' http://<Ingress入口IP>/K8S DNS 常见形式:
service-name.namespace.svc.cluster.local例如:
curl -v http://app.default.svc.cluster.local:8080/healthDNS 失败时看 CoreDNS:
kubectl -n kube-system get pods -l k8s-app=kube-dns
kubectl -n kube-system logs -l k8s-app=kube-dns --tail=100不同发行版和托管集群的 label 可能不同,找不到时直接看:
kubectl -n kube-system get pods | grep -i dns本文不深入 CNI、kube-proxy、iptables/ipvs/eBPF 细节。部署排障先把 Service、Endpoint、Ingress Controller、节点安全组、Pod 监听和应用健康检查看清楚,绝大多数问题已经能定位到具体层。
进入具体错误之前,先用现象把问题分流。下面这张决策图适合贴在排障 SOP 前面:值班同学先拿 curl -v、nc -vz、ss -lntp 和必要时的 tcpdump 归类现象,再进入对应小节,不要一看到访问失败就同时改 DNS、防火墙和 Nginx。
这张图的价值在于把“网络不通”拆成可验证的错误类型。Connection refused 优先回到监听和绑定地址;timeout 优先看包有没有到服务端;No route to host 优先看路由和网段;TLS/HTTP 错误说明 TCP 已经通了;502/504 通常已经进入入口代理到后端这一段。先分流,再动配置,才能减少生产上越修越乱的概率。
常见错误一:Connection refused
Connection refused 通常表示 TCP 包到了目标机器或目标网络栈,但目标端口没有进程接收,或者中间设备明确拒绝。
典型输出:
curl: (7) Failed to connect to 10.0.1.15 port 8080: Connection refused优先检查:
ss -lntp '( sport = :8080 )'
curl -v http://127.0.0.1:8080/
curl -v http://10.0.1.15:8080/常见原因:
| 场景 | 原因 |
|---|---|
| 普通进程 | 服务没启动、监听端口不是 8080、启动失败 |
| 绑定地址 | 服务只监听 127.0.0.1,外部访问内网 IP 被拒绝 |
| Docker | 容器没映射端口,或容器内应用没监听 |
| Nginx upstream | upstream 端口没进程,Nginx 返回 502 |
| K8S | Service 有地址但 Endpoint 为空,或 Pod 端口错 |
| 防火墙 | REJECT 规则显式拒绝 |
处理方式不是“开放所有端口”,而是先让正确进程监听正确地址,再放行必要来源。
常见错误二:timeout
timeout 通常表示连接请求发出去后没有得到回应。最常见原因是包被丢弃、路由不通、安全组未放行、系统防火墙 DROP、网段 ACL、VPN、代理或公网链路问题。
典型输出:
curl: (28) Failed to connect to 10.0.1.15 port 8080 after 3001 ms: Timeout was reached排查顺序:
# 客户端
ip route
nc -vz -w 3 10.0.1.15 8080
curl -v --connect-timeout 3 http://10.0.1.15:8080/
traceroute 10.0.1.15
# 服务端
ss -lntp '( sport = :8080 )'
sudo firewall-cmd --list-all 2>/dev/null || true
sudo iptables -L -n -v --line-numbers 2>/dev/null || true如果有权限,可以在服务端抓包确认包有没有到:
sudo tcpdump -i any host <客户端IP> and tcp port 8080解释:
| 抓包现象 | 含义 |
|---|---|
| 服务端完全看不到 SYN | 包没到服务端,查安全组、路由、ACL、VPN、中间网络 |
| 看到 SYN,没有 SYN-ACK | 服务端防火墙或内核没有回应 |
| 看到 SYN/SYN-ACK,客户端仍超时 | 回程路由、防火墙或非对称路由 |
| 握手完成,HTTP 无响应 | 应用层慢、线程阻塞、代理等待 |
timeout 比 refused 更像网络层问题,但也可能是应用 accept 队列满、线程池耗尽、TLS 握手卡住、代理连接池耗尽。要结合 ss -ant、应用日志和监控一起看。
常见错误三:No route to host
No route to host 表示客户端本机或中间网络认为目标不可达,或者收到了某类不可达响应。
典型输出:
curl: (7) Failed to connect to 10.0.1.15 port 8080: No route to host检查:
ip addr
ip route
ping -c 4 10.0.1.15
tracepath 10.0.1.15常见原因:
- 客户端不在正确 VPN、VPC、专线或内网。
- 目标 IP 写错,访问了不存在的网段。
- 路由表没有到目标网段的路由。
- 云上路由表、NACL、安全组拒绝。
- 系统防火墙返回不可达。
如果同网段另一台机器能访问,而当前机器不行,优先查当前机器路由、VPN、代理和本机防火墙。如果同网段都不行,查目标服务、安全组、系统防火墙和路由表。
常见错误四:DNS 解析失败或解析错
典型输出:
curl: (6) Could not resolve host: app.example.com检查:
getent hosts app.example.com
dig app.example.com
dig @<DNS服务器IP> app.example.com
cat /etc/resolv.conf如果解析到了错误 IP:
curl -v --resolve app.example.com:80:10.0.1.15 http://app.example.com/
curl -v --resolve app.example.com:443:10.0.1.15 https://app.example.com/如果 --resolve 后访问正常,说明服务端链路大概率没问题,问题集中在 DNS、hosts 或代理。
内网域名建议有明确命名和管理规则,不要长期依赖每台机器手工改 hosts。hosts 适合临时验证、灰度切换和离线环境小规模部署;一旦机器数量增加,就应该进入内部 DNS、配置管理或发布系统。
常见错误五:证书和代理导致的“网络不通”
HTTPS 错误经常被误判成端口不通。端口通了,TLS 校验失败,用户看到的仍然是访问失败。
常见证书问题:
| 现象 | 原因 |
|---|---|
| certificate has expired | 证书过期 |
| certificate is not yet valid | 服务器时间错误或证书生效时间未到 |
| certificate is not trusted | 客户端不信任 CA |
| hostname does not match | 证书域名和访问域名不匹配 |
| wrong version number | 用 HTTPS 访问了 HTTP 端口,或反过来 |
检查:
date
openssl s_client -connect app.example.com:443 -servername app.example.com </dev/null
curl -v https://app.example.com/企业内网如果使用内部 CA,要把根证书下发到服务器、容器镜像、JDK truststore、浏览器和运行时环境。否则命令行、Java 应用、Node 应用、浏览器可能表现不一致。
代理问题也常见:
env | grep -i proxy
curl -v https://app.example.com/
curl -v --noproxy '*' https://app.example.com/curl -v 输出里如果出现 Uses proxy env variable、CONNECT proxy 等信息,就说明请求走了代理。访问内网域名、K8S Service、私有仓库、数据库代理时,要确认 no_proxy 覆盖了这些地址。
中国大陆、企业内网和离线环境方案
部署运维文章不能默认服务器能访问 GitHub、Docker Hub、国外软件源、公共 DNS 和公网 CA。网络排障也一样,环境约束要提前写进方案。
中国大陆公网
中国大陆公网部署重点:
- 域名接入中国内地服务器时,按云厂商和监管要求处理备案。
- 80/443 要同时检查云安全组、系统防火墙、Nginx 监听和证书。
- Docker Hub、GitHub、国外 apt/yum/npm/Maven 源可能不稳定,要准备国内镜像源、云厂商仓库、内部缓存或离线包。
- 证书申请要考虑 HTTP-01 和 DNS-01 的网络条件。
- 不要把数据库、Redis、MQ、管理端口暴露到公网。
验证清单:
dig app.example.com
curl -v http://app.example.com/
curl -v https://app.example.com/
ss -lntp '( sport = :80 or sport = :443 )'云控制台检查:
- 实例绑定的安全组。
- 负载均衡监听和后端健康检查。
- 云防火墙、WAF、CDN、NAT 网关。
- 公网带宽和 EIP 绑定状态。
企业内网
企业内网重点:
- 内部 DNS 要能解析业务域名、仓库域名、K8S 内部域名。
- 办公网、服务器区、数据库区、DMZ、测试区之间通常有 ACL,不能默认互通。
- 服务器访问外网可能必须走代理,但访问内网服务不能误走代理。
- 内部 CA 证书要进入操作系统、浏览器、JDK、容器镜像和 CI 运行环境。
- 跳板机、堡垒机、VPN、专线断开时,排障现象会像端口不通。
内网验证命令:
getent hosts app.example.internal
curl -v --noproxy '*' http://app.example.internal:8080/health
nc -vz app.example.internal 8080
ip route代理建议:
export http_proxy=http://proxy.example.internal:8080
export https_proxy=http://proxy.example.internal:8080
export no_proxy="localhost,127.0.0.1,.example.internal,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16,.svc,.cluster.local"完全离线环境
离线环境不要到了现场再发现缺工具。至少提前准备:
| 类别 | 建议准备 |
|---|---|
| 基础命令 | iproute2、curl、bind-utils / dnsutils、traceroute、tcpdump、lsof、nc |
| 防火墙 | firewalld、iptables、nftables 对应包和持久化工具 |
| 容器 | Docker / containerd 安装包、镜像 tar 包、私有仓库地址 |
| 证书 | 内部 CA、服务端证书、过期时间清单、JDK truststore 更新脚本 |
| DNS | 内部 DNS 记录、临时 hosts 清单、回滚记录 |
| 端口 | 服务端口矩阵、安全组/防火墙规则、来源白名单 |
| 验证脚本 | curl、nc、ss、dig、kubectl 验证脚本 |
离线交付建议把“网络验证”做成固定脚本,输出每个节点的监听、解析、端口连通和证书状态:
#!/usr/bin/env bash
set -euo pipefail
targets=(
"app.example.internal:8080"
"nginx.example.internal:443"
"mysql.example.internal:3306"
)
for item in "${targets[@]}"; do
host="${item%:*}"
port="${item##*:}"
echo "== $host:$port =="
getent hosts "$host" || true
nc -vz -w 3 "$host" "$port" || true
done离线环境的关键不是命令多,而是每条命令都能在目标环境执行,依赖包、证书、DNS、端口策略、镜像和脚本都闭环。
生产端口矩阵要提前维护
团队一旦有多台机器、多套环境、多类组件,就不要靠口头记忆管理端口。建议维护端口矩阵:
| 服务 | 监听地址 | 端口 | 协议 | 暴露范围 | 允许来源 | 验证命令 | 负责人 |
|---|---|---|---|---|---|---|---|
| Nginx | 0.0.0.0 | 80/443 | TCP/HTTP(S) | 公网或内网入口 | 用户网段 / LB | curl -v | 运维 |
| App | 127.0.0.1 / 内网 IP | 8080 | TCP/HTTP | Nginx 或内网 | Nginx 节点 | curl /health | 应用组 |
| MySQL | 内网 IP | 3306 | TCP | 内网 | 应用网段 / DBA | nc -vz | DBA |
| Redis | 内网 IP | 6379 | TCP | 内网 | 应用网段 | redis-cli ping | 中间件 |
| K8S NodePort | 节点 IP | 30000-32767 | TCP | 视集群而定 | LB / 运维网段 | curl / nc | 平台组 |
矩阵要跟发布流程绑定:
- 新增服务必须申请端口和来源范围。
- 开放安全组和防火墙必须有变更记录。
- 发布验证必须包含端口、健康检查、日志和证书。
- 下线服务必须回收端口和安全组规则。
- 临时放行必须有过期时间。
排障 SOP:本机通,外部不通
服务端:
ss -lntp '( sport = :8080 )'
curl -v http://127.0.0.1:8080/health
curl -v http://<服务端内网IP>:8080/health如果 127.0.0.1 通,内网 IP 不通,改服务绑定地址。
如果服务端内网 IP 通,其他机器不通,查防火墙:
firewall-cmd --state 2>/dev/null || true
firewall-cmd --list-all 2>/dev/null || true
iptables -L -n -v --line-numbers 2>/dev/null || true客户端:
getent hosts <域名>
ip route
nc -vz -w 3 <服务端内网IP> 8080
curl -v --connect-timeout 3 http://<服务端内网IP>:8080/health然后查云安全组、NACL、VPN、专线、堡垒机来源 IP 和代理。
排障 SOP:容器 Up 但服务不可访问
先看容器状态和端口:
docker ps --format 'table {{.Names}}\t{{.Status}}\t{{.Ports}}'
docker logs --tail=100 <container>
docker port <container>进入容器看监听:
docker exec -it <container> sh
ss -lntp
curl -v http://127.0.0.1:<容器端口>/health宿主机看映射:
ss -lntp '( sport = :8080 )'
curl -v http://127.0.0.1:8080/health
curl -v http://<宿主机内网IP>:8080/health常见修复:
docker run增加-p 宿主机端口:容器端口。- 应用从
127.0.0.1改为监听0.0.0.0。 - Compose 服务间访问改为服务名和容器端口。
- 安全组和系统防火墙放行宿主机端口。
- 集群组件修正 announce IP,不要宣告
127.0.0.1。
排障 SOP:Nginx 502 / 504
看 Nginx 配置和日志:
sudo nginx -t
sudo nginx -T | less
sudo tail -f /var/log/nginx/error.log在 Nginx 所在机器直接访问 upstream:
curl -v http://127.0.0.1:8080/health
curl -v http://<upstream-ip>:8080/health
nc -vz <upstream-ip> 8080判断:
| 现象 | 方向 |
|---|---|
| upstream refused | 后端没启动、端口错、绑定地址错 |
| upstream timeout | 后端慢、网络丢包、防火墙 DROP、线程池阻塞 |
| no live upstreams | upstream 全部不可用或健康检查失败 |
| SSL handshake failed | Nginx 到 upstream 使用 HTTPS,但证书或 SNI 不匹配 |
只在确认后端确实慢且业务允许等待时,再调大超时:
proxy_connect_timeout 3s;
proxy_read_timeout 30s;
proxy_send_timeout 30s;超时参数不是修复网络不通的办法。它只能改变等待多久,不能让不可达变可达。
排障 SOP:K8S Service 不通
看 Pod:
kubectl -n default get pods -o wide
kubectl -n default describe pod <pod>
kubectl -n default logs <pod> --tail=100看 Service 和 Endpoint:
kubectl -n default get svc app -o wide
kubectl -n default describe svc app
kubectl -n default get endpoints app -o wide
kubectl -n default get endpointslice -l kubernetes.io/service-name=app如果 Endpoint 为空:
- 查 Service selector。
- 查 Pod label。
- 查 Pod readiness。
- 查 targetPort 和容器端口。
集群内验证:
kubectl -n default exec -it <pod> -- sh
curl -v http://app.default.svc.cluster.local:8080/healthIngress 验证:
kubectl get ingressclass
kubectl -n default describe ingress app
curl -v -H 'Host: app.example.com' http://<ingress-ip>/如果集群内 Service 通,Ingress 不通,问题在 Ingress Controller、Ingress 规则、入口安全组、证书或外部负载均衡。如果 Pod 内应用不通,先回到应用监听和容器端口,不要先怀疑 K8S 网络模型。
落地工程深水区
网络排障最怕“能通就行”的临时处理。今天为了止血关掉防火墙,明天为了赶发布开放 0.0.0.0/0,几个月后谁也说不清哪些端口应该存在。
| 深水问题 | 现场表现 | 落地约束 |
|---|---|---|
| 端口资产没人维护 | 机器上监听了一堆旧端口,安全组里也不知道谁在用 | 建立端口矩阵:服务名、监听地址、端口、来源、负责人、健康检查、回收时间 |
| 临时放行不回收 | 排障时开了大网段,故障结束后忘记收口 | 临时规则必须带过期时间和工单号,巡检脚本定期检查 0.0.0.0/0 和宽端口段 |
| 绑定地址误判 | 服务只监听 127.0.0.1,外部永远访问不到 | 发布前必须检查 ss -lntp,区分 127.0.0.1、内网 IP、0.0.0.0 |
| 安全边界叠加 | 云安全组、NACL、系统防火墙、Docker、Nginx、K8S 任一层拦截 | 排障 SOP 固定按客户端、DNS、入口、云边界、OS、容器/编排、应用逐层验证 |
| 内网 DNS 不稳定 | 容器、宿主机、办公终端解析结果不同 | 记录企业 DNS、resolv.conf、Docker daemon DNS、K8S CoreDNS 和 no_proxy 策略 |
| 观测缺口 | 只知道“超时”,不知道是 DROP、REJECT、连接池耗尽还是后端慢 | 日志里保留 upstream 状态、响应时间、客户端 IP;监控 TCP 连接、5xx、DNS 失败和入口延迟 |
| 自动化误伤 | 脚本批量刷新 iptables 或 firewalld,导致 SSH 断开 | 防火墙脚本先 runtime 验证,再持久化;远程操作前保留回滚会话和 out-of-band 通道 |
团队层面建议把“开端口”升级成“发布入口变更”:谁申请、为什么开、开给谁、验证命令是什么、什么时候回收,都要能查到。否则端口治理会慢慢变成安全事故。
生产检查清单
端口和网络治理建议长期坚持这些规则:
- 端口不通先按链路定位,不要先关防火墙。
- Web 入口、应用端口、数据库端口、管理端口分层暴露。
- 服务需要跨机器访问时,明确绑定
0.0.0.0或内网 IP;只给本机代理访问时,绑定127.0.0.1。 ss -lntp、curl -v、nc -vz、dig/getent是基础排障四件套。ping只能辅助判断主机可达,不能证明端口可达。- firewalld 修改要区分 runtime 和 permanent。
- iptables 要看规则顺序、默认策略和持久化方式。
- 云安全组只开放必要端口和必要来源,数据库和缓存不要对公网开放。
- Docker
EXPOSE不等于发布端口,-p默认发布范围要谨慎。 - Nginx 502 先查 upstream 是否可达,不要先改超时。
- K8S Service 不通先查 Endpoint,不要直接钻 CNI 深水区。
- 内网域名、代理、证书、
no_proxy要写进交付文档。 - 离线环境提前带齐网络排障工具、证书、DNS 记录和端口矩阵。
- 临时放行要有过期时间,排障结束要回收。
- 每次上线后验证端口、健康检查、日志、证书和核心接口。
官方文档入口
这些入口适合在落地前重新校准命令和平台行为:
- firewalld
firewall-cmd手册:https://firewalld.org/documentation/man-pages/firewall-cmd.html - iptables 手册:https://man7.org/linux/man-pages/man8/iptables.8.html
- nftables 手册:https://netfilter.org/projects/nftables/manpage.html
ss手册:https://man7.org/linux/man-pages/man8/ss.8.htmlnetstat手册:https://man7.org/linux/man-pages/man8/netstat.8.htmlhosts手册:https://man7.org/linux/man-pages/man5/hosts.5.htmlresolv.conf手册:https://man7.org/linux/man-pages/man5/resolv.conf.5.html- curl 手册:https://curl.se/docs/manpage.html
- tcpdump 手册:https://www.tcpdump.org/manpages/tcpdump.1.txt
- pcap-filter 过滤表达式手册:https://www.tcpdump.org/manpages/pcap-filter.7.txt
- traceroute 手册:https://man7.org/linux/man-pages/man8/traceroute.8.html
- Docker 端口发布文档:https://docs.docker.com/engine/network/port-publishing/
- Nginx
listen文档:https://nginx.org/en/docs/http/ngx_http_core_module.html#listen - Nginx
proxy_pass文档:https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_pass - Kubernetes Service 文档:https://kubernetes.io/docs/concepts/services-networking/service/
- Kubernetes Ingress 文档:https://kubernetes.io/docs/concepts/services-networking/ingress/
- Kubernetes DNS 文档:https://kubernetes.io/docs/concepts/services-networking/dns-pod-service/
- 阿里云 ECS 安全组规则:https://help.aliyun.com/zh/ecs/user-guide/security-group-rules
- 腾讯云安全组规则:https://cloud.tencent.com/document/product/213/112614
网络排障最后拼的是耐心和顺序。端口不通不是一个点的问题,而是一条链路的问题。把监听、绑定、解析、路由、防火墙、安全组、容器映射、入口代理、证书和代理逐层拆开,故障就会从一团雾变成一张可以勾选的清单。
