30

Kubernetes网络的IPVlan方案

 3 years ago
source link: https://kernel.taobao.org/2019/11/ipvlan-for-kubernete-net/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

Nov 25, 2019 • 侯志远

Kubernetes网络的IPVlan方案

背景及问题

云上构建容器网络一般有overlay bypass VPC和基于VPC两种方式。overlay方案的优点是不受vpc网络配额、创建响应速度的影响(例如路由表、路有条目数的限制,弹性网卡数量及创建速度限制等),缺点是因为多了一次的网络加解封装的开销,会使得网络复杂性的提升和性能的下降,也无法直接利用VPC提供的网络能力(如负载均衡、安全组等)。

基于VPC构建可以利用VPC原生的网络功能,性能较高、功能丰富,但同时需要处理VPC自身带来的一些限制。目前主要有VPC路由、弹性网卡、ENI多IP三种方案。VPC路由的方案受限于路由表创建数量支持的容器数量有限;弹性网卡方案性能可以接近vpc原生的网络性能但单台node上pod的数量存在限制;平衡性能和容器数量,ENI多IP应该是三个方案中最好的一种。基于ENI多IP构建容器网络一般有bridge, 策略路由, macvlan, ipvlan等多种方案,如下图。

vpc-eni-ip

而因VPC往往会检测进入报文的源mac,使得bridge, macvlan无法很好的适配ENI多IP。策略路由通过了三层网络联调,不存在mac的问题,但性能下降较多。ipvlan可以较好的解决mac的问题,性能也不错,但在适配k8s的service网络却在不少问题。kube-proxy依赖host namespace的3层处理(iptables或ipvs),而ipvlan本身无法和host namespace交互而导致:

  • L2模式下入出流量不会经过host namespace网络,无法支持kube-proxy
  • L3模式但入方向不经过host namespace网络,无法支持kube-proxy
  • L3S模式下入、出均经过host namespace的三层网络,但又会带来以下新的问题:
    • 当service的client和server POD在一个master时,server的response报文会走ipvlan datapath, service访问失败
    • L3S模式下流量从4层进入interface,无法支持kata等安全容器
    • 当client和server在同一node时,导致同一方向流量多次进出host conntrack,datapath复杂,和iptables/ipvs也存在兼容性问题

考虑以上问题,设计了新的ipvlan方案,保证性能和高密度的优点同时使其可以兼容k8s的service网络。

考虑Datapath的简洁性,方案采用ipvlan l2模式。通过linux route和tc识别service流量并导流到新的兼容kube-proxy的路径。方案设计如下图:

structure

为每个ENI额外创建一个ipvlan子接口,置于host的namespace,例如图中的ipvl_a0, ipvl_b0。IP地址配置主网卡IP+32位掩码地址并设置scope为host。

MASTERIP=1.1.1.1/32  #主网卡IP地址
ip link add link a0 name ipvl_a0 type ipvlan mode l2
ip link add link b0 name ipvl_b0 type ipvlan mode l2
ip link set ipvl_a0 up
ip link set ipvl_b0 up
ip addr add $MASTERIP  scope local dev ipvl_a0
ip addr add $MASTERIP  scope local dev ipvl_b0

host namespace中配置host到Pod的路由,下一跳设置为host namespace中的slave接口

IP_A1= # ipvl_a1地址
IP_A2= # ipvl_a2地址
IP_B1= # ipvl_b1地址
ip route add $IP_A1/32 dev ipvl_a0
ip route add $IP_A2/32 dev ipvl_a0
ip route add $IP_B1/32 dev ipvl_a0

每张eni网卡设置tc egress规则,将目的ip为service段的流量重定向到init namespace的slave网卡的ingress方向。考虑性能,使用无锁的clsact qdisc。

tc qdisc add dev $ENIA clsact
tc filter add dev $ENIA egress proto ip u32 \
    match ip dst $SERVICE_CIDR \
	action tunnel_key unset pipe \
	action tc_mirred ingress redirect dev ipvl_a0

最后,需要开启kube-proxy的源地址伪装。

Datapath分析

Pod流量分析

跨Node的Pod间互访和普通的ipvlan l2路径相同,不做讨论。

同Node内Pod间互访,属于同一ENI则走ipvlan快速路径,属于不同ENI则通过vpc在eni间转发流量访问。

pod-to-pod

同Node内Node访问Pod, 通过查找路由表进入ipvlan的转发逻辑实现访问,Pod访问Node借助VPC在ENI网卡和主网卡间转发实现。

node-to-pod

Service流量分析

跨Node的Pod间互访,Request方向的流量处理可分三个阶段:

  1. 流量从Pod到ENI网卡的tc egress filter时,依据目的ip被识别为service流量,重定向到host namespace,从而进入kube-proxy的处理流程.
  2. kube-proxy(iptables或ipvs)依据负载均衡策略查找backend pod,修改目的ip为backend pod ip, 修改源地址为主网卡地址,经vpc转发至目的端ENI网卡。
  3. 经目的端ENI网卡的ipvlan处理进入backen pod。
    pod-to-service

response方向与request方向相反:

  1. 流量从Backend Pod经ENI进入VPC,并转发至源Node的主网卡,进入kube-proxy
  2. 经kube-proxy处理,转换源ip为service ip, 目的ip为源pod ip,发送至host namespace的ipvlan slave网卡
  3. 经ipvlan处理进入源pod
    service-to-pod

跨Node的Node与Pod互访类似,不做进一步讨论。

同Node的Pod间互访分为两种情况,属于同一ENI和属于不同ENI。对于不同ENI的流量和跨Node Pod互访类似,不做进步一步讨论。

同一ENI下service流量处理Request方向分两个阶段:

  1. 流量从Pod到ENI网卡,被tc egress filter识别为service流量,重定向至host namespace。
  2. kube-proxy(iptables或ipvs)修改目的ip为backend pod ip,修改源地址为主网卡ip地址,经host namespace的slave网卡转发到backend pod
    pod-to-service-same-node
    ](pod-to-service-same-node.png)

同一ENI下service流量的response方向相反:

  1. 流量从Backend Pod经ipvlan处理进入host namespace。
  2. kube-proxy修改源地址为service ip, 目的地址为源pod ip,经host namespace slave网卡进入源Pod.
service-to-pod-same-node

我们申请阿里云的神龙裸金属机型,对IPVlan、策略路由、ENI等三种容器网络方案做了性能对比,结果如下。

时延采用ping,netperf做了测试。ping测试了普通模式和洪泛模式,netperf测试了tcp_rr, udp_rr两种模式。结果如下:

delay
其中IPVlan, ENI模式较为接近。策略路由普通ping模式下约有20ns增加,洪泛ping模式7ns增加;udp_rr下降约8%、tcp_rr下降约10%。

带宽测试采用netperf测试了tcp_stream和不同包长下的udp_stream, 结果如下:

bandwidth

其中udp stream模式下ENI,IPVlan较为接近约0.02%以下,策略路由约7%左右。吞吐IPVlan比ENI约有25%下降,策略路由相比ENI约有50%下降。 tcp stream模式下由于gso, gro的加速,吞吐较为接近。

在VPC ENI多IP基础上,我们通过IPVlan实现了一种既提高了单台ecs容器创建密度,又兼具性能和兼容K8S Service网络的方案。目前该方案已经在阿里巴巴容器服务团队开源的CNI插件Terway中实现。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK