Apache JMeter是一个纯Java开发的用于负载测试或者性能测试的开源软件。这篇文章介绍一下如何使用Alpine基础镜像将JMeter的压测能力进行容器化,并结合具体的示例来演示此镜像从构建到使用的整体过程。
以Alpine为基础构建JMeter镜像
Alpine镜像的特点就是小,在Alpine镜像之上安装jre,并下载JMeter并解压,设定环境变量就完成了JMeter的镜像。
Dockerfile
- 示例的Dockerfile如下所示
[root@liumiaocn jmeter]# ls
Dockerfile
[root@liumiaocn jmeter]# cat Dockerfile
FROM alpine:3.10.2
ARG VERSION_JMETER="5.1.1"
ENV FILENAME_JMETER apache-jmeter-${VERSION_JMETER}
ENV HOME_JMETER /usr/local/${FILENAME_JMETER}
ENV DOWNLOAD_URL_JMETER https://archive.apache.org/dist/jmeter/binaries/${FILENAME_JMETER}.tgz
ENV DOWNLOAD_DIR_LOCAL /tmp/download
RUN apk update \
&& apk upgrade \
&& apk add --update openjdk8-jre curl unzip bash \
&& mkdir -p /tmp/download \
&& curl -L --silent ${DOWNLOAD_URL_JMETER} > ${DOWNLOAD_DIR_LOCAL}/${FILENAME_JMETER}.tgz \
&& mkdir -p /opt ${DOWNLOAD_DIR_LOCAL} \
&& tar -xzf ${DOWNLOAD_DIR_LOCAL}/${FILENAME_JMETER}.tgz -C /usr/local \
&& rm -rf /var/cache/apk/* \
&& rm -rf ${DOWNLOAD_DIR_LOCAL}
ENV PATH $PATH:${HOME_JMETER}/bin
WORKDIR ${HOME_JMETER}/bin
[root@liumiaocn jmeter]#
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
注:此处为了减小size使用的JRE,但是由于JMeter一部分功能是在keytool基础上的,所以实际使用的时候还是根据情况换成jdk,或者选择相关的apk包进行安装达到要求。
构建JMeter镜像
- 使用docker build构建JMeter的镜像,输入日志如下所示
[root@liumiaocn jmeter]# docker build -t jmeter:5.1.1 .
Sending build context to Docker daemon 2.56 kB
Step 1/9 : FROM alpine:3.10.2
---> 961769676411
Step 2/9 : ARG VERSION_JMETER="5.1.1"
---> Using cache
---> f4f342eab6ba
Step 3/9 : ENV FILENAME_JMETER apache-jmeter-${VERSION_JMETER}
---> Using cache
---> f8ca701c741b
Step 4/9 : ENV HOME_JMETER /usr/local/${FILENAME_JMETER}
---> Using cache
---> 056cc7e91e6f
Step 5/9 : ENV DOWNLOAD_URL_JMETER https://archive.apache.org/dist/jmeter/binaries/${FILENAME_JMETER}.tgz
---> Using cache
---> 49e87f232d91
Step 6/9 : ENV DOWNLOAD_DIR_LOCAL /tmp/download
---> Using cache
---> 58cb1fc2f1f3
Step 7/9 : RUN apk update && apk upgrade && apk add --update openjdk8-jre curl unzip bash && mkdir -p /tmp/download && curl -L --silent ${DOWNLOAD_URL_JMETER} -o ${DOWNLOAD_DIR_LOCAL}/${FILENAME_JMETER}.tgz && mkdir -p /opt ${DOWNLOAD_DIR_LOCAL} && tar -xzf ${DOWNLOAD_DIR_LOCAL}/${FILENAME_JMETER}.tgz -C /usr/local && rm -rf /var/cache/apk/* && rm -rf ${DOWNLOAD_DIR_LOCAL}
---> Running in 908fac559368
fetch http://dl-cdn.alpinelinux.org/alpine/v3.10/main/x86_64/APKINDEX.tar.gz
fetch http://dl-cdn.alpinelinux.org/alpine/v3.10/community/x86_64/APKINDEX.tar.gz
v3.10.2-80-g68e4e4a13a [http://dl-cdn.alpinelinux.org/alpine/v3.10/main]
v3.10.2-83-g64319a6606 [http://dl-cdn.alpinelinux.org/alpine/v3.10/community]
OK: 10336 distinct packages available
(1/2) Upgrading libcrypto1.1 (1.1.1c-r0 -> 1.1.1d-r0)
(2/2) Upgrading libssl1.1 (1.1.1c-r0 -> 1.1.1d-r0)
OK: 6 MiB in 14 packages
(1/48) Installing ncurses-terminfo-base (6.1_p20190518-r0)
...省略
(48/48) Installing unzip (6.0-r4)
Executing busybox-1.30.1-r2.trigger
Executing ca-certificates-20190108-r0.trigger
Executing java-common-0.2-r0.trigger
OK: 95 MiB in 62 packages
---> 655fe0283c8d
Removing intermediate container 908fac559368
Step 8/9 : ENV PATH $PATH:${HOME_JMETER}/bin
---> Running in 9c731c259c57
---> e32e05b622a9
Removing intermediate container 9c731c259c57
Step 9/9 : WORKDIR ${HOME_JMETER}/bin
---> 45f070d75ce2
Removing intermediate container 958b82eaf6e0
Successfully built 45f070d75ce2
[root@liumiaocn jmeter]#
[root@liumiaocn jmeter]# docker images |grep jmeter |grep 5.1.1
jmeter 5.1.1 45f070d75ce2 16 seconds ago 190 MB
[root@liumiaocn jmeter]#
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
测试准备
压力测试应用准备
在本地机器的8088端口使用Docker启动一个Nginx应用(使用其他方式也可),示例如下所示:
liumiaocn:~ liumiao$ docker images |grep nginx |grep latest
nginx latest e445ab08b2be 2 months ago 126MB
liumiaocn:~ liumiao$ docker run -p 8088:80 -d --name=nginx-test nginx:latest
a80fb1a4fc20627891a6bd7394fd79ae9aefb7dc8cf72c12967bc2673a815308
liumiaocn:~ liumiao$
- 1
- 2
- 3
- 4
- 5
使用curl命令或者直接使用浏览器确认nginx已正常运行
liumiaocn:~ liumiao$ curl http://localhost:8088/
Welcome to nginx!
Welcome to nginx!
If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.
For online documentation and support please refer to
nginx.org.
Commercial support is available at
nginx.com.
Thank you for using nginx.
liumiaocn:~ liumiao$
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
准备jmx文件
jmx文件信息如下所示
liumiaocn:data liumiao$ ls
jmeter-nongui-test.jmx
liumiaocn:data liumiao$ cat jmeter-nongui-test.jmx
<jmeterTestPlan version="1.2" properties="5.0" jmeter="5.1.1 r1855137">
<hashTree>
<TestPlan guiclass="TestPlanGui" testclass="TestPlan" testname="测试计划" enabled="true">
<stringProp name="TestPlan.comments">stringProp>
<boolProp name="TestPlan.functional_mode">falseboolProp>
<boolProp name="TestPlan.tearDown_on_shutdown">trueboolProp>
<boolProp name="TestPlan.serialize_threadgroups">falseboolProp>
<elementProp name="TestPlan.user_defined_variables" elementType="Arguments" guiclass="ArgumentsPanel" testclass="Arguments" testname="用户定义的变量" enabled="true">
<collectionProp name="Arguments.arguments"/>
elementProp>
<stringProp name="TestPlan.user_define_classpath">stringProp>
TestPlan>
<hashTree>
<ThreadGroup guiclass="ThreadGroupGui" testclass="ThreadGroup" testname="线程组" enabled="true">
<stringProp name="ThreadGroup.on_sample_error">continuestringProp>
<elementProp name="ThreadGroup.main_controller" elementType="LoopController" guiclass="LoopControlPanel" testclass="LoopController" testname="循环控制器" enabled="true">
<boolProp name="LoopController.continue_forever">falseboolProp>
<stringProp name="LoopController.loops">10stringProp>
elementProp>
<stringProp name="ThreadGroup.num_threads">100stringProp>
<stringProp name="ThreadGroup.ramp_time">1stringProp>
<boolProp name="ThreadGroup.scheduler">falseboolProp>
<stringProp name="ThreadGroup.duration">stringProp>
<stringProp name="ThreadGroup.delay">stringProp>
ThreadGroup>
<hashTree>
<HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="HTTP请求" enabled="true">
<elementProp name="HTTPsampler.Arguments" elementType="Arguments" guiclass="HTTPArgumentsPanel" testclass="Arguments" testname="用户定义的变量" enabled="true">
<collectionProp name="Arguments.arguments"/>
elementProp>
<stringProp name="HTTPSampler.domain">192.168.31.242stringProp>
<stringProp name="HTTPSampler.port">8088stringProp>
<stringProp name="HTTPSampler.protocol">httpstringProp>
<stringProp name="HTTPSampler.contentEncoding">stringProp>
<stringProp name="HTTPSampler.path">/stringProp>
<stringProp name="HTTPSampler.method">GETstringProp>
<boolProp name="HTTPSampler.follow_redirects">trueboolProp>
<boolProp name="HTTPSampler.auto_redirects">falseboolProp>
<boolProp name="HTTPSampler.use_keepalive">trueboolProp>
<boolProp name="HTTPSampler.DO_MULTIPART_POST">falseboolProp>
<stringProp name="HTTPSampler.embedded_url_re">stringProp>
<stringProp name="HTTPSampler.connect_timeout">stringProp>
<stringProp name="HTTPSampler.response_timeout">stringProp>
HTTPSamplerProxy>
<hashTree/>
hashTree>
hashTree>
hashTree>
jmeterTestPlan>
liumiaocn:data liumiao$
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
注:关于此jmx的生成步骤和说明请参看
- https://liumiaocn.blog.csdn.net/article/details/101904948
注意事项:前面示例中关于本地Web应用的压测,hostname设定的为localhost,但是由于jmeter在容器中运行,此localhost不同于彼localhost,所以此处改为了IP(192.168.31.242),请实际验证时修改为自己的IP。
执行测试
启动容器&确认版本
liumiaocn:tmp liumiao$ docker run -it -v $(pwd)/data:/data jmeter:5.1.1 sh
/usr/local/apache-jmeter-5.1.1/bin # cd /data
/data # ls
jmeter-nongui-test.jmx
/data # which jmeter
/usr/local/apache-jmeter-5.1.1/bin/jmeter
/data # jmeter -v
_ ____ _ ____ _ _ _____ _ __ __ _____ _____ _____ ____
/ \ | _ \ / \ / ___| | | | ____| | | \/ | ____|_ _| ____| _ \
/ _ \ | |_) / _ \| | | |_| | _| _ | | |\/| | _| | | | _| | |_) |
/ ___ \| __/ ___ \ |___| _ | |___ | |_| | | | | |___ | | | |___| _ <
/_/ \_\_| /_/ \_\____|_| |_|_____| \___/|_| |_|_____| |_| |_____|_| \_\ 5.1.1 r1855137
Copyright (c) 1999-2019 The Apache Software Foundation
/data #
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
执行测试并生成结果
/data # jmeter -n -t jmeter-nongui-test.jmx -l result.jtl -e -o jmeter-nongui-rpt
Creating summariser
Created the tree successfully using jmeter-nongui-test.jmx
Starting the test @ Wed Oct 02 07:39:06 GMT 2019 (1570001946517)
Waiting for possible Shutdown/StopTestNow/HeapDump/ThreadDump message on port 4445
summary = 1000 in 00:00:02 = 538.5/s Avg: 55 Min: 2 Max: 393 Err: 0 (0.00%)
Tidying up ... @ Wed Oct 02 07:39:09 GMT 2019 (1570001949228)
... end of run
/data #
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9