基于 Containerd + Linux Bridge 实现跨节点容器网络性能损耗测试
containerd 是一个行业标准的容器运行时,强调简单性、健壮性、可移植性;继 Kubernetes、Prometheus、Envoy 和 CoreDNS 之后,于 2019 年 2 月 28 日,containerd 正式成为云原生计算基金会的毕业项目;从 k8s v1.20 开始废弃
containerd 是一个行业标准的容器运行时,强调简单性、健壮性、可移植性;继 Kubernetes、Prometheus、Envoy 和 CoreDNS 之后,于 2019 年 2 月 28 日,containerd 正式成为云原生计算基金会的毕业项目;从 k8s v1.20 开始废弃对 dockershim 的支持,改用 Containerd 作为默认的容器运行时,于 k8s v1.24 正式移除 dockershim 相关实现代码
Containerd 容器网络是通过 pause 容器(或 Infra 容器)实现,其容器镜像为gcr.io/google_containers/pause-amd64:3.6
,该容器是实现 Linux 命名空间共享的基础,
建议通过 PC 端访问本文章,以获取更好阅读体验,由于精力有限,该文章的后续更新、完善仅限于站点 运维技术帮 (https://ywjsbang.com) 望理解 !!
部署环境
1、部署环境说明
CentOS Linux release 7.9.2009 (Core)
Linux Kernel 5.4.186-1.el7.elrepo.x86_64
containerd v1.6.2
runc v1.1.1
crictl v1.20.0
2、节点 IP 地址及组件部署说明
节点 | IP 地址 | Pod IP 地址 | 部署信息 |
---|---|---|---|
a4 | 192.168.31.14 | 10.14.0.0/16 | containerd、crictl、runc |
a5 | 192.168.31.15 | 10.15.0.0/16 | containerd、crictl、runc |
Containerd 解压部署
1、下载解压部署
# 下载解压安装,该压缩文件除包含 containerd 外,还额外包含 cni 插件、runc
wget https://github.com/containerd/containerd/releases/download/v1.6.2/cri-containerd-cni-1.6.2-linux-amd64.tar.gz
tar xvf containerd-1.6.2-linux-amd64.tar.gz -C /
# 替换 containerd 中的 runc (可选)
wget https://github.com/opencontainers/runc/releases/download/v1.1.1/runc.amd64
mv runc.amd64 /usr/local/sbin/runc
# 生成 containerd 默认配置文件
mkdir -p /etc/containerd/ && containerd config default > /etc/containerd/config.toml
# 启动
systemctl daemon-reload && systemctl start containerd.service
2、cri-containerd-cni-1.6.2-linux-amd64.tar.gz 解压文件说明
# cni 网络插件
./opt/cni/bin/tuning、vrf、loopback、portmap、ptp、ipvlan、host-device、macvlan、host-local、firewall、bandwidth、sbr、vlan、static、bridge、dhcp
# cni 网络插件网络配置文件
./etc/cni/net.d/10-containerd-net.conflist
# containerd 启动脚本
./etc/systemd/system/containerd.service
./usr/local/bin/containerd-shim
./usr/local/bin/containerd-shim-runc-v1 # 使用了 v2 版本 shim API,该 shim 仍然只支持 cgroup v1
./usr/local/bin/containerd-shim-runc-v2 # 使用了 v2 版本 shim API,同时支持 cgroup v1 和 v2
./usr/local/bin/containerd # containerd
./usr/local/bin/containerd-stress # containerd 内置的压测工具
./usr/local/bin/ctr # containerd 自身内置的容器管理工具
./usr/local/bin/ctd-decoder
./usr/local/sbin/runc # 是一个 CLI 工具,用于根据 OCI 规范在 Linux 上生成和运行容器
# 命令行程序 crictl 程序配置
./etc/crictl.yaml
./usr/local/bin/crictl # 兼容 cri 规范的容器管理工具
./usr/local/bin/critest
各节点 cni 配置
1、使用 cni 插件 bridge, 将当前节点创建的容器桥接到主机网络
// 使用 bridge、portmap 插件提供内网地址、端口映射功能
cat > /etc/cni/net.d/10-containerd-net.conflist << EOF
{
"cniVersion": "1.0.0",
"name": "containerd-net",
"plugins": [
{
"type": "bridge",
"bridge": "cni0",
"isGateway": true,
"ipMasq": true,
"promiscMode": true,
"ipam": {
"type": "host-local",
"ranges": [
[{
"subnet": "10.14.0.0/16"
}]
],
"routes": [
{ "dst": "0.0.0.0/0" }
]
}
},
{
"type": "portmap",
"capabilities": {"portMappings": true}
}
]
}
EOF
// 容器环回口 lo 配置
cat > /etc/cni/net.d/99-loopback.conf << EOF
{
"cniVersion": "1.0.0",
"name": "lo",
"type": "loopback"
}
EOF
创建、运行测试容器
1、在一个 pod 沙箱中启动两个容器(nginx、debug)示例,pod 沙箱配置信息如下:
# 将镜像 k8s.gcr.io/pause:3.6 导入到指定命名空间 k8s.io 以便 crictl 工具使用
ctr -n k8s.io images import pause_v3.6.tar
# 启动运行一个 pod sandbox, 可在该 pod sandbox 运行一个或多个容器
cat > pod-sandbox.json << EOF
{
"metadata": {
"name": "pod-sandbox",
"uid": "hdishd83djaidwnduwk28bcsb",
"namespace": "k8s.io",
"attempt": 3
},
"log_directory": "/tmp",
"dns_config": {
"servers": ["8.8.8.8","8.8.4.4"]
},
"port_mappings":[
{
"protocol": 0,
"container_port": 80,
"host_port": 80,
"host_ip": "192.168.31.15"
}
]
}
EOF
2、a4、a5 节点执行如下操作创建测试容器 debug、nginx
# 删除转发默认动作
iptables -D FORWARD -j REJECT --reject-with icmp-host-prohibited
# 创建 pod 沙箱, 及查看 pod id
crictl runp pod-sandbox.json
crictl pods
# 通过 pod id 创建容器 debug
crictl create 6bc6f4352e3b3 debug.json pod-sandbox.json
crictl start 2369dff38e2db
# 通过 pod id 创建容器 nginx
crictl create 6bc6f4352e3b3 nginx.json pod-sandbox.json
crictl start a92939273b7de
# 手动添加不同节点内的 pod 网段路由
route add -net 10.15.0.0/16 gw 192.168.31.15
# 查看启动的容器
crictl ps
# > CONTAINER IMAGE CREATED STATE NAME ATTEMPT POD ID
# > a92939273b7de nginx:latest 18 seconds ago Running nginx 0 6bc6f4352e3b3
# > 2369dff38e2db harbor.it123.me/library/debug:v1.2 27 minutes ago Running debug 0 6bc6f4352e3b3
Containerd-stress
1、利用 Containerd 内置压测工具 containerd-stress 测试 containerd 守护进程每秒创建、启动、删除容器的性能
containerd-stress -c 10 -i docker.io/library/alpine:latest --runtime io.containerd.runc.v2
# > INFO[0000] pulling docker.io/library/alpine:latest
# > INFO[0002] starting stress test run...
# > INFO[0063] worker 0 finished
# > INFO[0063] worker 3 finished
# > INFO[0063] worker 1 finished
# > INFO[0063] worker 7 finished
# > INFO[0063] worker 8 finished
# > INFO[0063] worker 9 finished
# > INFO[0063] worker 6 finished
# > INFO[0063] worker 5 finished
# > INFO[0063] worker 4 finished
# > INFO[0063] worker 2 finished
# > INFO[0063] ending test run in 60.399 seconds
# > INFO[0063] create/start/delete 987 containers in 60.399 seconds (16.341 c/sec) or (0.061 sec/c) failures=0
压测结果说明: 60 秒内完成 987 个容器的创建、启动、删除等操作,平均每秒 16.34 个,经监测、系统磁盘写 io 操作数达到上限!!
iperf3 流量压测
1、节点间 iperf3 流量压测
# a5 节点执行
firewall-cmd --add-port=5201/tcp
iperf3 -s
# 从 a4 节点发起压测
iperf3 -c 192.168.31.15 -n 100G -b 30G
# > Connecting to host 192.168.31.15, port 5201
# > [ 4] local 10.14.0.4 port 39974 connected to 192.168.31.15 port 5201
# > [ ID] Interval Transfer Bandwidth Retr Cwnd
# > [ 4] 0.00-1.00 sec 1.69 GBytes 19.5 Gbits/sec 191 2.01 MBytes
# > [ 4] 1.00-2.00 sec 1.95 GBytes 19.7 Gbits/sec 0 2.01 MBytes
# > ...
# > ...
# > [ 4] 46.00-47.00 sec 2.27 GBytes 19.5 Gbits/sec 0 2.90 MBytes
# > [ 4] 47.00-48.00 sec 2.26 GBytes 19.4 Gbits/sec 0 2.90 MBytes
# > [ 4] 48.00-48.15 sec 344 MBytes 19.4 Gbits/sec 0 2.90 MBytes
# > - - - - - - - - - - - - - - - - - - - - - - - - -
# > [ ID] Interval Transfer Bandwidth Retr
# > [ 4] 0.00-48.15 sec 100 GBytes 19.5 Gbits/sec 451 sender
# > [ 4] 0.00-48.15 sec 100 GBytes 19.5 Gbits/sec receiver
# > iperf Done.
2、节点容器间 iperf3 流量压测
# 从 a4 节点容器发起压测
crictl exec -it 2369dff38e2db sh
iperf3 -c 10.15.0.3 -n 100G -b 30G
# > Connecting to host 10.15.0.3, port 5201
# > [ 4] local 10.14.0.4 port 52846 connected to 10.15.0.3 port 5201
# > [ ID] Interval Transfer Bandwidth Retr Cwnd
# > [ 4] 0.00-1.00 sec 1.60 GBytes 15.7 Gbits/sec 204 1.98 MBytes
# > [ 4] 1.00-2.00 sec 1.71 GBytes 16.7 Gbits/sec 0 2.00 MBytes
# > [ 4] 2.00-3.00 sec 1.97 GBytes 16.9 Gbits/sec 0 2.01 MBytes
# > [ 4] 3.00-4.00 sec 2.02 GBytes 17.3 Gbits/sec 34 2.01 MBytes
# > ...
# > ...
# > [ 4] 45.00-46.00 sec 2.29 GBytes 19.7 Gbits/sec 0 2.02 MBytes
# > [ 4] 46.00-47.00 sec 2.42 GBytes 18.8 Gbits/sec 0 2.02 MBytes
# > [ 4] 47.00-47.20 sec 492 MBytes 20.8 Gbits/sec 0 2.02 MBytes
# > - - - - - - - - - - - - - - - - - - - - - - - - -
# > [ ID] Interval Transfer Bandwidth Retr
# > [ 4] 0.00-47.20 sec 100 GBytes 18.2 Gbits/sec 298 sender
# > [ 4] 0.00-47.20 sec 100 GBytes 18.2 Gbits/sec receiver
# > iperf Done.
3、结论
节点间流量压测平均带宽 19.5 Gbits/sec,节点容器间压测平均带宽 18.2 Gbits/sec,容器化后其流量平均损耗为 (19.5 - 18.2)/19.5 = 6.7%
http 流量压测
1、节点间压测
autocannon http://192.168.31.15
# > Running 10s test @ http://192.168.31.15
# > 10 connections
# > ┌─────────┬──────┬──────┬───────┬───────┬─────────┬─────────┬───────┐
# > │ Stat │ 2.5% │ 50% │ 97.5% │ 99% │ Avg │ Stdev │ Max │
# > ├─────────┼──────┼──────┼───────┼───────┼─────────┼─────────┼───────┤
# > │ Latency │ 0 ms │ 4 ms │ 12 ms │ 13 ms │ 4.51 ms │ 3.29 ms │ 24 ms │
# > └─────────┴──────┴──────┴───────┴───────┴─────────┴─────────┴───────┘
# > ┌───────────┬─────────┬─────────┬─────────┬─────────┬─────────┬─────────┬─────────┐
# > │ Stat │ 1% │ 2.5% │ 50% │ 97.5% │ Avg │ Stdev │ Min │
# > ├───────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┤
# > │ Req/Sec │ 12967 │ 12967 │ 21535 │ 22575 │ 20583.6 │ 2720.26 │ 12967 │
# > ├───────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┤
# > │ Bytes/Sec │ 11.1 MB │ 11.1 MB │ 18.4 MB │ 19.3 MB │ 17.6 MB │ 2.32 MB │ 11.1 MB │
# > └───────────┴─────────┴─────────┴─────────┴─────────┴─────────┴─────────┴─────────┘
2、节点容器间压测
autocannon http://10.15.0.3
# > Running 10s test @ http://10.15.0.3
# > 10 connections
# > ┌─────────┬──────┬──────┬───────┬───────┬─────────┬─────────┬───────┐
# > │ Stat │ 2.5% │ 50% │ 97.5% │ 99% │ Avg │ Stdev │ Max │
# > ├─────────┼──────┼──────┼───────┼───────┼─────────┼─────────┼───────┤
# > │ Latency │ 0 ms │ 4 ms │ 13 ms │ 13 ms │ 4.77 ms │ 3.41 ms │ 20 ms │
# > └─────────┴──────┴──────┴───────┴───────┴─────────┴─────────┴───────┘
# > ┌───────────┬─────────┬─────────┬─────────┬─────────┬─────────┬─────────┬─────────┐
# > │ Stat │ 1% │ 2.5% │ 50% │ 97.5% │ Avg │ Stdev │ Min │
# > ├───────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┤
# > │ Req/Sec │ 8107 │ 8107 │ 19343 │ 22879 │ 18842 │ 3964.17 │ 8106 │
# > ├───────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┤
# > │ Bytes/Sec │ 6.92 MB │ 6.92 MB │ 16.5 MB │ 19.5 MB │ 16.1 MB │ 3.38 MB │ 6.91 MB │
# > └───────────┴─────────┴─────────┴─────────┴─────────┴─────────┴─────────┴─────────┘
3、结论
平均延迟
: 节点间 web 流量压测平均延迟 4.51ms,容器间平均压测 4.77ms, 容器化后平均损耗为 (4.77 - 4.51)/4.51 = 5.8%
平均每秒请求数
: 节点间每秒平均请求数 20583,节点容器间为 18842,其平均损耗为 (20583 - 18842)/20583 = 8.5%
重要提醒: 由于笔者时间、视野、认知有限,本文难免出现错误、疏漏等问题,期待各位读者朋友、业界大佬指正交流, 共同进步 !!
参考
https://github.com/opencontainers/runc/releases
https://github.com/containernetworking/plugins
https://github.com/containernetworking/cni
https://www.cni.dev/docs/
https://github.com/kubernetes-sigs/cri-tools
https://github.com/kubernetes-sigs/cri-tools/tree/master/docs/examples
更多推荐
所有评论(0)