一、常用问题梳理
笔者落地的istio只是接管了http的rpc流量,端口是8090(做了去安全处理,实际产品不是8090端口),istio的iptables使用的是nat表。
接管流量过程中碰到的几个问题:
1.istio-proxy容器里面设置iptables,需要开启特权模式或者在启动阶段通过--cap-add开放一些系统能力,并提供net_admin能力 (要注意的是net_admin能力会对宿主机有影响)
2.iptables开启劫持流量前已经建立好的长链接流量不会被接管,需要业务实现旧链接的主动断开机制,或者重启pod,java的话,可以tomcat里面设置定时优雅关闭逻辑,通过http的Connection:close来主动断开链接。
3.iptables清理配置以后,存量已经接管流量的链接,劫持流量还在,需要主动关闭链接,可以利用envoy的drwain-connection来操作定时断开。
4.业务层面如果是单pod循环调用自己这个pod的话,上面iptables的设置有防止死循环配置,会导致流量不通,解决思路是业务服务发现禁止自己pod调用自己。
二、iptables使用介绍
1.iptables的配置数据:
$ sudo iptables -t nat -S
-P PREROUTING ACCEPT
-P INPUT ACCEPT
-P OUTPUT ACCEPT
-P POSTROUTING ACCEPT
-N ISTIO_INBOUND
-N ISTIO_IN_REDIRECT
-N ISTIO_OUTPUT
-N ISTIO_REDIRECT
-A PREROUTING -s 188.251.1.1/32 -i veth1 -m comment --comment "xxxx PREROUTING rules" -j RETURN
-A PREROUTING -p tcp -j ISTIO_INBOUND
-A OUTPUT -p tcp -j ISTIO_OUTPUT
-A POSTROUTING ! -s 19.82.45.42/32 -o eth0 -m comment --comment "xxxxx SNAT rules" -j MASQUERADE
-A ISTIO_INBOUND -p tcp -m tcp --dport 15008 -j RETURN
-A ISTIO_INBOUND -p tcp -m tcp --dport 8090 -j ISTIO_IN_REDIRECT
-A ISTIO_IN_REDIRECT -p tcp -j REDIRECT --to-ports 15006
-A ISTIO_OUTPUT -s 127.0.0.6/32 -o lo -j RETURN
-A ISTIO_OUTPUT ! -d 127.0.0.1/32 -o lo -m owner --uid-owner 1337 -j ISTIO_IN_REDIRECT
-A ISTIO_OUTPUT -o lo -m owner ! --uid-owner 1337 -j RETURN
-A ISTIO_OUTPUT -m owner --uid-owner 1337 -j RETURN
-A ISTIO_OUTPUT ! -d 127.0.0.1/32 -o lo -m owner --gid-owner 1337 -j ISTIO_IN_REDIRECT
-A ISTIO_OUTPUT -o lo -m owner ! --gid-owner 1337 -j RETURN
-A ISTIO_OUTPUT -m owner --gid-owner 1337 -j RETURN
-A ISTIO_OUTPUT -d 127.0.0.1/32 -j RETURN
-A ISTIO_OUTPUT -p tcp -m tcp --dport 8080 -j ISTIO_REDIRECT
-A ISTIO_REDIRECT -p tcp -j REDIRECT --to-ports 15001
$
2.nat表数据流向总览:
数据包进入系统 → PREROUTING链 → 路由决策 →
├─ 到本机 → INPUT链 → 本机进程
├─ 转发 → FORWARD链 → POSTROUTING链 → 出系统
└─ 本机发出 → OUTPUT链 → POSTROUTING链 → 出系统
3.PREROUTING链调用树(入站和转发流量)
PREROUTING(nat表内置链)
├─ 规则1:-s 188.251.1.1/32 -i veth1 → RETURN(直接返回)
└─ 规则2:-p tcp → ISTIO_INBOUND(自定义链)
├─ 规则1:--dport 15008 → RETURN(返回PREROUTING)
└─ 规则2:--dport 8090 → ISTIO_IN_REDIRECT(自定义链)
└─ 规则1:-p tcp → REDIRECT --to-ports 15006(重定向)
调用顺序:
数据包进入 → PREROUTING链 →
↓ 匹配TCP协议
ISTIO_INBOUND链 →
↓ 匹配端口8090
ISTIO_IN_REDIRECT链 →
↓ 重定向到15006端口
处理完成,返回上层链
4.OUTPUT调用树(出口流量)
OUTPUT(nat表内置链)
└─ 规则1:-p tcp → ISTIO_OUTPUT(自定义链)
├─ 规则1:-s 127.0.0.6/32 -o lo → RETURN
├─ 规则2:! -d 127.0.0.1/32 -o lo --uid-owner 1337 → ISTIO_IN_REDIRECT
├─ 规则3:-o lo ! --uid-owner 1337 → RETURN
├─ 规则4:--uid-owner 1337 → RETURN
├─ 规则5:! -d 127.0.0.1/32 -o lo --gid-owner 1337 → ISTIO_IN_REDIRECT
├─ 规则6:-o lo ! --gid-owner 1337 → RETURN
├─ 规则7:--gid-owner 1337 → RETURN
├─ 规则8:-d 127.0.0.1/32 → RETURN
└─ 规则9:--dport 8090 → ISTIO_REDIRECT(自定义链)
└─ 规则1:-p tcp → REDIRECT --to-ports 15001(重定向)
调用顺序:
本机进程发送数据包 → OUTPUT链 →
↓ 匹配TCP协议
ISTIO_OUTPUT链 →
↓ 按顺序匹配13条规则
├─ 匹配到规则1-8 → RETURN(返回OUTPUT)
└─ 匹配到规则9 → ISTIO_REDIRECT链 →
↓ 重定向到15001端口
处理完成,返回上层链
5.POSTROUTING链(SNAT处理)
POSTROUTING(nat表内置链)
└─ 规则1:! -s 19.82.45.42/32 -o eth0 → MASQUERADE
6.数据包完整路径分析:
场景1:外部访问pod 8090端口
外部客户端 → 节点eth0 → PREROUTING链 → ISTIO_INBOUND链 → ISTIO_IN_REDIRECT链
↓ 重定向到15006
Sidecar Envoy(15006端口) → 应用容器(8090端口)
场景2:pod内部访问外部8090端口
应用进程 → OUTPUT链 → ISTIO_OUTPUT链 → ISTIO_REDIRECT链
↓ 重定向到15001
Sidecar Envoy(15001端口) → POSTROUTING链(SNAT) → 外部网络
场景3:pod内部访问本地回环
应用进程 → OUTPUT链 → ISTIO_OUTPUT链
↓ 匹配规则8(-d 127.0.0.1/32)
RETURN → POSTROUTING链 → 本地回环
场景4:envoy自身流量
Envoy进程 → OUTPUT链 → ISTIO_OUTPUT链
↓ 匹配规则4(--uid-owner 1337)
RETURN(避免循环) → POSTROUTING链 → 出系统
7.链之间的返回关系
PREROUTING(内置)
|
↓ (TCP流量)
ISTIO_INBOUND(自定义)
/ \
(15008端口)RETURN (8090端口)ISTIO_IN_REDIRECT
| |
返回PREROUTING ↓
REDIRECT 15006
|
返回ISTIO_INBOUND
|
返回PREROUTING
|
路由决策
OUTPUT(内置)
|
↓ (TCP流量)
ISTIO_OUTPUT(自定义)
/ | \
(匹配1-8)RETURN (8090端口)ISTIO_REDIRECT
| |
返回OUTPUT ↓
REDIRECT 15001
|
返回ISTIO_OUTPUT
|
返回OUTPUT
|
POSTROUTING
8.外部访问pod 8090端口的数据包路径:
-
数据包到达 eth0
-
nat表PREROUTING链匹配规则:-p tcp → 跳转到ISTIO_INBOUND
-
ISTIO_INBOUND链匹配规则:--dport 8090 → 跳转到ISTIO_IN_REDIRECT
-
ISTIO_IN_REDIRECT链执行:REDIRECT --to-ports 15006
-
数据包目标端口改为15006,返回ISTIO_INBOUND
-
ISTIO_INBOUND返回PREROUTING
-
PREROUTING没有更多规则,根据默认策略ACCEPT
-
路由决策,发现目标端口15006是本地端口
-
进入INPUT链(filter表),最终到达Sidecar Envoy进程
推荐的扩展阅读:
https://man7.org/linux/man-pages/man7/capabilities.7.html
https://blog.51cto.com/u_2010293/2781934
https://blog.csdn.net/weixin_44843710/article/details/124155548
https://www.json.cn/blog/2021/0107/p-16595.html