Docker容器的网络仿真解决方案

2019 年 9 月 25 日

Docker容器的网络仿真解决方案

在微服务架构的实践中,Docker作为重要的发布和运行方式而被我们青睐。但由此带来的问题也十分明显,在测试阶段,我们无法准确地控制网络,来了解Docker内的程序在网络异常时服务的反应。直到遇到了Pumba这个网络工具,问题才得以解决。在使用过程中发现Network emulation for Docker containers这篇文章对此工具介绍的比较易懂,遂翻译。


摘要


在微服务测试环节中,Pumba 作为网络工具,可以通过 netem delay 和 netem loss 命令模拟 Docker 容器之间的网络延迟和数据包丢失,从而实现所需要的网络环境。


简介


微服务架构作为一种更快地交付业务的方式,已被众多开发团队采用。容器技术的存在以及 Docker 为开发团队提供的一整套构建,发布和运行分布式应用程序的工具降低了服务交付的难度,加速了服务交付的进程。而当下的应用程序可以由数百个运行在 Docker 容器的微服务组成。


在最近的 NGINX 调查中发现 , “阻碍开发人员的最大挑战”是服务质量和交付速度之间的权衡取舍。就像 Martin Fowler 指出的那样, 微服务架构中的测试策略可能非常复杂,其中一个方面便是创建一个与真实环境相似的有效的测试环境。


在测试环境的创建中,一个无法避免的问题是如何模拟网络故障以确保应用程序和服务的稳定性。


网络是微服务架构中的动脉系统,用于确保任何分布式应用的可靠性。网络条件会因访问应用程序的接入时各种环境不同而产生不同效果,同时网络的表现会极大地影响整体应用程序可用性,稳定性,性能和用户体验。对开发人员来说,在用户遇到网络故障之前,对不同网络情况进行模拟和制定应对方法是至关重要的。因此,测试这些条件就需要十分贴近真实的网络环境。


在集群中部署 Docker 容器后,容器之间的所有通信都通过网络进行。这些容器在单个主机,不同主机,不同网络和不同数据中心上运行。


我们如何测试网络行为对应用程序的影响?我们可以做些什么来模拟单个主机上的容器之间或多个主机上的群集之间的不同网络属性?


Pumba 与网络仿真


Pumba 是一个受 Netflix Chaos Monkey 启发而产生的混乱测试工具。 主要的好处是它适用于容器而不是 VM。Pumba 可以杀死,停止,重新启动运行 Docker 容器或暂停指定容器内的进程。我们可以将其应用于分布式应用程序的稳定性测试。稳定性测试是开发团队验证其应用程序在遇到特别情况时,能正确恢复,而不会丢失任何数据或功能的关键。Pumba 为分布式和容器化应用程序模拟这些环境。


Pumba ‘netem’ 命令


我们通过从延迟和丢包来增强 Pumba 的能力。 使用 pumba netem 命令我们可以在任何 Docker 容器上实现延迟或丢包的状态。 本质上, Pumba 使用了 Linux 内核的 netem 排队规则来进行流量控制 (tc)。 作为依赖,我们需要将 iproute2 添加到我们想要测试的 Docker 镜像中。


Pumba 的 netem delay 和 netem loss 命令可以模拟 Docker 容器之间的网络延迟和数据包丢失,即使在单个主机上也是如此。


Linux 从内核 2.6.7(14 年前发布)开始,具有内置的网络仿真功能。这项功能允许我们使用 iproute2 中提供的 tc 工具来操纵流量控制设置,netem 是 tc 工具的扩展(排队规则)。通过它我们能够实现网络性能仿真场景下的各种属性和网络事件,包括延迟,丢包,打包机重新排序等事件,复制,腐败(数据在读写,持久化或其他情况下发生的意外事件)和带宽速率等。


Pumba netem 命令可以帮助开发团队在 Docker 容器中构建,发布和运行微服务时模拟真实的网络条件。通过简单的 netem 选项,极大地降低了其使用难度。


在当前版本中,Pumba 仅通过为指定容器添加延迟或数据包丢失来修改出口流量。目标容器可以通过名称(单个名称或空格分隔列表)或通过正则表达式(RE2)指定。Pumba 支持在指定的持续时间内修改容器网络条件,之后恢复正常的网络状况。Pumba 还可以通过 Ctrl-C 关闭 pumba 进程或使用 docker stop 命令关闭 Pumba 容器来重置链接。Pumba 可以通过修改配置选项,来指定网络仿真的 IP 范围,指定此范围内 IP 的传出流量,并保持其他传出流量不变。使用此选项,我们可以更改特定的容器间连接以及特定 Docker 网络的网络属性(每个容器有自己的 IP 范围)。


Pumba 延迟: netem delay


为了演示,我们将运行两个 Docker 容器:一个是运行 ping 命令,另一个是 Pumba Docker 容器,它为 ping 容器增加了将持续 1 分钟的 3 秒的网络延迟。1 分钟后,Pumba 容器在正常退出时恢复 ping 容器的网络连接属性。


 1# 打开两个终端窗口:(1)和 (2)  2 3# 终端 (1) 4# 创建一个以Alpine为基础镜像,可以使用iproute2的容器,起名“tryme”,之后执行ping “wwww.example.com” 的操作: 5$ docker run -it --rm --name tryme alpine sh -c "apk add --update iproute2 && ping www.example.com" 6 7# 终端(2) 8# 运行 pumba:向“tryme”的每个网络请求添加3s的网络延迟,并持续1分钟 9$ docker run -it --rm -v /var/run/docker.sock:/var/run/docker.sock gaiaadm/pumba \10         pumba netem --interface eth0 --duration 1m delay --time 3000 tryme1112# 可以观察到“ping”的网络请求在一分钟内,每个的延迟都增加了3000ms13# 当然,也可以通过`Ctrl-C`提前终止网络延迟14
复制代码


‘netem delay’ 使用示范


此部分展示进阶的 delay 命令使用。


 1# 向“mydb”容器通过“eth0”网卡发送的所有请求添加3s的网络延迟,并持续5分钟 2 3$ docker run -it --rm -v /var/run/docker.sock:/var/run/docker.sock gaiaadm/pumba \ 4    pumba netem --duration 5m \ 5      delay --time 3000 \ 6      mydb 7 8# 向所有名字以“hp”开头的容器的“eth1”网卡发送的请求,添加一个3000ms ± 30ms的延迟,并且延迟之后的一个随机请求有20%的可能丢失,并持续10分钟 910$ docker run -it --rm -v /var/run/docker.sock:/var/run/docker.sock gaiaadm/pumba \11    pumba netem --duration 5m --interface eth1 \12      delay \13        --time 3000 \14        --jitter 30 \15        --correlation 20 \16      re2:^hp171819# 随机选择列表中的容器,向其“eth0”网卡发送的网络包添加在3000ms ± 40ms范围内,符合“normal”分布的网络延迟,并持续5分钟2021$ docker run -it --rm -v /var/run/docker.sock:/var/run/docker.sock gaiaadm/pumba \22    pumba --random \23      netem --duration 5m \24        delay \25          --time 3000 \26          --jitter 40 \27          --distribution normal \28        container1 container2 container3
复制代码


Pumba 丢包命令: netem loss, netem loss-state, netem loss-gemodel


在这里,我们将模拟丢包场景。运行三个 Docker 容器,分别是用于发送数据的 iperf 服务器和客户端以及 Pumba Docker 容器,Pumba Docker 容器将在客户端容器上添加打包器丢失。我们使用执行网络吞吐量测试工具 iperf 来演示数据包丢失。


 1# 终端(1)iperf 服务器  2# ‘-s’ 命令运行服务器模式;‘-u’ 使用UDP;‘-i 1’ 每一秒报告一次 3$ docker run -it --rm --name tryme-srv alpine sh -c "apk add --update iperf && iperf -s -u -i 1" 4 5# 终端(2)iperf 客户端 6$ docker run -it --rm --name tryme alpine sh -c "apk add --update iproute2 iperf && iperf -c 172.17.0.3 -u" 7 8# 终端(3) 9# 运行 pumba:使“tryme”容器1分钟内20%的网络请求丢失10$ docker run -it --rm -v /var/run/docker.sock:/var/run/docker.sock gaiaadm/pumba \11         pumba netem --duration 1m loss --percent 20 tryme1213# 在终端(1)的服务器中将会在报告的‘Lost/Total Datagrams’中看到丢失的网络请求
复制代码


通常理解 IP 网络中的分组丢失分布是“突发的”。为了模拟更真实的分组丢失事件,使用不同的概率模型。Pumba 目前支持 3 种不同的丢包概率模型。Pumba 为每个概率模型定义了单独的损失命令。 loss- 独立概率损失模型(伯努利模型),它是最广泛使用的损耗模型,其中数据包丢失由伯努利轨迹组成的随机过程建模; loss-state-2 阶,-3 阶,-4 阶马尔可夫模型;loss-gemodelGilbert 模型和 Gilbert-Elliott 模型。


‘netem loss’ examples


 1# 将“mydb”容器的“eth0”网卡的丢包率控制在0.3%,并持续5分钟 2$ docker run -it --rm -v /var/run/docker.sock:/var/run/docker.sock gaiaadm/pumba \ 3    pumba netem --duration 5m \ 4      loss --percent 0.3 \ 5      mydb 6 7# 使名字以“hp”开头的容器的“eth1”网卡1.4%的丢包率,其中每个请求的成功率有1/4依赖于前一个请求的丢包率 Prob(n) = .25 * Prob(n-1) + .75 * Random 8$ docker run -it --rm -v /var/run/docker.sock:/var/run/docker.sock gaiaadm/pumba \ 9    pumba netem --interface eth1 --duration 15m \10      loss --percent 1.4 --correlation 25 \11      re2:^hp1213# 在c1,c2,c3三个容器上使用二阶马尔可夫模型模拟丢包概率: P13=15%, P31=85%(从c1到c3丢包率15%,从c3到c1丢包率85%,译者注),并持续12分钟14$ docker run -it --rm -v /var/run/docker.sock:/var/run/docker.sock gaiaadm/pumba \15    pumba netem --interface eth1 --duration 12m \16      loss-state -p13 15 -p31 85 \17      c1 c2 c31819# 在“mydb”容器的“eth2”网卡上使用Gilbert-Elliot模型模拟丢包概率: p=5%, r=90%, (1-h)=85%, (1-k)=7%,并持续9分30秒20$ docker run -it --rm -v /var/run/docker.sock:/var/run/docker.sock gaiaadm/pumba \21    pumba netem --interface eth2 --duration 9m30s \22      loss-gemodel --pg 5 --pb 90 --one-h 85 --one-k 7 \23      mydb
复制代码


投入使用


更多关于 Pumba 使用的例子,请移步[Pumba GitHub Repository]


(https://github.com/alexei-led/pumba).


二进制文件(Windows, Linux and MacOS)可在GitHub project release page获得。


Docker 镜像[Docker image]


(https://hub.docker.com/r/gaiaadm/pumba/)。


作者介绍:


V 笑(企业代号名),目前负责贝壳找房服务云平台开发工作。


本文转载自公众号贝壳产品技术(ID:gh_9afeb423f390)。


原文链接:


https://mp.weixin.qq.com/s/GcLuundZmzJV0qCm7ri8iA


2019 年 9 月 25 日 08:00834

评论

发布
暂无评论
发现更多内容

LeetCode题解:剑指 Offer 40. 最小的k个数,快速排序,JavaScript,详细注释

Lee Chen

算法 LeetCode 前端进阶训练营

重学JS | 找出数组中出现次数最多元素的4种算法

梁龙先森

前端 编程语言

工具词典:Inner Peace

lidaobing

28天写作营 随机漫步的傻瓜

架构师训练营 1 期第 8 周:性能优化(二)- 作业

灵霄

极客大学架构师训练营

7. JDK拍了拍你:字符串拼接一定记得用MessageFormat#format

YourBatman

Spring Framework 类型转换 MessageFormat DateFormat

架构大作业一

Geek_michael

极客大学架构师训练营

架构师训练营 - 大作业 2

阿甘

为移动应用产业开辟出海新航路,华为应用市场是如何“破冰”的?

脑极体

架构师训练营第五周”技术选型一“总结

随秋

极客大学架构师训练营

像用户一样测试:不妨犯傻

QualityFocus

软件测试 体验 可用性 用户体验

CAP 原理 <笔记>

raox

极客大学架构师训练营

扫地阿姨看完都学会了!万字长文总结Android多进程,满满干货指导

欢喜学安卓

android 程序员 面试 移动开发

架构大作业二

Geek_michael

极客大学架构师训练营

冰河又一MySQL力作出版(文末送书)!!

冰河

MySQL 高可用 高并发 高性能 MySQL架构

重学JS | 数组去重的7种算法

梁龙先森

前端 编程语言

如何给团队制定合理的季度绩效?

Alan

团队管理 绩效 28天写作营 七日更

在wildfly 21中搭建cluster集群

程序那些事

程序那些事 wildfly wildfly21 集群部署 集群架构

重磅盘点!2020年区块链行业十件大事

CECBC区块链专委会

区块链

面试官:我问的是Java内存模型,你回答堆栈方法区干嘛?

Java鱼仔

Java 程序员 JMM 多线程 并发

架构师训练营第五周”技术选型一“作业

随秋

极客大学架构师训练营

理论!三天两夜,万字长文,吃透TCP/IP

云流

Java 计算机网络 HTTP TCP/IP

手把手教你写!2021年Android工作或更难找,最全的BAT大厂面试题整理

欢喜学安卓

android 程序员 面试 移动开发

测开之函数进阶· 第4篇《匿名函数》

清菡

测试开发

自研ARM芯片,亲手拆掉Wintel联盟,微软这次是认真的吗?

脑极体

面试官:Android事件分发机制及设计思路,跳槽薪资翻倍

欢喜学安卓

android 程序员 面试 移动开发

架构师训练营 - 大作业1

阿甘

突破2.8万美元关口,比特币为何“疯涨”? ​

CECBC区块链专委会

比特币 比特币数字货币

专家:区块链底层技术创新是关键

CECBC区块链专委会

区块链

JAVA并发编程原理与实战

Geek_53983e

原理 java 并发 实战

甲方日常 76

句子

工作 随笔杂谈 日常

与前端训练营的日子 --Week09

SamGe

学习

Docker容器的网络仿真解决方案-InfoQ