AWS EC2 + Docker + JMeter load testing infrastructure for building distributed

Description link

@

Overview and Scope

This article describes how to create a distributed load testing infrastructure using AWS EC2 + Docker + JMeter.
After completion of all steps, the infrastructure are as follows:
AWS EC2 + Docker + JMeter infrastructure

In Part 1 , we will follow the necessary steps to create a custom fit your image and JMeter Dockerfiles demand.
Then, in Part 2 , we will use these elements in AWS EC2 settings.
Then begin the first step:

Prerequisites

In order to be able to smoothly step by step to configure and operate, you need some basic knowledge of each of these systems (EC2, Docker and JMeter) of.
In addition, we also need an active AWS account to perform all the steps.

Part 1: Local setup- local configuration

Step 1: Create an image from Dockerfile

dockerfile is to start using the basic elements needed docker or "cookbook", so we'll begin.
We need to build layer 2:
1, one base layer, which create a running instance of the required basic settings JMeter;
2, the second is the logical layer, which is a JMeter example, may be a master node or a slave node;

JMeter base image and entrypoint.sh Dockerfile script is as follows:
Dockerfile:

# Use Java 11 JDK Oracle Linux
FROM openjdk:11-jdk-oracle
MAINTAINER Dragos
# Set the JMeter version you want to use
ARG JMETER_VERSION="5.1.1"
# Set JMeter related environment variables
ENV JMETER_HOME /opt/apache-jmeter-${JMETER_VERSION}
ENV JMETER_BIN ${JMETER_HOME}/bin
ENV JMETER_DOWNLOAD_URL https://archive.apache.org/dist/jmeter/binaries/apache-jmeter-${JMETER_VERSION}.tgz
# Set default values for allocation of system resources (memory) which will be used by JMeter
ENV Xms 256m
ENV Xmx 512m
ENV MaxMetaspaceSize 1024m
# Change timezone to local time
ENV TZ="Europe/Bucharest"
RUN export TZ=$TZ
# Install jmeter
RUN yum -y install curl \
&& mkdir -p /tmp/dependencies \
&& curl -L --silent ${JMETER_DOWNLOAD_URL} >  /tmp/dependencies/apache-jmeter-${JMETER_VERSION}.tgz \
&& mkdir -p /opt \
&& tar -xzf /tmp/dependencies/apache-jmeter-${JMETER_VERSION}.tgz -C /opt \
&& rm -rf /tmp/dependencies
# Set JMeter home
ENV PATH $PATH:$JMETER_BIN
# copy our entrypoint
COPY entrypoint.sh /
RUN chmod +x ./entrypoint.sh
# Run command to allocate the default system resources to JMeter at 'docker run'
ENTRYPOINT ["/entrypoint.sh"

Entrypoint.sh:

#!/bin/bash
# Run command to allocate the default or custom system resources (memory) to JMeter at 'docker run'
sed -i 's/\("${HEAP:="\)\(.*\)\("}"\)/\1-Xms'${Xms}' -Xmx'${Xmx}' -XX:MaxMetaspaceSize='${MaxMetaspaceSize}'\3/' ${JMETER_BIN}/jmeter
exec "$@"

在基础层之上,可以创建一个Master层和一个Slave层。这些Dockerfile可以根据你的特定要求进行自定义。
现在让我们看一下我们的逻辑层:
Master层的Dockerfile:

# Use my custom base image defined above
FROM dragoscampean/testrepo:jmetrubase
MAINTAINER Dragos
# Expose port for JMeter Master
EXPOSE 60000

Slave层的Dockerfile:


# Use my custom base image defined above
FROM dragoscampean/testrepo:jmetrubase
MAINTAINER Dragos
# Expose ports for JMeter Slave
EXPOSE 1099 50000
COPY entrypoint.sh /
RUN chmod +x ./entrypoint.sh
# Run command to allocate the default system resources to JMeter at 'docker run' and start jmeter-server with all required parameters
ENTRYPOINT ["/entrypoint.sh"]

Slave层的Entrypoint.sh:

#!/bin/bash
# Run command to allocate the default system resources to JMeter at 'docker run'
sed -i 's/\("${HEAP:="\)\(.*\)\("}"\)/\1-Xms'${Xms}' -Xmx'${Xmx}' -XX:MaxMetaspaceSize='${MaxMetaspaceSize}'\3/' ${JMETER_BIN}/jmeter &&
$JMETER_HOME/bin/jmeter-server \
-Dserver.rmi.localport=50000 \
-Dserver_port=1099 \
-Dserver.rmi.ssl.disable=true \
-Djava.rmi.server.hostname=$HostIP
exec "$@"

我们不会详细讨论dockerfiles中的所有内容的含义,在网上有很多这样的文档。不过值得一提的是与Dockerfiles绑定在一起的entrypoint shell脚本。

docker entrypoints的作用是在运行时将数据初始化或者配置到容器中。在我们的例子中,我们需要它们来指定JMeter允许使用多少内存,并使用一些自定义配置来启动JMeter服务器,这些配置是基础设施工作所必需的。这将在“Step 2”部分中举例说明。

现在,让我们看一下创建Docker映像所需的命令。顺便说一下,Docker图像表示一组很好地集成在一起的层,是我们需要的环境的稳定快照。
从这样一个映像开始,我们可以生成N个容器,这正是我们在这个特定场景中所需要的,这取决于我们想要模拟的负载。

创建一个简单的docker映像的命令:
docker build /path/to/dockerfile

为docker映像创建一个标签:
docker tag imageId username/reponame:imageTag

同时创建docker映像和标签:
docker build -t username/reponame:imageTag /path/to/dockerfile

Step 2: 从一个映像创建一个容器

现在我们已经准备好映像,可以开始从中创建容器,在其中可以实际运行性能测试脚本。
创建一个新的容器:
sudo docker run -dit --name containername repository:tag or imageId /bin/bash

启动/停止容器:
docker start containerId
docker stop containerId

访问正在运行的容器:
docker exec -it containerId or containerName /bin/bash

到目前为止,如果你一直使用类似于Step 1中提供的Dockerfile,那么您应该拥有一个完全可用的Java + JMeter容器。 你可以通过检查工具版本来测试它,看看是否有任何错误,甚至可以尝试运行你计划在AWS中扩展的脚本(所有这些都应该在运行的容器中完成):
Jmeter -v
Java -version
Jmeter -n -t -J numberOfThreads=1 /path/to/script.jmx -l /path/to/logfile.jtl

Step 3: 将映像Push/Pull到Dockerhub或任何私有的Docker仓库(docker登录CLI后)

测试创建的图像是否符合要求的标准(容器内的所有内容),通常,最好将此图像保存到存储库中。然后,你可以在后续随时从那里提取它,而不必每次都从Dockerfile构建它。

Push映像到dockerhub:
docker push username/reponame:imageTag

从dockerhub中Pull已存在的映像(例如jdk映像):
docker pull openjdk:version

到此为止,这意味着您已经为cloud setup准备好了一组功能强大的JMeter从属映像和主映像。

Part 2: Cloud端基础架构——Infrastructure

可以使用EC2免费层实例,最多750小时/月,持续1年,因此有很多时间进行试验。
注意:对于下面提供的示例,我使用了Ubuntu Server 18.04 LTS实例,因此提供的命令可能无法在其他Linux发行版上使用。

Step 4: 创建安全组——Security Group

使容器内的JMeter实例(master实例或slave实例)能够通信,自定义安全组已定义并将其附加到每个主机:

入站规则(Inbound rules):
Security group inbound rules
出站规则(Outbound rules):
Security group outbound rules
注意:确保将要成为负载测试基础结构部分的所有实例分配给此安全组,否则它们可能无法相互通信。

Step 5: 创建一个IAM策略(可选)

假设您只需要一个由1个JMeter主节点和2个从节点组成的基础架构。在这种情况下,访问每个实例并对其进行配置(安装docker +启动容器)相对容易。

但是,如果需要处理的实例超过3个,会发生什么情况呢?

手动逐个配置变得极其乏味,手动并不是一个好主意。
这时,你将需要一个系统,能够管理你正在使用的大量容器。一些著名的工具,如谷歌的Kubernetes,或者Rancher等工具。

由于当前使用的是AWS,因此这两种解决方案似乎过于庞大了,因为亚马逊针对这一点提供了一个开箱即用的解决方案:
Run Command”功能使我们可以同时在多个EC2实例上执行Shell脚本。因此,我们不必访问每个实例,安装docker并一次一个实例地启动容器。

能够通过“Run Command”功能在EC2实例上执行命令的唯一要求是,适当的IAM角色已与该实例相关联。我将IAM策略命名为“ EC2Command”,并为每个新创建的实例选择了该策略(但是稍后可以通过“attach/replace role”功能将该角色分配给该实例):
IAM set policy for an existing instance
IAM related policies when instance is created
当您创建角色时,请确保将“AmazonEC2RoleforSSM”策略附加到您的角色上,这样就可以了。
Associate permissions to the IAM role
现在您可以使用“Run command”功能对多个实例批量执行脚本。
这将我们带入流程的下一步。

Step 6: 在测试机器上安装Docker

现在,你需要在EC2主机上安装docker,以便可以启动容器并将它们连接在一起以进行分布式负载测试。
直接使用命令(直接在Ubuntu上的实例终端中执行):

sudo apt-get install  curl  apt-transport-https ca-certificates software-properties-common \
&& curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add \
&& sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" \
&& sudo apt-get update \
&& sudo apt-get install -y docker-ce \
&& sudo usermod -aG docker $USER \
&& sudo curl -L "https://github.com/docker/compose/releases/download/1.23.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose \
&& sudo chmod +x /usr/local/bin/docker-compose \
&& sudo ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose

通过“Run command”执行的Shell脚本:

#!/bin/bash
sudo apt-get install  curl  apt-transport-https ca-certificates software-properties-common
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add
sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
sudo apt-get update
sudo apt-get install -y docker-ce
USER_DOCKER=$(getent passwd {1000..60000} | grep "/bin/bash" | awk -F: '{ print $1}')
sudo usermod -aG docker $USER_DOCKER

理想情况下,您将在多个EC2实例上运行第二个脚本,之后它们都将具有可用的Docker版本。
下一步是配置主节点和从属节点:

Step 7: 配置主节点——Master Node

在某些情况下,你甚至不需要多个从属节点来分布式运行测试,比如,当你有一台功能强大的主机并且该计算机能够生成目标的负载量时,对于这种特定情况,不需要Step 8和Step 9。对于这种情况,你甚至不想使用容器并直接在主机上安装JMeter。

但是,假设你确实需要一个Master + Slaves系统,然后继续启动Master容器:
直接使用命令(直接在Ubuntu上的实例终端中执行):

HostIP=$(ip route show | awk '/default/ {print $9}') \
&& docker pull dragoscampean/testrepo:jmetrumaster \
&& docker run -dit --name master --network host -e HostIP=$HostIP -e Xms=256m -e Xmx=512m -e MaxMetaspaceSize=512m -v /opt/Sharedvolume:/opt/Sharedvolume dragoscampean/testrepo:jmetrumaster /bin/bash

通过“Run command”执行的Shell脚本:

#!/bin/bash
HostIP=$(ip route show | awk '/default/ {print $9}')
docker pull dragoscampean/testrepo:jmetrumaster
docker run -dit --name master --network host -e HostIP=$HostIP -e Xms=256m -e Xmx=512m -e MaxMetaspaceSize=512m -v /opt/Sharedvolume:/opt/Sharedvolume dragoscampean/testrepo:jmetrumaster /bin/bash

脚本的第一行将机器的私有IP存储在变量“HostIP”中。主的HostIP不用于任何目的,仅使用从属节点的HostIP。我们将在Step 9看到具体要做什么。现在,请记住,你可以快速访问每个容器中主机的专用IP地址。

第二行很简单,只是从适当的仓库中获取图像。

最后一行创建我们将要使用的容器。此命令中有一些要点:
1、'--network host '命令启用主机连网,这意味着容器内的应用程序(JMeter),将在‘entrypoint.sh’脚本公开的端口上可用。如果没有它,我就无法进行设置。问题是,即使脚本是在从节点上执行的,由于错误(java.rmi.ConnectException: Connection refused to host:masterPrivateIP),主节点上也没有聚集任何结果。注意,我在较老版本的JMeter(如3.x.x)中没有遇到这个问题

2、‘- e Xms=256m -e Xmx=512m -e MaxMetaspaceSize=512m’ 是Xms和Xmx的参数化,MaxMetaspaceSize决定了允许使用JMeter的内存量。这是通过首先在容器内设置一些环境变量来完成的。然后,在“ entrypoint.sh”脚本中运行命令,将更改JMeter的“ / bin”文件夹中的“JMeter”文件。如果未指定这些值,则使用默认值。

要进一步了解这些变量代表什么以及如何设置它们,请阅读以下内容:
Xmx计算如下:系统总内存-(OS使用的内存+ JVM使用的内存+在计算机上运行所需的任何其他脚本)
如果您有一台专用的测试机器,为避免在测试运行时重新分配Xms,请从一开始就设置Xms = Xmx

MaxMetaspaceSize跟踪所有加载的类元数据和静态内容(静态方法,原始变量和对象引用)

例如:
一台专用机器上64 GB RAM
Xmx = 56G
Xms = 56G
MaxMetaspaceSize = 4096 MB
这为操作系统和其他进程留下了将近4GB的空间,这绰绰有余。

3、-v /opt/Sharedvolume:/opt/Sharedvolume userName/repoName:imageTag 该命令只是将主机上的文件夹映射到容器内的文件夹,你将在其中保存脚本文件和生成的日志。我们将不做进一步详细介绍,但是如果您想了解有关卷映射的更多信息,请参阅本文和迷你教程

Step 8: 配置从节点——Slave Nodes

HostIP”变量仅在“entrypoint.sh”脚本中用于此处,以启用从master服务器到slave服务器的远程访问(“-Djava.rmi。server.hostname = $ HostIP”)。
直接使用命令(直接在Ubuntu上的实例终端中执行):

HostIP=$(ip route show | awk '/default/ {print $9}') \
&& docker pull dragoscampean/testrepo:jmetruslave \
&& docker run -dit --name slave --network host -e HostIP=$HostIP -e HostIP=$HostIP -e Xms=256m -e Xmx=512m -e MaxMetaspaceSize=512m dragoscampean/testrepo:jmetruslave /bin/bash

通过“Run command”执行的Shell脚本:

#!/bin/bash
HostIP=$(ip route show | awk '/default/ {print $9}')
docker pull dragoscampean/testrepo:jmetruslave
docker run -dit --name slave --network host -e HostIP=$HostIP -e Xms=256m -e Xmx=512m -e MaxMetaspaceSize=512m dragoscampean/testrepo:jmetruslave /bin/bash

Step 9: 分布式模式下运行脚本

到此,准备就绪,可以开始运行测试了。这是我们需要在master主节点上运行以开始运行分布式测试的命令:

jmeter -n -t /path/to/scriptFile.jmx -Dserver.rmi.ssl.disable=true -R host1PrivateIP, host2PrivateIP,..., hostNPrivateIP -l /path/to/logfile.jtl

总结:

按照上面的操作步骤,可以实现AWS EC2+Jmeter+Docker的分布式性能测试,可能会遇到一些问题,完全没问题那是不可能的。
比如:
该文提到了一个EC2实例中有太多Websocket连接时可能遇到的问题。
另一个例子是我的一位同事在对Apa​​che服务器进行负载测试时遇到的情况,他会在JMeter中遇到各种连接错误,我们最初认为这是来自被测试的服务器。解决这个问题的方法来自这篇简短的文章。

I stumbled upon a problem in a project that, while attempting to perform approximately 20,000 threads from one computer, carried out some data-driven testing. If you type "in Linux / MacOS terminal ulimit -a ", you'll see a line called "open files" of. The problem is that the property is set to 1024 on the test computer. When using JMeter to run data-driven testing, this tool will open each thread starts or .csv file descriptors, once the number of parallel threads over 1024, I will receive an error message.
Solution: from ' / etc / Security / Limits edit' 'file open files maximum' and set to ' Unlimited '.

Guess you like

Origin www.cnblogs.com/PeterZhang1520389703/p/12423950.html