关于docker:kuberouter实现networkpolicy的原理

4次阅读

共计 6333 个字符,预计需要花费 16 分钟才能阅读完成。

简介

kube-router 是一套开源网络计划,基于 bgp 协定构建路由,从而构建整个容器集群网络,它应用 ipvs 实现了 k8s 的 service 网络,并应用 ipset 和 iptables 工具实现了 networkpolicy。

咱们晓得 calico 对于 networkpolicy 的实现也是 ipset+iptables 这一套,本文将联合源码和实例,介绍 kube-router 是如何实现 networkpolicy 的,并剖析它与 calico 在设计上的异同。

简要概括

kube-router 在节点上启动一个 agent 同步 pod、networkpolicy 对象的信息,并构建 iptables 规定和 ipset 汇合。次要的程序入口在func (npc *NetworkPolicyController) fullPolicySync()。读者能够本人浏览源码,挺清晰的。

规定解决分为四步:

  1. 顶层规定集: npc.ensureTopLevelChains()
  2. networkpolicy 粒度的规定集: networkPoliciesInfo, err = npc.buildNetworkPoliciesInfo() ; activePolicyChains, activePolicyIPSets, err := npc.syncNetworkPolicyChains(networkPoliciesInfo, syncVersion)
  3. pod 粒度规定集:activePodFwChains, err := npc.syncPodFirewallChains(networkPoliciesInfo, syncVersion)
  4. 清理 stale 规定 err = cleanupStaleRules(activePolicyChains, activePodFwChains, activePolicyIPSets)

顶层规定集

与 calico 一样,在 INPUT/FORWARD/OUTPUT 三个中央做 hook。别离 hook 到 KUBE-ROUTER-INPUT、KUBE-ROUTER-FORWARD、KUBE-ROUTER-OUTPUT。

KUBE-ROUTER-FORWARD、KUBE-ROUTER-OUTPUT 两个链中没有什么非凡的规定,间接就进入到了各个 pod 粒度的规定集中。

KUBE-ROUTER-INPUT 链中做了一些非凡目标地址的 egress 白名单,如下:

  1. 容许拜访 service cidr

-d $SERVICE_RANGE -j RETURN

  1. 容许拜访 nodeport port range

-p tcp/udp -m addrtype --dst-type LOCAL -m multiport --dports $NODEPORT_RANGE -j RETURN

  1. 容许拜访 service external ip

-d $SERVICE_EXTERNAL_RANGE -j RETURN

  1. 各个 pod 的规定

networkpolicy 粒度规定集

networkpolicy 粒度的规定以 KUBE-NWPLCY 为前缀,一个规定一个链。

来个例子:

Chain KUBE-NWPLCY-4UOMHLJABMXP4VW2 (1 references)
target     prot opt source               destination
MARK       all  --  anywhere             anywhere             /* rule to ACCEPT traffic from source pods to dest pods selected by policy
name access-pod namespace default */ match-set KUBE-SRC-IMXDMRGLZFP7QJCX src match-set KUBE-DST-5CXCQ5O6AOA47RC6 dst /* rule to mark traf
fic matching a network policy */ MARK or 0x10000
RETURN     all  --  anywhere             anywhere             /* rule to ACCEPT traffic from source pods to dest pods selected by policy
name access-pod namespace default */ match-set KUBE-SRC-IMXDMRGLZFP7QJCX src match-set KUBE-DST-5CXCQ5O6AOA47RC6 dst /* rule to RETURN tr
affic matching a network policy */ mark match 0x10000/0x10000
MARK       all  --  anywhere             anywhere             /* rule to ACCEPT traffic from source pods to specified ipBlocks selected b
y policy name: access-pod namespace default */ match-set KUBE-SRC-5CXCQ5O6AOA47RC6 src match-set KUBE-DST-7VKW2UTKN2UOEU4I dst /* rule to
 mark traffic matching a network policy */ MARK or 0x10000
RETURN     all  --  anywhere             anywhere             /* rule to ACCEPT traffic from source pods to specified ipBlocks selected b
y policy name: access-pod namespace default */ match-set KUBE-SRC-5CXCQ5O6AOA47RC6 src match-set KUBE-DST-7VKW2UTKN2UOEU4I dst /* rule to
 RETURN traffic matching a network policy */ mark match 0x10000/0x10000

一个KUBE-NWPLCY-*** chain 里形容了一个 networkpolicy 对象,对于该对象的每一个 rule(ingress or egress),咱们都会有如下的操作:

  1. 判断源地址 + 端口 / 目标地址 + 端口是否合乎 ingress/egress rule。如果合乎就打 mark: MARK or 0x10000。这里的地址匹配,是一个 ipset
  2. 判断 mark 是否匹配mark match 0x10000/0x10000, 如果匹配,return,如果不匹配,再查看下一个 rule 的规定。

pod 粒度规定集

从顶层规定集中,kube-router 基于包的源 / 目标 IP 跳转到相应的 pod 粒度规定集。

如何进入 pod 粒度集

因为 kube-router 对接的网络插件是官网的 bridge 插件,node 上容器 host-veth 都绑在网桥上,pod 彼此之间属于二层互联(包间接桥接转发)

所以同一个 node 上的 pod-to-pod 的包会间接在 bridge 进行二层转发,这类包必须要经由如下的 iptables 规定解决:

-t filter KUBE-ROUTER-FORWARD -m physdev --physdev-is-bridged -m comment --comment "******" -d $POD_IP -j KUBE-POD-FW-XXXXX (匹配某个 pod 的 ingress policy)    例:同 node 的 pod 要拜访本 pod,node 对 pod 做健康检查
-t filter KUBE-ROUTER-FORWARD -m physdev --physdev-is-bridged -m comment --comment "******" -s $POD_IP -j KUBE-POD-FW-XXXXX (匹配某个 pod 的 egress policy)    例:本 pod 要拜访同 node 其余 pod

留神:

  • XXXXX是 pod 的 ns+name 的 hash,但格局与 calico 不一样
  • 同一个 node 上的 pod-to-pod 走二层转发,这个过程想要被 netfilter hook,须要加载 br_netfilter 模块,并且开启 /proc/sys/net/bridge/bridge-nf-call-iptables ,/proc/sys/net/bridge/bridge-nf-call-ip6tables 为 1

除此之外的包,都是通过对方向、src 或 dst IP 的匹配,来进入特定 pod 的规定链。例如:

-t filter KUBE-ROUTER-FORWARD -d $POD_IP -j KUBE-POD-FW-XXXXX (匹配某个 pod 的 ingress policy) 例:其余节点(及上的 pod)拜访 pod
-t filter KUBE-ROUTER-OUTPUT -d $POD_IP -j KUBE-POD-FW-XXXXX (匹配某个 pod 的 ingress policy)
-t filter KUBE-ROUTER-INPUT -s $POD_IP -j KUBE-POD-FW-XXXXX (匹配某个 pod 的 egress policy) 例:pod 拜访其余任何地址
-t filter KUBE-ROUTER-FORWARD -s $POD_IP -j KUBE-POD-FW-XXXXX (匹配某个 pod 的 egress policy)
-t filter KUBE-ROUTER-OUTPUT -s $POD_IP -j KUBE-POD-FW-XXXXX (匹配某个 pod 的 egress policy)

pod 粒度规定集里有什么?

ingress policy

在 KUBE-POD-FW-XXXXX 链中,增加了若干规定:

一、曾经建设的连贯,间接承受

-t filter KUBE-POD-FW-XXXXX -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT

二、所有从 node 拜访过去的包,都予以承受

-t filter KUBE-POD-FW-XXXXX -m addrtype --src-type LOCAL -d $POD_IP -j ACCEPT

三、其余状况下,须要基于匹配该 pod 的每个 ingress policy,都增加一条 jump 规定:

-t filter KUBE-POD-FW-XXXXX -j XXXXXXXXX  (XXXXXXXXX 示意作用于该 pod 的第一个 networkpolicy 的 ns+name 的 hash)
-t filter KUBE-POD-FW-XXXXX -j XXXXXXXXY  (XXXXXXXXY 示意作用于该 pod 的第二个 networkpolicy 的 ns+name 的 hash)
...

egress policy

一、曾经建设的连贯,间接承受

-t filter KUBE-POD-FW-XXXXX -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT

二、其余状况下,须要基于匹配该 pod 的每个 egress policy,都增加一条 jump 规定:

-t filter KUBE-POD-FW-XXXXX -j XXXXXXXXX  (XXXXXXXXX 示意作用于该 pod 的第一个 networkpolicy 的 ns+name 的 hash)
-t filter KUBE-POD-FW-XXXXX -j XXXXXXXXY  (XXXXXXXXY 示意作用于该 pod 的第二个 networkpolicy 的 ns+name 的 hash)
...

示例

Chain KUBE-POD-FW-VFY4MIYKQH6U2ZBK (7 references)
target     prot opt source               destination
ACCEPT     all  --  anywhere             anywhere             /* rule for stateful firewall for pod */ ctstate RELATED,ESTABLISHED
ACCEPT     all  --  anywhere             10.0.0.24            /* rule to permit the traffic traffic to pods when source is the pod's loca
l node */ ADDRTYPE match src-type LOCAL
KUBE-NWPLCY-4UOMHLJABMXP4VW2  all  --  anywhere             anywhere             /* run through nw policy access-pod */
KUBE-NWPLCY-TOUTUXPCBONZJXQA  all  --  anywhere             anywhere             /* run through nw policy access-pod-and-node */
NFLOG      all  --  anywhere             anywhere             /* rule to log dropped traffic POD name:hyserver-d4f9cf4df-55ggn namespace:
 default */ mark match ! 0x10000/0x10000 limit: avg 10/min burst 10 nflog-group 100
REJECT     all  --  anywhere             anywhere             /* rule to REJECT traffic destined for POD name:hyserver-d4f9cf4df-55ggn na
mespace: default */ mark match ! 0x10000/0x10000 reject-with icmp-port-unreachable
MARK       all  --  anywhere             anywhere             MARK and 0xfffeffff

咱们留神到,先是 Accept 了已成立的连贯和来自宿主机的 IP,而后就会遍历所有的 networkpolicy,全副走一遍后,判断 mark,如果 mark 不匹配,打印日志,并且 reject,如果匹配,咱们将用于标记的那一位再置 0:MARK and 0xfffeffff

整体上的链路如下图:

总结

依据对 kube-router 的实现判断,能够看出它和 calico-felix 在实现上的一些区别。kube-router 的规定脉络更清晰,更简略,而且有充沛的 comment 进行判断和跟踪。最重要的是,它是基于 pod IP 进行匹配的;felix 在规定上更简单,然而做了一些优化,所以从设计上看,性能应该会比 kube-router 更好。体现在:

  1. felix 基于网卡做前缀判断 pod 流量,相比于依据 pod IP(记录于 etcd)更精确靠谱一些
  2. felix 基于网卡前缀做分表,能够节俭遍历工夫
  3. felix 在任何一个 networkpolicy 规定匹配后间接 return,不须要遍历所有 networkpolicy。

kube-router 比拟人性化的中央在于:

  • 它默认放行了 node 对 pod 的被动拜访(兼容了健康检查)
  • 默认放行了 pod 对各种 service 的拜访(防止用户定义了过于严格的 egress 规定导致 pod 无法访问 dns 等要害 service)

所以应用上心智累赘会更少。

附录

calico 中 networkpolicy 的实现

能够参考[网易数帆 k8s 集群对 networkpolicy 的实际——felix]

iptables 中 physdev 选项的阐明

–physdev-in [name|prefix+|!name] 匹配从 name 端口进入网桥的数据包。(作用于 INPUT、FORWARD 和 PREROUTING 链),能够通过 ’+’ 对端口名进行前缀匹配。’!name’ 用于反向匹配。
–physdev-out [name|prefix+|!name] 匹配从 name 端口收回的数据包。(作用于 FORWARD、OUTPUT 和 POSTROUTING 链)
–physdev-is-in 匹配进入网桥数据包
–physdev-is-out 匹配来到网桥数据包
–physdev-is-bridged 匹配被桥接不是被路由的数据包。(作用于 FORWARD 和 POSTROUTING 链)

正文完
 0