KubeProxy:IPtables 模式
文章目录
分析Kube-Proxy在默认工作模式(iptable mode)下,那些眼花缭乱的自定义规则,并绘制成图,希望后续能为定位集群的网络问题提供帮助。
1. KubeProxy:IPtables Mode
1. IPtables
简单回顾 IPtables 的工作原理:IPtables 在TCP/IP协议栈特定位置(Chain),根据一些设定的规则(Rule)过滤数据包,并对符合条件的数据包执行某些操作(ACTION)。
当数据包匹配某条Rule时,我们可以对数据包执行特定ACTION,以下是常用ACTION:
ACTION | 说明 | 后续操作 |
---|---|---|
ACCEPT | 允许数据包通过 | next Chain |
DROP | 丢弃数据包 | 中断 |
REJECT | 丢弃数据包,发送拒绝信息 | 中断 |
SNAT | 源地址转换 | next Chain |
DNAT | 目标地址转换 | next Chain |
REDIRECT | 目标端口转换 | next rule |
MARK | 将数据包打上标记 | next rule |
RETURN | parent Chain | |
MASQUERADE | 改写SRC IP为当前IP | next Chain |
LOG | 记录信息到/var/log | next rule |
MIRROR | 调换源IP和目的IP,将包发回 | 中断 |
QUEUE | 封包放入队列,交给其它程序处理 | 中断 |
在 IPtables 的体系中根据 Rule 的作用,将其分成4类(或者认为将其分为4个不同的表):
- filter:负责过滤功能
- nat:网络地址转换功能,典型的比如 SNAT、DNAT
- mangle:解包报文、修改并封包
- raw:关闭 nat 表上启用的连接追踪机制(conntrack)
在 netfilter 内核中的 Hook 点上,一串顺序执行的规则称为链。netfilter 提供了以下5个默认链:
chain | 允许表规则 |
---|---|
PreRouting | raw, mangle, nat |
Forward | mangle, filter |
Input | mangle, filter |
Output | raw, mangle, nat, filter |
PostRouting | mangle, nat |
数据包进入 IPtables 的流程如下:
更细致的流程图:
2. kube-proxy
在 Kubernetes 中,kube-proxy 是一个 L4(TCP/UDP/SCTP)负载均衡器,它使用 DNAT 将入站流量从Service IP重定向到后端 pod,可以说是除 CNI 之外 Kubernetes 网络体系中最重要的组成部分。
Kubernetes 中支持创建 ClusterIP、NodePort、LoadBalancer、ExternalName 四种类型的 Service ,下面详细叙述一下对于 ClusterIP 和 NodePort 的流量,kube-proxy 如何通过自定义 chain 实现流量转发。
kube-proxy 自定义以下 Chain 处理目的地址为 ClusterIP 或者 local:NodePort 的数据包。
- KUBE-SERVICES(nat.PREROUTING/nat.OUTPUT):安装在 PREROUTING 和 OUTPUT 链的最开始
- 将目标地址为 SVCIP:Port 的数据包分派到相应的 KUBE-SVC-xxx 链
- 将目标地址为本地网卡的数据包分派到 KUBE-NODEPORTS 链
- KUBE-NODEPORTS:根据 dst-port 匹配NodePort端口
- 数据包分派到相应的 KUBE-SVC-xxx 链(externalTrafficPolicy=Cluster)
- 数据包分派到相应的 KUBE-XLB-xxx 链(externalTrafficPolicy=Local)
- KUBE-SVC-xxx: 对应 service,数据包将随机进入 KUBE-SEP-xxx 链
- KUBE-XLB-xxx: 对应 service,数据包可能进入 KUBE-SEP-xxx 链或者被丢弃
- KUBE-SEP-xxx: 对应 endpoint 中的IP地址,数据包将 DNAT 到 Pod IP
- KUBE-FIREWALL(filter.INPUT/filter.OUTPUT):丢弃 0x8000 的包,主要用在 externalTrafficPolicy=Local的场景
- KUBE-MARK-MASQ:标记数据包为0x4000(需要SNAT)
- KUBE-MARK-DROP:标记数据包为0x8000(DROP包)
- KUBE-POSTROUTING(nat.POSTROUTING):MASQUERADE 0x4000 的包
数据包在iptable中的流向如下:
几个注意点:
- 物理访问 ClusterIP/NodePort 时,流量从output进入;本地容器中访问 ClusterIP/NodePort 时,流量从 PREROUTING 进入
- 那些流量会被 SNAT:
- 访问 ClusterIP:
- MasqueradeAll=true:所有Client的流量被 SNAT(PS:在POD中访问 ClusterIP,服务端也会丢失真实IP)
- MasqueradeAll=false:Pod以外的流量被 SNAT (PS:在POD中访问 ClusterIP,服务端可以获取POD的真实IP)
- 访问 host-ip:NodePort:
- externalTrafficPolicy=Cluster:必定被SNAT
- externalTrafficPolicy=Local:
- 本地HOST-IP:无论当前节点是否有 Pod 后端都进行 SNAT,剩余逻辑按照 externalTrafficPolicy=Cluster 时处理
- 其他HOST-IP(K8S集群其他Node的ip):不会进行 SNAT
- 容器通过ClusterIP访问自身(PS:访问的后端是自己,即POD通过 ClusterIP 访问自己,请求也可能丢失真实IP)
- 访问 ClusterIP:
参考文档
文章作者 yoaz
上次更新 2022-03-10
许可协议 MIT