专栏首页深入理解k8s网络原理深入理解kubernetes(k8s)网络原理之四-pod流量控制
原创

深入理解kubernetes(k8s)网络原理之四-pod流量控制

深入理解kubernetes(k8s)网络原理之四-pod流量控制

在前面的几篇文章中,我们解决了pod连接主机、pod连接外网、pod与相同节点或不同节点的pod连接、用clusterIP和nodeport的方式访问pod等几个问题,可以说,对于组织pod的网络的每一环都已经完成了。

和CPU、内存这类资源一样,我们肯定希望网络资源对于每个pod来说也是平均分配的,起码能做到每个pod的数据包发送与接收的速度都能控制在一定的范围内,节点的带宽不能被某个pod耗光而影响其它的pod,所以这一章我们来讨论如何控制pod的进出流量速率。

首先我们来看看这回linux给我们准备了哪些工具;

TC(traffic control)

linux自带流量控制框架,这个框架允许用户在数据发送前配置数据包排队规则qdisc(queueing discipline),对流量进行限制或整形,linux的tc只控制发送速率不控制接收速率,当然要控制接收速率也是有办法实现的。

对于限制网卡的发送速率,一般有两种方式:

  1. 第一种是对整个网卡的发送速率进行简单粗暴的限制,例如eth0网卡的发送速率限制100mbit;
  2. 第二种是对网卡发出的流量先进行分类,再分别对每一分类的的速率单独限制,例如访问mysql的流量限制80mbit,访问http服务的流量限制20mbit;

对于第一种方式,我们选择无类别队列,对于第二种方式,我们选择可分类队列。

无类别队列

主要有:

  • pfifo/bfifo(First In First Out):先进先出队列,只需设置队列的长度,pfifo是以数据包的个数为单位,bfifo是以字节数为单位;
  • pfifo_fast:数据包是按照TOS被分配多三个波段里,band0优先级最高,band1次之,band2最低,按优先级从高到低发送,在每个波段里面,使用先进先出规则;
  • tbf(Token Bucket Filter):针对数据字节数进行限制,适合于把流速降低到某个值,但允许短暂突发流量超过设定值,我们限制pod的发送速率主要就用这个队列;
  • red(Random Early Detection):当带宽的占用接近于规定的带宽时,系统会随机地丢弃一些数据包
  • sfq(Stochastic Fairness Queueing):它按照会话为流量进行排序,然后循环发送每个会话的数据包。
  • FQ (Fair Queue):公平队列

在这里我们只介绍下如何创建tbf队列,因为后面主要是使用这个队列来限制pod的发送速率,下面的命令可以控制eth0的发送速率为100mbit:

tc qdisc add dev eth0 root tbf rate 100mbit burst 100mbit limit 100mbit

## rate:传输速率
## burst:桶的大小
## limit:确定最多有多少数据(byte)在队列中等待令牌

流量控制单位kbps:千字节/秒 mbps:兆字节/秒 kbit:KBits/秒 mbit:MBits/秒 bps:字节数/秒(如果不带单位,则默认单位是这个)

可分类队列

不同于无分类队列,可分类队列使用时步骤稍微复杂些,产要分三步:

  1. 给网卡创建一个队列
  2. 创建队列的分类,在各个分类里可以设置不同的流量策略
  3. 创建分类规则,把流量导到第二步创建的分类

可分类队列主要有:

  • cbq(class based queueing:基于类别排队):没用过,自行google
  • htb(hierarchy token bucket:层级令牌桶):看下面的示例

示例配置:访问mysql的速率限制80mbit,访问http服务的速率限制20mbit

  • 创建htb队列:
tc qdisc add dev eth0 root handle 1: htb default 11 ##使用htb队列,默认流量去分类11
  • 创建队列分类:
tc class add dev eth0 parent 1: classid 1:11 htb rate 80mbit ceil 80mbit  ## 创建分类11,速率限制80mbit
tc class add dev eth0 parent 1: classid 1:12 htb rate 20mbit ceil 20mbit  ## 创建分类12,速率限制20mbit
  • 引导流量到分类:
tc filter add dev eth0 protocol ip parent 1:0 prio 1 u32 match ip dport 3306 0xffff flowid 1:11  ## 所有访问3306端口的流量导到分类11中
tc filter add dev eth0 protocol ip parent 1:0 prio 1 u32 match ip dport 80 0xffff flowid 1:12  ## 所有访问80端口的流量导到分类12中

也可以通过来源IP+目标端口来引导流量

tc filter add dev eth0 protocol ip parent 1:0 prio 1 u32 match ip src 192.168.6.160 match ip dport 23 oxffff flowid 1:11

也可以通过数据标记来引导流量:

iptables -t mangle -A POSTROUTING -d 10.244.1.10 -j MARK –set-mark 100 ## 用iptables给数据打标记
tc filter add dev eth0 protocol ip parent 1:0 prio 2 handle 100 fw flowid 1:11  ## 标记了100的数据包引导到分类11中

pod的流量限制

首先还是在测试的主机上创建一个pod:(笔者的测试主机IP为192.168.6.160)

ip netns add pod-a
ip link add eth0 type veth peer name veth-pod-a
ip link set eth0 netns pod-a
ip netns exec pod-a ip addr add 192.168.10.10/24 dev eth0
ip netns exec pod-a ip link set eth0 up
ip netns exec pod-a ip route add default via 169.254.10.24 dev eth0 onlink
ip link set veth-pod-a up
echo 1 > /proc/sys/net/ipv4/conf/veth-pod-a/proxy_arp
echo 1 > /proc/sys/net/ipv4/ip_forward
iptables -I FORWARD -s 192.168.0.0/16 -d 192.168.0.0/16 -j ACCEPT
ip route add 192.168.10.10 dev veth-pod-a scope link

然后在主机上安装iperf3:

yum install iperf3

在pod-a中启动服务端:

ip netns exec pod-a iperf3 -s

再开一个终端,测试一下限速前的速度:

iperf3 -c 192.168.10.10 -i 1 -t 10

Connecting to host 192.168.10.10, port 5201
[  5] local 192.168.6.160 port 50768 connected to 192.168.10.10 port 5201
[ ID] Interval           Transfer     Bitrate         Retr  Cwnd
[  5]   0.00-1.00   sec  8.19 GBytes  70.3 Gbits/sec    0   1.35 MBytes
[  5]   1.00-2.00   sec  8.27 GBytes  71.0 Gbits/sec    0   1.35 MBytes
[  5]   2.00-3.00   sec  8.18 GBytes  70.3 Gbits/sec    0   1.35 MBytes
[  5]   3.00-4.00   sec  8.36 GBytes  71.8 Gbits/sec    0   1.35 MBytes
[  5]   4.00-5.00   sec  8.46 GBytes  72.7 Gbits/sec    0   1.35 MBytes
[  5]   5.00-6.00   sec  8.40 GBytes  72.2 Gbits/sec    0   1.35 MBytes
[  5]   6.00-7.00   sec  8.50 GBytes  73.1 Gbits/sec    0   1.42 MBytes
[  5]   7.00-8.00   sec  8.25 GBytes  70.8 Gbits/sec    0   1.57 MBytes
[  5]   8.00-9.00   sec  8.53 GBytes  73.2 Gbits/sec    0   1.57 MBytes
[  5]   9.00-10.00  sec  8.45 GBytes  72.6 Gbits/sec    0   1.57 MBytes
- - - - - - - - - - - - - - - - - - - - - - - - -
[ ID] Interval           Transfer     Bitrate         Retr
[  5]   0.00-10.00  sec  83.6 GBytes  71.8 Gbits/sec    0             sender
[  5]   0.00-10.04  sec  83.6 GBytes  71.5 Gbits/sec                  receiver
iperf Done.

可以看到,限制前的速度为71G/秒;

因为pod使用的是veth网卡对,所以我们可以通过主机端的网卡,达到控制pod流量的目的;

控制pod的接收速率

我们控制主机网卡veth-pod-a的发送速率,就相当于是控制pod的接收速率,我们限制pod的接收速率为100mbit:

tc qdisc add dev veth-pod-a root tbf rate 100mbit burst 100mbit limit 100mbit

此时再测:

iperf3 -c 192.168.10.10 -i 1 -t 10
 
Connecting to host 192.168.10.10, port 5201
[  5] local 192.168.6.160 port 50626 connected to 192.168.10.10 port 5201
[ ID] Interval           Transfer     Bitrate         Retr  Cwnd
[  5]   0.00-1.00   sec  24.9 MBytes   209 Mbits/sec    0    389 KBytes
[  5]   1.00-2.00   sec  11.6 MBytes  97.5 Mbits/sec    0    389 KBytes
[  5]   2.00-3.00   sec  11.6 MBytes  97.5 Mbits/sec    0    389 KBytes
[  5]   3.00-4.00   sec  11.7 MBytes  98.0 Mbits/sec    0    389 KBytes
[  5]   4.00-5.00   sec  10.8 MBytes  90.2 Mbits/sec    0    389 KBytes
[  5]   5.00-6.00   sec  11.7 MBytes  98.0 Mbits/sec    0    389 KBytes
[  5]   6.00-7.00   sec  11.6 MBytes  97.5 Mbits/sec    0    389 KBytes
[  5]   7.00-8.00   sec  11.0 MBytes  92.3 Mbits/sec    0    389 KBytes
[  5]   8.00-9.00   sec  11.6 MBytes  97.5 Mbits/sec    0    389 KBytes
[  5]   9.00-10.00  sec  11.6 MBytes  97.5 Mbits/sec    0    389 KBytes
- - - - - - - - - - - - - - - - - - - - - - - - -
[ ID] Interval           Transfer     Bitrate         Retr
[  5]   0.00-10.00  sec   128 MBytes   107 Mbits/sec    0             sender
[  5]   0.00-10.05  sec   126 MBytes   105 Mbits/sec                  receiver
iperf Done.

看到限速后的结果为105mbit/秒左右,符合预期

删除接收限速:

tc qdisc del dev veth-pod-a root tbf rate 100mbit burst 100mbit limit 100mbit

控制pod的发包速率

因为linux的tc框架控发不控收,所以我们不能像上面一样,通过控制主机端veth-pod-a网卡的接收速率来控制pod发送速率的目的,但也不是完全没有办法:

在pod内直接限制发送速率

虽然不能在主机端控制pod的发送,但是可以直接在容器里控制,命令和上面的一样,只不过是在pod-a的ns中执行:

ip netns exec pod-a tc qdisc add dev eth0 root tbf rate 100mbit burst 100mbit limit 100mbit

因为是测试从容器发送的速率,所以我们要把iperf3的服务端调整一下,服务端跑在主机上,然后再在容器中进行发送测试:

ip netns exec pod-a iperf3 -c 192.168.6.160 -i 1 -t 10

Connecting to host 192.168.6.160, port 5201
[  5] local 192.168.10.10 port 49224 connected to 192.168.6.160 port 5201
[ ID] Interval           Transfer     Bitrate         Retr  Cwnd
[  5]   0.00-1.00   sec  26.6 MBytes   223 Mbits/sec    0    641 KBytes
[  5]   1.00-2.00   sec  11.2 MBytes  94.4 Mbits/sec    0    641 KBytes
[  5]   2.00-3.00   sec  11.2 MBytes  94.4 Mbits/sec    0    641 KBytes
[  5]   3.00-4.00   sec  11.2 MBytes  94.4 Mbits/sec    0    641 KBytes
[  5]   4.00-5.00   sec  11.2 MBytes  94.4 Mbits/sec    0    641 KBytes
[  5]   5.00-6.00   sec  12.5 MBytes   105 Mbits/sec    0    641 KBytes
[  5]   6.00-7.00   sec  11.2 MBytes  94.4 Mbits/sec    0    641 KBytes
[  5]   7.00-8.00   sec  11.2 MBytes  94.4 Mbits/sec    0    641 KBytes
[  5]   8.00-9.00   sec  11.2 MBytes  94.4 Mbits/sec    0    641 KBytes
[  5]   9.00-10.00  sec  11.2 MBytes  94.4 Mbits/sec    0    641 KBytes
- - - - - - - - - - - - - - - - - - - - - - - - -
[ ID] Interval           Transfer     Bitrate         Retr
[  5]   0.00-10.00  sec   129 MBytes   108 Mbits/sec    0             sender
[  5]   0.00-10.04  sec   126 MBytes   105 Mbits/sec                  receiver
iperf Done.

结果是105mbit/秒,也是符合预期

删除限制:

ip netns exec pod-a tc qdisc del dev eth0 root tbf rate 100mbit burst 100mbit limit 100mbit

通常我们会把容器的命令执行权限开给业务方,这样他们就有可能在容器里把这个速率限制取消,有没有一种办法是在主机端限制pod的发送速率呢?有。

在主机端用ifb网卡的方式限制收包速率

ifb网卡也是linux虚拟网络设备,类似于tun/tap/veth,只不过ifb的原理要简单得多,可以看作是一张只有tc过滤功能的虚拟网卡,而且它不会改变数据包的流向,比如把某张网卡接收流量导给ifb网卡,经过ifb的流量控制过滤后,继续走原网卡的接收流程,发送也是如此;这样我们就可以把pod在主机一端的网卡的接收重定向到ifb网卡,然后通过控制ifb网卡的发送速率,来间接控制pod的发送速率。

首先要确认内核有加载ifb模块,如果没有则加载

modprobe ifb    //需要加载ifb模块

然后创建ifb网卡,并设置发送队列长度为1000:

ip link add ifb0 type ifb
ip link set dev ifb0 up txqueuelen 1000

veth-pod-a的接收重定向到ifb网卡上:

tc qdisc add dev veth-pod-a ingress handle ffff: 
tc filter add dev veth-pod-a parent ffff: protocol ip u32 match u32 0 0 flowid 1:1 action mirred egress redirect dev ifb0   //重定向流量到ifb

设置ifb0的发送速率:

tc qdisc add dev ifb0 root tbf rate 100mbit burst 100mbit limit 100mbit

此时再测:

ip netns exec pod-a  iperf3 -c 192.168.6.160 -i 1 -t 10

Connecting to host 192.168.6.160, port 5201
[  5] local 192.168.10.10 port 54762 connected to 192.168.6.160 port 5201
[ ID] Interval           Transfer     Bitrate         Retr  Cwnd
[  5]   0.00-1.00   sec  26.5 MBytes   223 Mbits/sec    0    700 KBytes
[  5]   1.00-2.00   sec  11.2 MBytes  94.4 Mbits/sec    0    700 KBytes
[  5]   2.00-3.00   sec  11.2 MBytes  94.4 Mbits/sec    0    700 KBytes
[  5]   3.00-4.00   sec  11.2 MBytes  94.4 Mbits/sec    0    700 KBytes
[  5]   4.00-5.00   sec  12.5 MBytes   105 Mbits/sec    0    700 KBytes
[  5]   5.00-6.00   sec  11.2 MBytes  94.4 Mbits/sec    0    700 KBytes
[  5]   6.00-7.00   sec  11.2 MBytes  94.4 Mbits/sec    0    700 KBytes
[  5]   7.00-8.00   sec  11.2 MBytes  94.4 Mbits/sec    0    700 KBytes
[  5]   8.00-9.00   sec  11.2 MBytes  94.4 Mbits/sec    0    700 KBytes
[  5]   9.00-10.00  sec  11.2 MBytes  94.4 Mbits/sec    0    700 KBytes
- - - - - - - - - - - - - - - - - - - - - - - - -
[ ID] Interval           Transfer     Bitrate         Retr
[  5]   0.00-10.00  sec   129 MBytes   108 Mbits/sec    0             sender
[  5]   0.00-10.05  sec   126 MBytes   105 Mbits/sec                  receiver
iperf Done.

105mbit/秒,符合预期,改一下速率限制,从100mbit改为200mbit:

tc qdisc replace dev ifb0 root tbf rate 200mbit burst 200mbit limit 200mbit

然后再测:

ip netns exec pod-a  iperf3 -c 192.168.6.160 -i 1 -t 10

Connecting to host 192.168.6.160, port 5201
[  5] local 192.168.10.10 port 56044 connected to 192.168.6.160 port 5201
[ ID] Interval           Transfer     Bitrate         Retr  Cwnd
[  5]   0.00-1.00   sec  48.0 MBytes   403 Mbits/sec    0    354 KBytes
[  5]   1.00-2.00   sec  23.1 MBytes   194 Mbits/sec    0    354 KBytes
[  5]   2.00-3.00   sec  23.1 MBytes   194 Mbits/sec    0    354 KBytes
[  5]   3.00-4.00   sec  22.4 MBytes   188 Mbits/sec    0    354 KBytes
[  5]   4.00-5.00   sec  23.1 MBytes   194 Mbits/sec    0    354 KBytes
[  5]   5.00-6.00   sec  22.4 MBytes   188 Mbits/sec    0    354 KBytes
[  5]   6.00-7.00   sec  23.1 MBytes   194 Mbits/sec    0    354 KBytes
[  5]   7.00-8.00   sec  23.1 MBytes   194 Mbits/sec    0    354 KBytes
[  5]   8.00-9.00   sec  22.4 MBytes   188 Mbits/sec    0    354 KBytes
[  5]   9.00-10.00  sec  23.1 MBytes   194 Mbits/sec    0    354 KBytes
- - - - - - - - - - - - - - - - - - - - - - - - -
[ ID] Interval           Transfer     Bitrate         Retr
[  5]   0.00-10.00  sec   254 MBytes   213 Mbits/sec    0             sender
[  5]   0.00-10.04  sec   252 MBytes   210 Mbits/sec                  receiver
iperf Done.

210mbit/秒,都符合预期。

删除pod-a的发送限速:

tc qdisc del dev veth-pod-a ingress
tc qdisc del dev ifb0 root tbf rate 200mbit burst 200mbit limit 200mbit
ip link del ifb0

OK,pod的流量控制也就说完了。

到目前为止,我们已经解决了一个常规则的k8s的cni需要解决的一切问题,但直到现在,也没见过go语言的影子,所以说k8s都是负责粘合功能的胶水代码,真正工作的是linux系统,与其说学习k8s的网络,不如说在学习linux提供的各种虚拟网络设备及内核协议栈的工作机制。

下一章我们来详细介绍下flannel,然后再动手用go语言撸个cni出来。

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • ASP.NET Core on K8S深入学习(11)K8S网络知多少

    本篇已加入《.NET Core on K8S学习实践系列文章索引》,可以点击查看更多容器化技术相关系列文章。

    Edison Zhou
  • 深入理解kubernetes(k8s)网络原理之一-pod连接主机

    对于刚接触k8s的人来说,最令人懵逼的应该就是k8s的网络了,如何访问部署在k8s的应用,service的几种类型有什么区别,各有什么使用场景,服务的负载均衡是...

    一生无聊
  • 开工必备!50+篇超实用云原生技术干货合集

    kai 开 gong 工 da 大 ji 吉 新年新气象,更要1G棒 2020年没写完的代码,现在还有思路吗? 2021年开始使用云原生技术了吗? 一开工就遇...

    腾讯云原生
  • K8s 系列(一) - 知识图谱

    Kubernetes(K8s) 作为当前最知名的容器编排工具,称得上是云原生(Cloud Native)时代的“操作系统”,熟悉和使用它是研发、运维、产品等的必...

    astraw99
  • 了解 Kubernetes

    Docker 虽好用,但面对强大的集群,成千上万的容器,突然感觉不香了。这时候就需要我们的主角 Kubernetes 上场了,先来了解一下 Kubernetes...

    耕耘实录
  • 深入理解kubernetes(k8s)网络原理之三-跨主机pod连接

    在之前的两篇文章中分别介绍了pod与主机连接并且上外网的原理及service的clusterIP和nodeport的实现原理,对于组织pod的网络这件事来说,还...

    一生无聊
  • 转发有礼 | 50篇+云原生系列干货文章汇总,请查收!

    云原生技术干货文章合集,来咯~ ? 2020 年,要说咱们技术圈子里什么最火? 云原生肯定是那 NO.1 ? 截止目前,我们不难看出,K8s 容器、服务...

    腾讯云原生
  • 中秋福利 | 15个系列100+篇超实用云原生原创干货合集(内含腾讯彩蛋)

    还有2天,就要迎来中秋小长假啦 这个中秋节你打算怎么过? ? 小云选择把这篇干货全部拿下! 云原生技术干货文章合集,来咯~ ? 2021 年,要说咱们技术圈...

    腾讯云原生
  • 「走进k8s」Kubernetes基本概念和组件(13)

    k8s为每个pod分配了唯一的IP地址,一个pod里的多个容器共享pod IP。 pod其实有两种类型:普通的pod和静态pod,后者比较特殊,它并不存放在et...

    IT架构圈
  • Kubernetes设计的4个原则

    今天我要带给大家的是2018年底,在西雅图举办的Kubecon的一场分享,来自谷歌K8s团队的工程师Saad Ali分享的《Kubernetes设计原则》。这场...

    yuanyi928
  • Tungsten Fabric与K8s集成指南丨创建隔离命名空间

    K8s与Tungsten Fabric集成后有四种配置模式,分别为:默认模式、自定义隔离模式、命名空间隔离模式、嵌套模式。

    Tungsten Fabric
  • 最详细的 K8S 学习笔记总结(2021最新版)!建议收藏

    虽然 Docker 已经很强大了,但是在实际使用上还是有诸多不便,比如集群管理、资源调度、文件管理等等。那么在这样一个百花齐放的容器时代涌现出了很多解决方案,比...

    民工哥
  • 艾编程arry老师课堂笔记:kubernetes K8S基于Docker安装部署

    在Docker容器技术被炒得热火朝天之时,大家发现,如果想要将Docker应用于具体的业务实现,是存在困难的——编排、管理和调度等各个方面,都不容易。于是,人们...

    艾编程
  • 简单5步,轻松debug K8s服务!

    在Kubernetes中,服务是一个核心概念。在本文中,将介绍如何调试K8S服务,这些服务是由多个Pod组成的工作负载的抽象接口(主机+端口)。

    CNCF
  • k8s基本原理

    前面hello world程序中,对于如何访问到服务,有必要了解一下k8s的网络模型,在这之前先介绍docker的网络模型

    kinnylee
  • 深入理解kubernetes(k8s)网络原理之五-flannel原理

    flannel有udp、vxlan和host-gw三种模式,udp模式因为性能较低现在已经比较少用到,host-gw我们在前面简单介绍过,因为使用场景比较受限,...

    一生无聊
  • 深入理解kubernetes(k8s)网络原理之二-service原理

    上一篇文章中我们介绍了pod与主机互通及pod访问外网的原理,在这一章我们将介绍pod与pod的相互访问以及外部服务访问pod的方式,由此引出k8s的servi...

    一生无聊
  • 硬核技能k8s初体验

    Kubernetes 是一个软件系统,使你在数以万计的电脑节点上运行软件时就像 所有节点是以单个大节点一样, 它将底层基础设施抽象,这样做同时简化了应用开发、部...

    有态度的马甲
  • 一文搞懂Kubernetes网络策略(下)

    今天zouyee为大家带来《一文搞懂Kubernetes网络策略(下)》,其中《kuberneter调度由浅入深:框架》预期周五出,敬请期待,当前涉及版本均为1...

    zouyee

扫码关注云+社区

领取腾讯云代金券