在腾讯云基于VPC(虚拟私有网络)的CVM上使用k8s集群,有两种方式:
使用腾讯云官方容器服务CCS时, 会使用专有的VPC容器网络, 节点上会给容器分配一个跟VPC CIDR不重叠的容器网段(用户可配置),由CCS负责向VPC网络注册容器网段的路由,容器之间,容器跟节点之间,在用户看来都是直接路由的。
自己搭建k8s集群的话, 常用的容器网络方案是vxlan。
为了弄清楚这两种网络方案下, 容器网络的性能情况,笔者设计并执行了一个简单的对比测试, 对比了吞吐量和时延。
本文不介绍vxlan和vpc网络原理,只呈现一个可复现的详细测试流程,并附上典型测试结果。 只关心测试结果的话,直接看最后一节。
通过腾讯云容器服务(CCS)创建一个两节点的集群。
通过CCS(或kubectl)创建两个POD, 分布在两个节点上。这两个POD使用的是VPC容器网络。后面简称这两个POD为VPC POD。
通过flannel给两个节点分配另一个虚拟网段,并创建vxlan设备。通过本地docker run命令在两个节点个运行一个docker container, 这两个docker container使用的是flannel管理的vxlan虚拟网络,后面简称这两个容器为vxlan容器。
在两个VPC POD间运行qperf测试(走的是VPC容器网络), 在两个vxlan 容器之间运行qperf测试(走的是vxlan网络), 然后进行对比。
从节点二的VPC POD和vxlan容器分别访问节点一, 通过qperf测试性能对比。
测试使用的节点是CVM, 不可避免收到母机上其他CVM的影响。 为了尽量排除这一影响, 让两个网络下的qperf测试,在同样两台CVM节点上,先后进行(间隔在一分钟之内)。
为了排除两次测试收到母机网络负载的波动影响,每间隔半小时,重复执行一遍对比测试,测试多次。最后取平均值来对比。
参考上一问题的答案。
https://console.cloud.tencent.com/vpc
CIDR选择 172.31.0.0/16
https://console.cloud.tencent.com/ccs/cluster
容器网络CIDR选择 10.0.0.0/14
节点配置选择1核CPU, 1G内存
操作系统选择Ubuntu 16.04 64位
等几分钟,两个节点的状态为“健康”以后,说明节点和集群都已经初始化完成了。
两个节点分配到的IP分别为(后面分别记为节点一和节点二):
查看节点的内网IP和状态
root@VM-0-5-ubuntu:~# kubectl get nodes
NAME STATUS AGE VERSION
172.31.0.16 Ready 14d v1.7.8-qcloud
172.31.0.5 Ready 12d v1.7.8-qcloud
查看CCS(腾讯云容器服务)给每个节点分配的容器网段
# kubectl get node/172.31.0.5 -o jsonpath={.spec.podCIDR}
10.0.1.0/24
kubectl get node/172.31.0.16 -o jsonpath={.spec.podCIDR}
10.0.0.0/24
wget https://github.com/coreos/flannel/releases/download/v0.9.1/flannel-v0.9.1-linux-amd64.tar.gz
tar -xzf flannel-v0.9.1-linux-amd64.tar.gz
为了简单,只在节点172.31.0.5上安装和运行etcd:
apt install etcd
systemctl start etcd
这样两个节点上都可以通过 http://172.31.0.5:4001 来访问这个只有一个实例的etcd集群
etcdctl --endpoint http://172.31.0.5:4001 set /flannel/net/config '{"NetWork":"192.168.0.0/16","SubnetLen": 24, "Backend": {"Type": "vxlan"}}'
./flanneld -etcd-endpoints=http://172.31.0.5:4001 -etcd-prefix=/flannel/net -iface=eth0 &
查看etcd数据可以看到两个节点上的flanneld各自分配到的网段:
# etcdctl --endpoint http://172.31.0.5:4001 ls /flannel/net/subnets
/flannel/net/subnets/192.168.24.0-24
/flannel/net/subnets/192.168.81.0-24
# etcdctl --endpoint http://172.31.0.5:4001 get /flannel/net/subnets/192.168.24.0-24
{"PublicIP":"172.31.0.5","BackendType":"vxlan","BackendData":{"VtepMAC":"6a:7d:68:63:b4:d1"}}
# etcdctl --endpoint http://172.31.0.5:4001 get /flannel/net/subnets/192.168.81.0-24
{"PublicIP":"172.31.0.16","BackendType":"vxlan","BackendData":{"VtepMAC":"7e:f8:6a:92:eb:a8"}}
flanneld还会在本地生成一个文件/run/flannel/subnet.env。例如在节点172.31.0.5上:
# cat /run/flannel/subnet.env
FLANNEL_NETWORK=192.168.0.0/16
FLANNEL_SUBNET=192.168.24.1/24
FLANNEL_MTU=1450
FLANNEL_IPMASQ=false
停止dockerd
systemctl stop dockerd
修改/usr/lib/systemd/system/dockerd.service, 如下所示,增加"EnvironmentFile=-/run/flannel/subnet.env", 并修改ExecStart定义
EnvironmentFile=-/run/flannel/subnet.env
ExecStart=/usr/bin/dockerd ${LOG_LEVEL} --bip=${FLANNEL_SUBNET} --mtu=${FLANNEL_MTU} ${STORAGE_DRIVER} ${REGISTRY_MIRROR}
重新启动dockerd
systemctl start dockerd
通过kubectl create -f命令创建一个deployment。 所用yaml文件内容如下:
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
labels:
qcloud-app: nginx
name: nginx
namespace: default
spec:
replicas: 2
selector:
matchLabels:
qcloud-app: nginx
template:
metadata:
labels:
qcloud-app: nginx
spec:
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: "qcloud-app"
operator: In
values:
- nginx
topologyKey: "kubernetes.io/hostname"
containers:
- image: nginx:alpine
imagePullPolicy: Always
name: nginx
imagePullSecrets:
- name: qcloudregistrykey
restartPolicy: Always
这个yaml文件中通过podAntiAffinity来确保两个POD被调度到两个不同的节点。
(这一步也可以通过控制台来完成: https://console.cloud.tencent.com/ccs/service)
然后检查pod状态
# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE
nginx-2438677318-d9jv7 1/1 Running 0 3m 10.0.1.10 172.31.0.5
nginx-2438677318-jc4b1 1/1 Running 0 3m 10.0.0.26 172.31.0.16
可以看到,两个POD分布在两个节点, IP分别为10.0.1.10 和 10.0.1.26, 属于之前配置的VPC容器网络10.0.0.0/14。
docker run -d nginx:alpine
获取POD和vxlan容器的IP。 以节点一上的VPC POD为例:
# kubectl get pod/nginx-2438677318-d9jv7 -o jsonpath={.status.containerStatuses[0].containerID}
docker://a1173da42e8b395a1b72e9ffe9dad43a135826e32dedc9202acc717d63b21967
# docker inspect --format '{{.State.Pid}}' a1173da42e8b395a1
17694
最终两个VPC POD和vxlan容器的IP, pid如下表所示:
节点 | POD | 容器 | 容器IP | pid |
---|---|---|---|---|
172.31.0.5 | nginx-2438677318-d9jv7 | a1173da42e8b | 10.0.1.11 | 17694 |
172.31.0.5 | --- | 8b610711dc45 | 192.168.24.2 | 28611 |
172.31.0.16 | nginx-2438677318-jc4b1 | 461b98c72697 | 10.0.1.30 | 6512 |
172.31.0.16 | --- | 5a56b09429b | 192.168.81.2 | 18172 |
ubuntu下安装qperf:
wget https://www.openfabrics.org/downloads/qperf/qperf-0.4.9.tar.gz
tar -xzvf qperf-0.4.9.tar.gz
cd qperf-0.4.9
/config
make
centos下直接yum install qperf
即可
在host, VPC POD, vxlan容器三个不同的网络namespace中启动qperf server。
1) host网络
qperf &
2) VPC POD
# 其中17694是节点一上VPC POD的pid
nsenter -t 17694 -n qperf &
3) vxlan容器
# 其中28611是节点一上vxlan容器的pid
nsenter -t 28611 -n qperf &
在172.31.0.16上,运行
# 其中10.0.1.11是远端POD的IP
nsenter -t 6512 -n qperf 10.0.1.11 -oo msg_size:64:64K:*2 -vu -vvc tcp_bw tcp_lat > vpc-c2c.raw
在172.31.0.16上,运行
# 其中192.168.24.2是远端vxlan容器的IP
nsenter -t 18172 -n qperf 192.168.24.2 -oo msg_size:64:64K:*2 -vu -vvc tcp_bw tcp_lat > vxlan-c2c.raw
在172.31.0.16上,运行
nsenter -t 6512 -n qperf 172.31.0.5 -oo msg_size:64:64K:*2 -vu -vvc tcp_bw tcp_lat > vpc-c2n.raw
在172.31.0.16上,运行
nsenter -t 18172 -n qperf 172.31.0.5 -oo msg_size:64:64K:*2 -vu -vvc tcp_bw tcp_lat > vxlan-c2n.raw
qperf 172.31.0.5 -oo msg_size:64:64K:*2 -vu -vvc tcp_bw tcp_lat > n2n.raw
下载qperf-plot工具: https://github.com/honkiko/qperf-plot
把原始qperf报告转换为plot数据文件
cat vxlan-c2c.raw | ./qperf-parse.py > vxlan-c2c
cat vpc-c2c.raw | ./qperf-parse.py > vpc-c2c
cat vxlan-c2n.raw | ./qperf-parse.py > vxlan-c2n
cat vpc-c2n.raw | ./qperf-parse.py > vpc-c2n
cat n2n.raw | ./qperf-parse.py > n2n
生成对比图表
gnuplot -c qperf-plot.plt vpc-c2c vxlan-c2c
会在当前目录生成bw-[vpc-c2c]-vs-[vxlan-c2c].png和lat-[vpc-c2c]-vs-[vxlan-c2c].png
gnuplot -c qperf-plot.plt vpc-c2n vxlan-c2n
会在当前目录生成bw-[vpc-c2n]-vs-[vxlan-c2n].png和lat-[vpc-c2n]-vs-[vxlan-c2n].png
节点配置: 腾讯云北京一区 标准型S1 1核1G
节点操作系统: Ubuntu 16.04.1 LTS
节点内核版本: 4.10.0-32-generic
qperf版本: qperf 0.4.9
flannel版本: v0.9.1
容器到容器(c2c)
以上5个qperf测试(vpc-c2c, vxlan-c2c, vpc-c2n, vxlan-c2n, n2n),重复5轮, 每轮之间间隔两分钟。5轮测试结果取平均值。结果如下。
加入节点到节点(n2n)的曲线(图中紫色曲线)作为参照
加入节点到节点(n2n)的曲线(图中紫色曲线)作为参照
吞吐率方面,VPC容器网络要比vxlan高40%, 是不是消耗了特别多的CPU资源换来的呢。为此笔者专门做了一个对比测试。
两种网络模式下,使用固定msg_size=1440, 执行qperf tcp_bw测试, 时长60秒, 同时通过mpstat每秒采集一次CPU利用率指标。 重复执行10轮测试,取平均值。结果如下:
同样的msg_size, 吞吐率大40%, 也意味着同样时间的发包数量多40%, 从而send系统调用次数也多40%。 因此mpstat统计出来的VPC容器网络下sys要高。 vxlan的封包解包是在软中断中执行的,所以即使多发送了40%的报文, VPC容器网络模式下, mpstat统计出来的softirq CPU占用反而还比vxlan要低。
进行吞吐率测试时, usr和sys这两个CPU消耗,肯定是随着每秒发包数量(pps, PacketPerSecond)增加而增加的。但是softirq的消耗对比, 则体现出了vxlan模式下额外的封包解包带来的额外CPU开销。
容器到容器,VPC容器网络是直接路由,无论是吞吐率还是时延,都很接近节点到节点通信的性能;
而vxlan需要多一层隧道封装,因此带来了很大的开销。
吞吐率方面,VPC容器网络要比vxlan高40%,时延要小5%~10%。
容器到其他节点, VPC容器网络仍然是直接路由,而vxlan容器则是通过iptables规则实现的NAT来完成通信,因此性能损耗不算大。但是不得不面对NAT带来的各种复杂性。
因此,想要在腾讯云上使用k8s, 建议还是选择官方CCS。官方CCS由专业团队来提供保障和服务,在网络性能上也有巨大的优势。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。