Kubernetes 网络: kube-proxy 和 ipvs - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
GopherDaily
V2EX    Kubernetes

Kubernetes 网络: kube-proxy 和 ipvs

  •  
  •   GopherDaily 2023-04-13 00:59:35 +08:00 1743 次点击
    这是一个创建于 963 天前的主题,其中的信息可能已经有所发展或是发生改变。

    Link: http://blog.j2gg0s.com/2023/04/12/Kubernetes-%E7%BD%91%E7%BB%9C-kube-proxy-%E5%92%8C-ipvs.html

    Dustin Specker 有个Container Networking 系列的博客, 手动模拟了 kube-proxy 在 iptables/ipvs 下的相关逻辑, 非常有助理解. 我们在这儿也从零走一遍 ipvs 相关的逻辑.

    整个流程的大部分命令可以在 Makefile 中找到.

    创建独立的网络命名空间(netns) foo

    每个 Pod 都拥有自己独立的网络命名空间, 进而实现网络隔离. 即使同一 Node 上的不同 Pod 之间也无法直接访问, Pod 也无法直接访问 Node 的网络.

    ip netns add foo ip netns exec foo ip link set dev lo up 

    在默认网络命名空间中创建 bridge, 并通过 veth, 将 foo 和默认空间链接起来

    ip link add dev cni0 type bridge ip addr add 172.22.0.1/24 dev cni0 ip link set dev cni0 up ip link add dev veth_foo type veth peer name veth_foo_eth0 ip link set dev veth_foo master cni0 ip link set dev veth_foo up ip link set dev veth_foo_eth0 netns foo ip netns exec foo ip link set dev veth_foo_eth0 up ip netns exec foo ip addr add 172.22.0.2/24 dev veth_foo_eth0 

    为了测试, 我们在 foo 中启动一个 http 服务.

    ~ ip netns exec foo python3 -m http.server -d foo 8080 Serving HTTP on 0.0.0.0 port 8080 ( http://0.0.0.0:8080/) ... 

    这时候, 我们就可以直接访问命名空间 foo 中的 http 服务.

    ~ curl 172.22.0.2:8080 -s | grep im <li><a href="im-foo">im-foo</a></li> 

    创建另一个网络命名空间 bar, 并通过 veth 关联到 bridge

    ip netns add bar ip netns exec bar ip link set dev lo up ip link add dev veth_bar type veth peer name veth_bar_eth0 ip link set dev veth_bar master cni0 ip link set dev veth_bar up ip link set dev veth_bar_eth0 netns bar ip netns exec bar ip link set dev veth_bar_eth0 up ip netns exec bar ip addr add 172.22.0.3/24 dev veth_bar_eth0 

    在测试 foo 和 bar 的互通之间, 我们需要先允许通过 cni0 来转发流量.

    iptables -t filter -A FORWARD --in-interface cni0 -j ACCEPT iptables -t filter -A FORWARD --out-interface cni0 -j ACCEPT ip netns exec bar curl 172.22.0.2:8080 -s | grep im <li><a href="im-foo">im-foo</a></li> 

    使用 ipvs 代理 foo 中的 http 服务

    我们可以简单将 ipvs 理解为 L4 的负载均衡, 通过 ipvsadm 可以创建一个虚拟的 IP 地址, 并将相关流量转发给 foo.

    ipvsadm --add-service --tcp-service 172.23.0.1:8080 --scheduler rr ipvsadm --add-server --tcp-service 172.23.0.1:8080 --real-server 172.22.0.2:8080 --masquerading 

    在访问 172.23.0.1:8080 之前, 我们需要将 cni0 指定为 foo 的默认网关.

    ip netns exec foo ip route add default via 172.22.0.1 ~ curl 172.23.0.1:8080 -s | grep im <li><a href="im-foo">im-foo</a></li> 

    ipvs 的负载均衡功能

    如果将 bar 也增加到 172.23.0.1:8080 的后端负载, 则可以免费体验 ipvs 的负载均衡功能.

    ipvsadm --add-server --tcp-service 172.23.0.1:8080 --real-server 172.22.0.3:8080 --masquerading ip netns exec bar ip route ad default via 172.22.0.1 curl 172.23.0.1:8080 -s | grep im <li><a href="im-foo">im-foo</a></li> curl 172.23.0.1:8080 -s | grep im <li><a href="im-bar">im-bar</a></li> curl 172.23.0.1:8080 -s | grep im <li><a href="im-foo">im-foo</a></li> curl 172.23.0.1:8080 -s | grep im <li><a href="im-bar">im-bar</a></li> 

    在 Pod 中通过 Service 访问当前 Pod

    k8s 中一个很经典的场景. 为了便于模拟, 我们先将 bar 中 172.23.0.1 的后端服务中踢出, 仅保留 foo.

    ipvsadm --delete-server --tcp-service 172.23.0.1:8080 --real-server 172.22.0.3:8080 

    为了在 bar 中访问 172.23.0.1, 我们需要虚构对应的设备.

    ip link add dev ipvs0 type dummy ip addr add 172.23.0.1/32 dev ipvs0 ip netns exec bar curl 172.23.0.1:8080 -s | grep im <li><a href="im-foo">im-foo</a></li> 

    但是你会发现, 我们无法直接在 foo 通过 ipvs 来访问 foo.

    ip netns exec foo curl 172.23.0.1:8080 --connect-timeout 1 curl: (28) Connection timeout after 1001 ms 

    我们需要做三件事来解决这个问题:

    • cni0 开启 promisc 来支持 hairpin
    • 对来自 foo 的流量做一次 SNAT
    • 激活 conntrack
    ip link set cni0 promisc on iptables -t nat -A POSTROUTING -s 172.22.0.0/24 -j MASQUERADE sysctl net.ipv4.vs.cOnntrack=1 --write ~ ip netns exec foo curl 172.23.0.1:8080 -s | grep im <li><a href="im-foo">im-foo</a></li> 

    MadHatter 在 severfault 上的这个回答非常好的解释了 hairpin 和这次 SNAT 的原因.

    TODO

    有时间的话, 我们后续可以找个实际的集群, 来验证下上述的理解.

    5 条回复    2023-04-13 12:01:01 +08:00
    GopherDaily
        1
    GopherDaily  
    OP
       2023-04-13 01:01:07 +08:00   5
    冲浪冲多了,币入不敷出,多的借点给我
    artnowben
        2
    artnowben  
       2023-04-13 11:15:20 +08:00
    dperf 可以测试 ipvs 的性能,DPVS 发布版本也是用 dperf 去做性能报告的
    https://github.com/baidu/dperf
    GopherDaily
        3
    GopherDaily  
    OP
       2023-04-13 11:33:03 +08:00
    @artnowben 昨天正好看到了你这个,ipvs 在大集群的情况下是显然优于 iptables ,又没其他可以选,测试意义不大。我倒是很期待,你们准备不准备自己维护一个对主流 gateway 的测试结果集。
    artnowben
        4
    artnowben  
       2023-04-13 11:37:29 +08:00
    @GopherDaily 不维护,吃力不讨好的事。测试过 AWS 、GCP ;测试国内某大型云厂商的网卡性能,文章在国内就被屏蔽了
    GopherDaily
        5
    GopherDaily  
    OP
       2023-04-13 12:01:01 +08:00
    @artnowben 我猜也是
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     5090 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 25ms UTC 09:28 PVG 17:28 LAX 01:28 JFK 04:28
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86