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

阅读数:256 2019 年 9 月 25 日 08:00

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 tryme
11
12# 可以观察到“ping”的网络请求在一分钟内,每个的延迟都增加了 3000ms
13# 当然,也可以通过`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 分钟
9
10$ 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:^hp
17
18
19# 随机选择列表中的容器,向其“eth0”网卡发送的网络包添加在 3000ms ± 40ms 范围内,符合“normal”分布的网络延迟,并持续 5 分钟
20
21$ 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 tryme
12
13# 在终端(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:^hp
12
13# 在 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 c3
18
19# 在“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

评论

发布